目录

  • 一、数组对象Array
    • sort()
    • forEach()
    • concat连接数组
    • map()
    • Date日期对象
    • Math对象
    • Json对象
    • RegExp对象
    • javascript允许之定义对象
  • 二、运算符
    • 算数运算符
    • 比较运算符
    • 逻辑运算符
    • 赋值运算符
  • 三、流程控制
    • if->else
    • if->else if->else
    • switch
    • for
    • while
    • 三元运算
  • 四、函数
    • 函数的定义与调用(与pytho类同)
    • 函数中的arguments参数
    • 函数的全局变量和局部变量
    • 作用域

一、数组对象Array

数组对象的作用是:使用单独的变量名来存储一系列的值。类似于Python中的列表

var x = ["egon", "hello"];
console.log(x[1]);  // 输出"hello"

常用方法:

方法 说明
.length 数组的大小
.push(ele) 尾部追加元素
.pop() 获取尾部的元素
.unshift(ele) 头部插入元素
.shift() 头部移除元素
.slice(start, end) 切片
.reverse() 反转
.join(seq) 将数组元素连接成字符串
.concat(val, …) 连接数组
.sort() 排序
.forEach() 将数组的每个元素传递给回调函数
.splice() 删除元素,并向数组添加新元素。
.map() 返回一个数组元素调用函数处理后的值的新数组

sort()

关于sort()需要注意:

如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。

var arr = [123,9,1211,11]
arr.sort()
#[11, 1211, 123, 9]

如果想按照其他标准进行排序,就需要提供比较函数,该函数应该具有两个参数 a 和 b,接收传入的a和b,执行函数体代码,然后返回一个值用于说明a和b的大小

返回值 < 0 :代表a小于b

返回值 =0 : 代表a等于b

返回值 > 0 :代表a大于b

注意:

var x = "5";
var y = "3";
res = x - y; //res = 2
typeof res  //"number"

示例:

function sortNumber(a,b){return a - b
}
var arr = [123,9,1211,11]
arr.sort(sortNumber) #[9, 11, 123, 1211]

关于遍历数组中的元素,可以使用下面的方式:

var arr = [11, 22, 33, 44];
for (var i=0;i<arr.length;i++) {console.log(i);
}

forEach()

语法:

forEach(function(currentValue, index, arr), thisValue)

参数:

参数 描述
function(currentValue, index, arr) 必需。 数组中每个元素需要调用的函数。 函数参数:参数描述currentValue必需。当前元素index可选。当前元素的索引值。arr可选。当前元素所属的数组对象。
thisValue 可选。传递给函数的值一般用 “this” 值。 如果这个参数为空, “undefined” 会传递给 “this” 值

示例:

#例一
var arr=['aa','bb','cc','dd','ee']arr.forEach(function(v,i,arr){console.log(v,i,arr);console.log(this[0]);
},"hello")#例二:

concat连接数组

var arr=['aa','bb','cc','dd','ee']
arr1=[34,35,54]
(3) [34, 35, 54]
arr+arr1
"aa,bb,cc,dd,ee34,35,54"
arr.concat(arr1)
(8) ["aa", "bb", "cc", "dd", "ee", 34, 35, 54]

'+'拼接成字符串,concat可以连接成数组

splice()

语法:

splice(index,howmany,item1,…,itemX)

参数:

index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 可选。表示要删除的项目数量(index对应的值也算一个)。如果不指定默认值为0,代表不会删除项目。
item1, …, itemX 可选。向数组添加的新项目。

示例:

#例一:
var arr=['aa','bb','cc','dd','ee']arr.splice(1,3,'xxxx') # 删除‘bb’,‘cc’,’dd‘这三个值,然后插入’xxxx‘arr #["aa", "xxxx", "ee"]#例二:
arr=[1,2,3,4]
(4) [1, 2, 3, 4]
arr.splice(1,2,'xxx','yyy','zzz')
(2) [2, 3]
arr
(5) [1, "xxx", "yyy", "zzz", 4]#例三:删除个数设为0时,相当于不删除,可用于在特定的位置添加值
arr=[1,2,3,4]
(4) [1, 2, 3, 4]
arr.splice(1,0,'xxx')
[]
arr
(5) [1, "xxx", 2, 3, 4]

map()

语法:

map(function(currentValue,index,arr), thisValue)

参数:

参数 描述
function(currentValue, index,arr) 必须。函数,数组中的每个元素都会执行这个函数 函数参数: 参数描述currentValue必须。当前元素的值index可选。当期元素的索引值arr可选。当期元素属于的数组对象
thisValue 可选。对象作为该执行回调时使用,传递给函数,用作 “this” 的值。 如果省略了 thisValue ,“this” 的值为 “undefined”

示例:

forEach vs map:
1、forEach()返回值是undefined,不可以链式调用。
var res=arr.forEach(function(v,i,arr){console.log(v,i,arr);console.log(this[0]);return 123;
},"hello")
res # undefined2、map()返回一个新数组,原数组不会改变
var res=arr.map(function(v,i,arr){v=v + 'SB'return v;
},"hello")res #["aaSB", "bbSB", "ccSB", "ddSB", "eeSB"]例:
var arr=['egon','lili','json']
undefined
var res=arr.forEach(function(item){return item+'_sb'})
undefined
res
undefinedvar res=arr.map(function(item){return item+'_sb'})
undefined
res
(3) ["egon_sb", "lili_sb", "json_sb"]
arr
(3) ["egon", "lili", "json"]在使用forEach()时候,如果数组在迭代的视乎被修改,则其他元素会被跳过
var arr=[11,22,33,44,55]
arr.forEach(function(v){console.log(v);if (v === 33){arr.shift() // 下一次循环应该循环出第索引为3的元素,但此时一旦删除第一个元素,那么值55的索引变成了3}
})
11
22
33
55反转字符串
var str = '12345';
Array.prototype.map.call(str, function(x) {   //同时利用了call()方法return x;
}).reverse().join('');

Date日期对象

创建日期对象只有构造函数一种方式,使用new关键字

//方法1:不指定参数
var d1 = new Date();
console.log(d1.toLocaleString());//方法2:参数为日期字符串
var d2 = new Date("2018/01/27 11:12:13");
console.log(d2.toLocaleString());var d3 = new Date("01/27/18 11:12:13"); // 月/日/年 时分秒
console.log(d3.toLocaleString());//方法3:参数为毫秒数
var d4 = new Date(7000);
console.log(d4.toLocaleString());
console.log(d4.toUTCString());//方法4:参数为:年,月,日,时,分,秒,毫秒
var d5 = new Date(2018,1,27,11,12,13,700);
console.log(d5.toLocaleString());  //毫秒并不直接显示

常用的方法,更详细点我

方法 含义
getDate() 根据本地时间返回指定日期对象的月份中的第几天(1-31)。
getMonth() 根据本地时间返回指定日期对象的月份(0-11)
getFullYear() 根据本地时间返回指定日期对象的年份(四位数年份时返回四位数字)
getDay() 根据本地时间返回指定日期对象的星期中的第几天(0-6)
getHours() 根据本地时间返回指定日期对象的小时(0-23)
getMinutes() 根据本地时间返回指定日期对象的分钟(0-59)
getSeconds() 根据本地时间返回指定日期对象的秒数(0-59)
getMilliseconds() 根据本地时间返回指定日期对象的获取毫秒
getTime() 返回累计毫秒数(从1970/1/1午夜)

Math对象

方法 含义
Math.floor() 向下取整,如5.1取整为5
Math.ceil() 向上取整,如5.1取整为6
Math.max(a,b) 求a和b中的最大值
Math.min(a,b) 求a和b中的最小值
Math.random() 随机数,默认0-1之间的随机数,若想求min~max之间的数,公式为:min+Math.random()*(max-min)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bJOIJ7D9-1600774104447)(C:\Users\高雨\AppData\Roaming\Typora\typora-user-images\image-20200922165728736.png)]

Json对象

# JSON格式的字符串转成对象
var str1='{"name":"egon","age":18}';var obj1=JSON.parse(str1);
console.log(obj1.name);
console.log(obj1["name"]);# 对象转成JSON字符串
var obj2={"name":"egon","age":18};var str2=JSON.stringify(obj2);

RegExp对象

#1. 创建正则对象的方式1
// 参数1 正则表达式
// 参数2 匹配模式:常用g(全局匹配;找到所有匹配,而不是在第一个匹配后停止)和i(忽略大小写)
// 注意:正则放到引号内,{}内的逗号后面不要加空格
var reg1 = new RegExp("^[a-zA-Z][a-zA-Z0-9_]{5,11}$"); // 匹配用户名只能是英文字母、数字和_,并且首字母必须是英文字母。长度最短不能少于6位 最长不能超过12位。
reg1.test("egon_123") // true#2. 创建正则对象的方式2
var reg2 = /^[a-zA-Z][a-zA-Z0-9_]{5,11}$/; // 不要加引号
reg2.test("egon_123") // true#3. String对象与正则结合的4个方法
var s1="hello world";
s1.match(/l/g) // 符合正则的内容["l", "l", "l"]
s1.search(/h/g) // 符合正则的内容的索引0
s1.split(/ /) // ["hello", "world"]
s1.replace(/l/g,'L') // "heLLo worLd"#4. 匹配模式g与i
var s2="name:Egon age:18"
s2.replace(/e/,"赢") // "nam赢:Egon age:18"
s2.replace(/e/g,"赢") // "nam赢:Egon ag赢:18"
s2.replace(/e/gi,"赢") //"nam赢:赢gon ag赢:18"#5. 注意1:
// 1、如果regExpObject带有全局标志g,test()函数不是从字符串的开头开始查找,而是从属性regExpObject.lastIndex所指定的索引处开始查找。
// 2、该属性值默认为0,所以第一次仍然是从字符串的开头查找。
// 3、当找到一个匹配时,test()函数会将regExpObject.lastIndex的值改为字符串中本次匹配内容的最后一个字符的下一个索引位置。
// 4、当再次执行test()函数时,将会从该索引位置处开始查找,从而找到下一个匹配。
// 5、因此,当我们使用test()函数执行了一次匹配之后,如果想要重新使用test()函数从头开始查找,则需要手动将regExpObject.lastIndex的值重置为 0。
// 6、如果test()函数再也找不到可以匹配的文本时,该函数会自动把regExpObject.lastIndex属性重置为 0。
var reg3 = /egon/g;
reg3.lastIndex
0
reg3.test("egon") // true,匹配成功
true
reg3.lastIndex // 匹配成功reg3.lasIndex=4
4reg3.test("egon") // 从4的位置开始匹配,本次匹配失败
falsereg3.lastIndex // 匹配失败,lastIndex归为0
0reg3.test("egon") // 再次匹配成功
true#6. 注意2:
当我们不加参数调用RegExpObj.test()方法时, 相当于执行RegExpObj.test("undefined"), 并且/undefined/.test()默认返回true。
var reg4 = /^undefined$/;
reg4.test(); // 返回true
reg4.test(undefined); // 返回true
reg4.test("undefined"); // 返回true

在线网络链接

https://www.processon.com/view/link/5b3d87d8e4b00c2f18be35e4

在线图片链接

http://on-img.com/chart_image/5add499be4b0518eacc94649.png

图片下载:

https://pan.baidu.com/s/1qzdAunyFXUZiAUxaro5sGg

javascript允许之定义对象

详解

#一、创建对象的几种常用方式
1.使用Object或对象字面量创建对象2.工厂模式创建对象3.构造函数模式创建对象4.原型模式创建对象#1.1、 使用Object或对象字面量创建对象
JS中最基本创建对象的方式:var student = new Object();
student.name = "easy";
student.age = "20";
这样,一个student对象就创建完毕,拥有2个属性name以及age,分别赋值为"easy"和20。如果你嫌这种方法有一种封装性不良的感觉。来一个对象字面量方式创建对象
var sutdent = {name : "easy",age : 20
};
这样看起来似乎就完美了。但是马上我们就会发现一个十分尖锐的问题:当我们要创建同类的student1,student2,…,studentn时,我们不得不将以上的代码重复n次....var sutdent1 = {name : "easy1",age : 20
};var sutdent2 = {name : "easy2",age : 20
};...var sutdentn = {name : "easyn",age : 20
};
能不能像工厂车间那样,有一个车床就不断生产出对象呢?我们看”工厂模式”。#1.2、工厂模式创建对象
JS中没有类的概念,那么我们不妨就使用一种函数将以上对象创建过程封装起来以便于重复调用,同时可以给出特定接口来初始化对象function createStudent(name, age) {var obj = new Object();obj.name = name;obj.age = age;return obj;
}var student1 = createStudent("easy1", 20);
var student2 = createStudent("easy2", 20);
...
var studentn = createStudent("easyn", 20);
这样一来我们就可以通过createStudent函数源源不断地”生产”对象了。看起来已经高枕无忧了,但贪婪的人类总有不满足于现状的天性:我们不仅希望”产品”的生产可以像工厂车间一般源源不断,我们还想知道生产的产品究竟是哪一种类型的。比如说,我们同时又定义了”生产”水果对象的createFruit()函数:function createFruit(name, color) {var obj = new Object();obj.name = name;obj.color = color;return obj;
}var v1 = createStudent("easy1", 20);
var v2 = createFruit("apple", "green");
对于以上代码创建的对象v1、v2,我们用instanceof操作符去检测,他们统统都是Object类型。我们的当然不满足于此,我们希望v1是Student类型的,而v2是Fruit类型的。为了实现这个目标,我们可以用自定义构造函数的方法来创建对象#1.3、构造函数模式创建对象
在上面创建Object这样的原生对象的时候,我们就使用过其构造函数:
var obj = new Object();在创建原生数组Array类型对象时也使用过其构造函数:
var arr = new Array(10);  //构造一个初始长度为10的数组对象在进行自定义构造函数创建对象之前,我们首先了解一下构造函数和普通函数有什么区别。
1、实际上并不存在创建构造函数的特殊语法,其与普通函数唯一的区别在于调用方法。对于任意函数,使用new操作符调用,那么它就是构造函数;不使用new操作符调用,那么它就是普通函数。2、按照惯例,我们约定构造函数名以大写字母开头,普通函数以小写字母开头,这样有利于显性区分二者。例如上面的new Array(),new Object()。3、使用new操作符调用构造函数时,会经历(1)创建一个新对象;(2)将构造函数作用域赋给新对象(使this指向该新对象);(3)执行构造函数代码;(4)返回新对象;4个阶段。了解了构造函数和普通函数的区别之后,我们使用构造函数将工厂模式的函数重写,并添加一个方法属性:function Student(name, age) {this.name = name;this.age = age;this.alertName = function(){alert(this.name)};
}function Fruit(name, color) {this.name = name;this.color = color;this.alertName = function(){alert(this.name)};
}
这样我们再分别创建Student和Fruit的对象:
var v1 = new Student("easy", 20);
var v2 = new Fruit("apple", "green");
这时我们再来用instanceof操作符来检测以上对象类型就可以区分出Student以及Fruit了:
alert(v1 instanceof Student);  //true
alert(v2 instanceof Student);  //false
alert(v1 instanceof Fruit);  //false
alert(v2 instanceof Fruit);  //truealert(v1 instanceof Object);  //true 任何对象均继承自Object
alert(v2 instanceof Object);  //true 任何对象均继承自Object
这样我们就解决了工厂模式无法区分对象类型的尴尬。那么使用构造方法来创建对象是否已经完美了呢?使用构造器函数通常在js中我们来创建对象。我们会发现Student和Fruit对象中共有同样的方法,当我们进行调用的时候这无疑是内存的消耗。我们完全可以在执行该函数的时候再这样做,办法是将对象方法移到构造函数外部:function Student(name, age) {this.name = name;this.age = age;this.alertName = alertName;
}function alertName() {alert(this.name);
}var stu1 = new Student("easy1", 20);
var stu2 = new Student("easy2", 20);
在调用stu1.alert()时,this对象才被绑定到stu1上。我们通过将alertName()函数定义为全局函数,这样对象中的alertName属性则被设置为指向该全局函数的指针。由此stu1和stu2共享了该全局函数,解决了内存浪费的问题。但是,通过全局函数的方式解决对象内部共享的问题,终究不像一个好的解决方法。如果这样定义的全局函数多了,我们想要将自定义对象封装的初衷便几乎无法实现了。更好的方案是通过原型对象模式来解决。#1.4、原型的模式创建对象
原型链甚至原型继承,是整个JS中最难的一部分也是最不好理解的一部分,在这里由于我们课程定位的原因,如果对js有兴趣的同学,可以去查阅一下相关JS原型的一些知识点。更加有助于你以后前端JS的面试。function Student() {this.name = 'easy';this.age = 20;
}Student.prototype.alertName = function(){alert(this.name);};var stu1 = new Student();
var stu2 = new Student();stu1.alertName();  //easy
stu2.alertName();  //easyalert(stu1.alertName == stu2.alertName);  //true 二者共享同一函数详解

二、运算符

算数运算符

+
-
*
/
%
++
--

比较运算符

> >=
< <=
!=
==
===
!==

注意

1 == “1”  // true
1 === "1"  // false

逻辑运算符

&&
||
!

赋值运算符

=
+=
-=
*=
/=

三、流程控制

if->else

var age = 30;
undefined
if(age > 18){console.log('too old');
}else {console.log('too young');
}

if->else if->else

var age=18;
if(age > 18){console.log('too old');
}
else if(age == 18){console.log('花姑娘,吆西');
}
else {console.log('too young');
}

switch

switch中的case子句通常都会加break语句,否则程序会继续执行后续case中的语句。

var day = new Date().getDay();
switch (day) {case 0:console.log("星期天,出去浪");break;case 6:console.log("星期六,也出去浪");break;default:console.log("工作日,正常上班")
}

for

for (let i=1;i<=3;i++){console.log(i);
}

while

let i=0;
undefined
while (i<=3){console.log(i);i++;
}

三元运算

var x=1;
var y=2;
var z=x>y?x:y

四、函数

函数的定义与调用(与pytho类同)

// 无参函数
function f1() {console.log("Hello world!");
};
f1();// 有参数函数
function f2(a, b) {console.log(arguments);  // 内置的arguments对象console.log(arguments.length);console.log(arguments[0],arguments[1]);console.log(a, b);
};
f2(10,20);// 带返回值的函数
function sum(a, b){return a + b;
}
sum(1, 2);  // 调用函数// 匿名函数
var sum = function(a, b){return a + b;
}
sum(1, 2);// 立即执行函数
(function(a, b){return a + b;
})(1, 2);

函数中的arguments参数

function add(a,b){console.log(a+b);console.log(arguments.length)
}add(1,2)

输出:

3
2

注意:

函数只能返回一个值,如果要返回多个值,只能将其放在数组或对象中返回。

函数的全局变量和局部变量

#局部变量:在JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它(该变量的作用域是函数内部)。只要函数运行完毕,局部变量就会被删除。#全局变量:
在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。#变量生存周期:
JavaScript变量的生命期从它们被声明的时间开始。
局部变量会在函数运行以后被删除。
全局变量会在页面关闭后被删除。
function text(){var a=22b=333console.log(a)}
undefined
a
VM7372:1 Uncaught ReferenceError: a is not definedat <anonymous>:1:1
(anonymous) @ VM7372:1
b
VM7381:1 Uncaught ReferenceError: b is not definedat <anonymous>:1:1
(anonymous) @ VM7381:1
text()
VM7350:4 22
undefined
a
VM7409:1 Uncaught ReferenceError: a is not definedat <anonymous>:1:1
(anonymous) @ VM7409:1
b
333

作用域

首先在函数内部查找变量,找不到则到外层函数查找,逐步找到最外层。另外函数的作用域关系是在定义阶段就固定死的,与调用位置无关

例一

var city = "BeiJing";
function f() {var city = "ShangHai";function inner(){var city = "ShenZhen";console.log(city);}inner();
}f();  //输出结果是?

例二

var city = "BeiJing";
function Bar() {console.log(city);
}
function f() {var city = "ShangHai";return Bar;
}
var ret = f();
ret();  // 打印结果是?

例三

var city = "BeiJing";
function f(){var city = "ShangHai";function inner(){console.log(city);}return inner;
}
var res = f();
res();

day56 JavaScript相关推荐

  1. 【AJAX】JavaScript的面向对象

    Ajax中后端数据返回后需要前端通过JavaScript来实现动态数据更新的问题.所以,在Ajax中加深了一遍JavaScript面向对象的印象. 基础部分: JavaScript中创建对象并简单对象 ...

  2. 【JavaScript总结】JavaScript语法基础:JS高级语法

    作用域链: 1.JS中只有函数能够限定作用域的范围: 2.变量处理在制定的函数范围内,还有一个特殊的作用域,就是没有用var 声明的全局作用域 3.js中的作用域链是为了清晰的表示出所有变量的作用范围 ...

  3. 【JavaScript总结】JavaScript语法基础:DOM

    ->DOM的理解:文档对应dom树 ->有了DOM能做什么:DOM的操作 html文档做为DOM树模型,DOM树的节点就是对象.对象会触发事件来执行一些事件代码. C#中的事件是一个委托变 ...

  4. 【JavaScript总结】JavaScript语法基础:JS编码

    运算符 数学:+. -. *. / 逻辑:>. < .>= .<=. == . !=.&&.|| . === .!==(完全等于) 对象相关 new delet ...

  5. 【JavaScript总结】JavaScript语法基础:数据类型

    ------>数据类型有哪些? ->基本类型:数字类型,布尔类型,字符串类型 ->引用类型:对象类型,函数类型 ->空类型:null 和 undefined ->运算符: ...

  6. 【JavaScript总结】JavaScript发展与学习内容

    发展: 最初浏览器是为大学里浏览文档用,从地址栏输入文档地址,找到文档显示. 后来各种需求(购物网站,个人博客)出现,已有功能不能满足需求. 可人们依旧在努力满足这种需求,但实现后的效果很不尽人意. ...

  7. Python:模拟登录、点击和执行 JavaScript 语句案例

    案例一:网站模拟登录 # douban.pyfrom selenium import webdriver from selenium.webdriver.common.keys import Keys ...

  8. [JavaScript] JavaScript数组挖掘,不只是讲数组哟(2)

    课程来源:后盾人 上一篇的内容:[JavaScript] JavaScript数组挖掘,不只是讲数组哟 数组引用类型分析,多维数组,用Array.of为数组创建细节,类型检测与转换,在一个数组后面加一 ...

  9. [JavaScript] JavaScript 数组挖掘,不只是讲数组哟

    课程来源:后盾人 数组引用类型分析 数组的定义 const array = new Array('hello', 'dust', 1, 2, 3, 4, 5) console.log(array) l ...

最新文章

  1. Linux shell 学习笔记(5)— 文件权限(添加、修改、删除用户及创建、修改群组)
  2. python自学平台-怎么自学python,大概要多久?
  3. Ubuntu下apt-get命令详解
  4. 缓存和字符串相互转换
  5. Android无需权限显示悬浮窗, 兼谈逆向分析app
  6. win10 docker desktop无法拉取镜像解决办法
  7. java如何开发bpm系统_java工作流bpm开发ERP实例
  8. python主线程执行_Python队列 – 最多运行n个线程
  9. pycharm的updating indices
  10. stringutils_番石榴分配器vs StringUtils
  11. 我的处女作《设计模式之禅》——前言
  12. Touch 方法属性 映射工具
  13. 多文件管理器 tablacus explorer 下载与安装
  14. 怎么查看XP电脑服务器型号,xp怎么查看电脑配置
  15. fragment中文网_Android使用Fragment打造万能页面切换框架
  16. 西农 生成树配置_华为交换机配置STP功能示例
  17. .Net 面试题 汇总(二)
  18. Git:解决Git向码云中push文件报错:! [rejected] master -> master (fetch first)
  19. 利用Python把遥感影像的某几个波段合成
  20. 拓端tecdat|基于模型的聚类和R语言中的高斯混合模型

热门文章

  1. docker compose容器域名配置
  2. 外贸老鸟帮新人点评、修改的5个开发信案例
  3. 一日一Shader·进阶版笔刷【SS_18】
  4. 【临侦探侦工作原理】
  5. 计算机图形学基础:2D/3D坐标变换(Transformation)
  6. Python逐行读取tsv文件
  7. Spring Boot搭建Web服务器,实现用户注册登录功能
  8. 哈工大2021春软件构造实验总结
  9. html pdf支持css%写法吗,flying-saucer-pdf终于完美解决了(中文问题,换行问题,分页,页眉页脚,水印),html+css控制pdf样式...
  10. md魂斗罗机器人c弹锁定_史上最细节机器人勾C/防勾指南