标签:document Fix 有用 取消 this oat 循环结构 动态 验证
全栈课程-------全栈工程师
前端:信息展示,普通用户浏览---前端工程师(html+css:静态页面 js:页面的交互效果)
后台:信息管理,管理员,数据库------后端工程师(php+mysql)动态页面
产品上线,部署
特别注意:
1.每条js语句结束都需要写英文状态下的;
2.js所有的标点都是英文状态下的
3.单双引号的问题:进行字符串的定义或者输出,单双引号的内容可以原样输出,互相嵌套
网景公司:Navigator浏览器0.9版本【1994】
sun公司:javascript
js之父:Brendan Eich--10就发明了js
ESMAScript组织规范js的语法
理解(抄笔记、敲代码)+记忆
实现网页的交互作用
进行数据验证
操作cookie、session
小游戏:贪吃蛇、打字游戏、扫雷
与后台的node.js
......
ECMAScript------js的基础语法
BOM------Broswer Object Model 浏览器对象模型
DOm----Document object Model 文档对象模型
基于对象和事件驱动的松散型、解释性语言,寄宿于浏览器,单线程异步
JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言内置支持类型,他的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,用来给html网页增加动态功能。
语法错误:Uncaught SyntaxError
低级错误,执行前全部扫描一遍,如果有语法错误,所有js代码错误,所有js代码都不执行
逻辑错误:
在js代码执行时发生,不可避免,出错的代码不会执行,之前的代码会正常执行
注意:外部引入和嵌入式不能混合使用,一个srcipr中不能既有src又有js代码,但可以有多个srcipt标签共同作用
外部引入
<srcipt src="js/index.js"></srcipt>
嵌入式
<srcipt>直接写js代码</srcipt>
在a的href中
<a href="javasrcipt:alert(‘1‘)">我是a</a>
form表单
事件后面
<div class="box" onclik="alert(‘1‘)">
[]\]
</div>
?
alert()------窗口弹出框
console.log()--------在控制台输出
document.write()-------写入的页面(可以识别标签)
prompt()-----输出弹框
confirm()----确认取消框
可以变化的量。数据存储的容器
变量的声明
声明变量,用关键字var
没有用var声明的变量,叫全局变量
不要用var多次声明同一个变量
变量提升:一个变量先使用后赋值,默认为undefined(变量提升)
js执行时浏览器会进行预解析,var声明的变量以及function函数会进行变量提升
变量的赋值
可以在声明的同时赋值
var num = 1;
可以先声明,后赋值
var num1,
num1 = 1;
一次性声明多个变量(用,隔开),然后分别赋值
var num2,num3;num2 = "123"; num3 = "123";
一次性声明多个变量的同时赋值
var num4 = 1, num5 = 2;
可以多次赋值,后面的会覆盖前面的
一个变量没有声明就使用,会报错(该变量 is not defined)
未赋值的变量默认为undefined
3.变量命名时注意的:
名字都是以数字、下划线、字母与$组成,数字不能开头
常用的命名方式:要有意义,见名知意(英文翻译)、驼峰命名法、首字母大写
避免与关键字与保留字冲突
区分大小写:
初始数据类型和引用数据类型的区别:分别放在栈区和堆区,栈区和堆区的区别:栈区放置变量和函数名,执行完程序自动删除,堆区放置引用的数据,可以自己删除,也会被js的垃圾回收处理删除
数值型-----typeof:number
整数
小数
负数
科学计数法(3.2e5)
二进制0b开头、八进制0开头、十进制、十六进制0x开头
最大值(Number MAX_VALUE)
最小值(Number MIN_VALUE)
parseint 从首位开始转化为整型。,如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN 123a456 转换成123
? null\undefined/bolen--->NaN
NaN (not a number)-----不是一个数 Nan==NaN (false) Number.isNAN(NaN)
if(Number.isNAN(num) 如果number是NaN。返回true
字符串--------typeof:String
单双引号里面的内容,双引号里面嵌套单引号,单引号里面嵌套双引号
数值型字符串
var str2 = "12234";
非数值型字符串
var str = "abcdef";
var str1 = "cdes‘qwe‘qq";
布尔值--------typeof:Boolean
var b = false;
var c = true;
undefined--------typeof:undefined
未定义----只声明未赋值的变量默认是undefined,先使用后声明的变量为undefined
var cc;
console.log(cc)//undefined
console.log(dd)//undefined
var dd = 10;
null--------typeof:Object
清空对象
对象/object--------typeof:Object
? 函数、数组
算数加: 算数加/字符串拼接
!!任何数据类型与字符串相加,结果都是字符串
/ * -
算数的减乘除,得到的结果一定是number类型
如果不能运算(字符串/字符串),得到的结果为NaN
如果是数值型字符串,会默认转化为数值型
% 取余得到的结果
++/-- 自增
如果++/--在前,先自增再运算
如果++/--在后,先运算后自增
? <= < > >= == != === !==
数值型与数值型比较,直接比大小
数值型与非数值型字符串比较,不能比较大小,直接返回false
数值型与数值型字符串比较,先把数值型字符串转化为数值型,再依次比较大小
字符串与字符串比较,依次比较ASCll码的大小
== === != !==
== 判断数值是否相等
=== 判断数值与数据类型相等
PS:= 赋值运算
= += -= *= /= %=
&& 逻辑与
当所有表达式都为真时,结果为真;只要一个为假,结果为假
|| 逻辑或
只要一个为真,结果为真;所有表达式为假,结果为假
! 逻辑非
取反,原来表达式为真,结果为假;原来表达式为假,结果为真
特殊的几个假值:0 NaN false undefined "" null
======================================================================
赋值时,会发生短路运算:
&&会找第一个假值,如果没有会找第二真值;
||会找第一个真值,如果没有会找第二假值
let x,y,z
x=1+3<2|| true 输出为true || 小于 = 小于 < 小于 +
=======================================================================
表达式1 | 表达式2 | && | || | ! |
---|---|---|---|---|
true | true | true | true | false |
true | false | false | true | flase |
false | false | false | false | true |
false | true | false | true | true |
一元运算符:+(正数) -(负数) ++(自增) --(自减) new实例化对象 delete删除对象属性或变量
(表达式1)?(表达式2):(表达式3)
如果表达式1成立,执行表达式2,否则,执行表达式3
,声明多个变量的时候进行分隔
() ---- 提高运算的优先级/函数调用
\转义
=====================================================
运算的优先级:
赋值运算优先级最低,()优先级最高
赋值运算时,从左往右的顺序执行
其他运算,从左往右的顺序执行
====================================================
代码执行的顺序
按照顺序依次执行
单路分支
if(条件表达式){
//条件成立要执行的语句
}
双路分支
if(条件表达式){
条件成立要执行的代码
}else{
条件不成立要执行的代码
}
多路分支
if(条件表达式1){
执行语句1
}else if(条件表达式2){
执行语句2
}else if(条件表达式2){
执行语句2
}else{
以上条件不成立,输出的语句
}
?
嵌套分支
if(表达式1){
if(表达式){
执行语句1;
}else{
执行语句2;
}
}
switch分支
// switch(表达式){
// case "表达式可能的值":如果是该值要执行的语句;
// break(终止后面程序的执行)
// }
//案例1:测试星期几
var week = prompt("亲输入内容");
switch(week){
case "1":alert("星期一");
break;
case "2":alert("星期二");
break;
case "3":alert("星期三");
break;
case "4":alert("星期四");
break;
case "5":alert("星期五");
break;
case "6":alert("星期六");
break;
case "7":alert("星期日");
break;//终止,结束
//其余所有情况都不满足时要执行的代码
default:alert("输入错误")
}
if和switch的不同点:
if是连续性数据的区间
switch是离散型数据
if(括号里可以写)
条件表达式
number 除了0以外都是true 0是falsestring “”空字符串是false,其他都是true
undefined/null在转换下会变成NaN
bolean true/ false
for循环
for (var i = 0; i < 10; i++) {
//循环体
console.log(i)
}
//语法
for(表达式1;表达式2;表达式3){
循环体
}
表达式1:变量的初始值
表达式2:进行循环的条件 i<10
表达式3:步进值 i++/i--
// 执行过程:
表达式1--->表达式2(判断是否满足当前的条件)--->如果满足,执行循环体--->表达式3(让变量自增)如果 不满足,直接跳出循环体
while循环
当条件满足时,在进入循环体
适用于:只知道循环的条件,不知道要循环几次
var num = 6;
while(num<10){
console.log(1)
num++;
}
do while循环
先执行循环体,在判断条件是否满足
不管条件是否满足,总会先执行一次循环体
适用于:只知道循环的条件,不知道循环的次数
do while{
//循环体
}(条件)
应用场景:
? 解决大量相关数据的存储
? 便于程序的开发和使用
var arr = [];
var newarr = new Array(里面的是数组的长度);new一个实例化对象
//数组中可以存储任何数据类型的数据如下:
var arr = [1,"234",undefined,null,false,[]];
访问数组用下标,从0开始
可以越界访问,越界访问的值默认为undefined
自定义数组的长度,未赋值的位置为undefined
数组的长度,arr.length
与下标的关系:比下标多一
for of更加适合遍历数组,遍历的是数组的value,不能遍历对象
for in 更适合遍历对象 ,遍历的是数组的index
1.一维数组
let arr1=[1,2,3]
let arr2
arr2=arr 直接赋值这叫传址 ar r1再次发生变化 arr2 也变化
遍历赋值 叫做浅拷贝 arr1变化 不影响arr2
var arr5=["fas",23, 45,"asd"];
for(var i=0;i<arr.length;i++){
console.log(arr5[i]);
}
2.二维数组的遍历
浅拷贝是一个传址,也就是把a的值赋给b的时候同时也把a的址赋给了b,当b(a)的值改变的时候,a(b)的值同时也会改变
深拷贝:深拷贝是指,拷贝对象的具体内容,二内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象页互相不影响,互不干涉
外循环控制的是二维数组的长度,其实就是一维数组的个数行数。
内循环控制的是一维数组的长度,每一行,一维数组元素分别的个数。
// 求二维数组所有元素的和
var arr9 = [[1,1],[1,1],[1,1]];
function arr(arr1){
var plus=0;
for (var i = 0; i < arr1.length; i++) {
for (var j = 0; j < arr1[i].length; j++) {
plus +=arr9[i][j];
}
}
return plus;
}
console.log(arr(arr9))
?
for(let i in arr9){
console.log(i);
console.log(arr9[i])
}
?
//forEach
let res = arr9.forEach(function(val,index){
console.log(val,index)
})
?
?
let res = arr9.forEach(function(val,index)=>{
console.log(val,index)
})
封装具有特定功能的代码段,代码段可以重复使用
用function关键字定义--会优先解析,可以声明之前调用函数
形参:形式参数,在声明函数时括号里面的参数 作用 :接收实参
实参:实际参数,在调用函数时括号里面的参数 作用:传递参数
参数问题:1.参数可以是任何的数据类型
? 2、参数的个数(默认要一一对应)
? 如果形参>实参,剩余形参为undefined
? 如果实参>形参,剩余实参可以在arguments对象中寻找
function funName(形参1,形参2,
通过字面量的函数,匿名函数--只能先定义后调用,不能再定义之前调用,否则,会报错
var a=function(){
//函数体
return;;
}a()
匿名函数
(function(){
console.log(123)
})()
通过实例化Function得到一个函数
var fn = new Function("形参","函数体")
?
fn()
函数名();
写在事件中
自调用
(function aa(){
alert(num)
})(2);
可以让函数更加灵活
形参:定义函数时()中的的参数,相当于变量名
实参:调用时函数里面的参数,相当于变量值
函数的重载:通过参数的类型或值得不同,执行不同的函数体
关系
? 实参=形参:--对应
? 实参<形参:多余的形参默认是undefined
? 实参>形参:多余的实参用arguments处理
? 也可以...res接受
? arguments:每个函数都有的属性,用来接收所有的的实参,把实参放在类似于数组的对象中
? ...res:接受多余的实参,放在一个数组中
? function aa(num,num1,...num2){
console.log(num,num1,num2)//1 2 (9) [3, 5, 8, 9, 2, 45, 5, 5, 5]
? }
? aa(1,2,3,5,8,9,2,45,5,5,5)
参数的默认值
if else
function fn(num,flag){
if(flag==undefined){
flag="+";
}else{
flag=flag;
}
if(flag=="<"){
//从大到小排序
}else if(flag==">"){
//从小往大排序
}
}
三元表达式
flag = (flag==undefined)?("+"):(flag)
逻辑表达式
flag = flag||"+";
ES6中,直接写在形参的最后,如果该值为假,才会促发
function fu(num,flag="+“){
//函数体
}
作用:
终止函数的运行
给函数一个返回值
可以返回任何数据类型的数据,函数返回的结果是调用函数的结果
每个函数都只能有一个返回值,如果有多个,就是在分支结构中
原则上,每个函数都有一个返回值,如果没有,调用函数的结果undefined
全局作用域/全局变量:
在全局或任何地方都可以起作用的变量,任何地方都可以修改
通过var在外部定义的变量
没有用var声明但赋值的变量
局部作用域/局部变量:
定义在函数内部的变量
函数的形参
用let声明的块级作用域的变量
块级作用域:{}
作用域链:
我们可以把作用域看成是用链条连接起来的,这样能够使得函数能有序的进行运行
里层函数可以访问外层函数的变量,但是外层函数不可以访问里层函数的变量
自己调用函数
案例
1.深拷贝
2阶乘:1的阶乘为1 0的阶乘为1
//阶乘 5! = 5*4*3*2*1
// 5! = 5*4!
// 4*3!=24
// 3*2!=6
// 2*1!=2
// 1!=1
// 0!=1
//找规律n! = n*(n-1)!
//找界定条件 0!=1 1!=1
function jc(num){
if(num == 1||num == 0){
return 1;
}
return num*jc(num-1);
}
alert(jc(6))
斐波纳契数列 fb(num-1)+fb(num-2)的阶乘为1
F(n)=F(n-1)+F(n-2) F(5)=F(4)+F(3) 5 F(4)=F(3)+F(2) 3 F(3)=F(2)+F(1) 2 function fb(num){ if(num == 1||num==2){ return 1; } return fb(num-1)+fb(num-2); } alert(fb(10))
function main(num1,num2,collback){
console.log("我是主函数")
collback();
return num1+num2;
}
function fn(){
console.log("我是回调函数");
}
let arr = [1,2,3];
main(1,2,fn)
四则运算
function jia(a,b){
return a+b;
}
function jian(a,b){
return a-b;
}
function cheng(a,b){
return a*b;
}
function chu(a,b){
return a/b;
}
function fnn(a,b,fn){
return fn(a,b)
}
console.log(fnn(10,30,cheng))
高阶参数
//num的阶乘
?
function fn(num){
if(num==0){
return 1;
}
if(num==1){
return 1;
}
else{
return num*fn(num-1)
}
}
console.log(fn(5))
?
//数组 深拷贝
let arr=[[1,2],[5,8],[1,[8,77,[99,33]]]];
function aa(arr){
for(let i=0;i<arr.length;i++){
if(typeof arr[i]!="object"){
newarr[i]=arr[i]
}else{
newarr[i]=aa(arr[i])
}
}
return newarr
}
console.log(arr)
定义:当两个函数发生嵌套关系时,内层函数使用外层函数的变量,并在全局环境下调用内层函数 保护内部变量不别清理掉
1.形参=>返回值
let sum = num=>num;
console.log(sum(1))
2.(形参1,形参2)=>返回值
//(形参)=>返回值
let sum=(num,num1)=>num+num1;
console.log(sum(1,2))
3.(形参1,形参2)=>{? 函数体;? return;}
let fu = (num1,num)=>{
if(num1%2=0){
num1=1;
}
return;
}
‘
ECMAscript 自带的函数,ECMAscript将我们常用的一些功能封装起来,我们不需要知道他是怎么实现
的,只需要知道怎么调用即可。.js内部定义的,在任何地方可以调用的函数
escape() 将非字母、数字字符进行编码
unescape() 对编码的字符串进行解码
Number() 转换成数值类型
布尔值-->false--0 true---1 字符串:数值型的字符串---直接转换 非数值字符串---NaN
undefined-->NaNnull--->0
String() 转换成字符串类型
Boolean() 转换成布尔类型
null、undefined、0、""、NaN 、false为假,其他都为真
!!!!!!!parseInt() 将字符串转换为整型
parseFloat() 转换为浮点数数:去掉一些没有意义的0
tofixed(n)给数字后面加小数点后位数
let num=12 ; console.log(num.toFixed(2))---12.00
isNaN() 判断是不是NaN
如果是NaN,返回true,否则,返回false
强制数据类型转化:number、Boolean、string、parseint、parsefloat
隐式数据类型转化: if() 2+"5";运算符、while
除了强制类型转换(能看到的),其他都是隐式数据转换
引用函数的类型是function
ES6中新增的声明变量的关键字,用法同var
不同点
let不存在变量提升
let不能重复声明同一个变量,可以重复赋值
let可以识别块级作用域,成为局部变量,只在当前的块级作用域起作用
ES6新增的关键字,用来声明常量(不变的量)
只能在声明的同时赋值
一般常量的名字全部大写
常量不能重复赋值
可以识别块级作用域
只在当前的块级作用域起作用
不存在变量提升
使用new操作符调用构造函数时,会经历4个阶段
1.创建一个对象2.将这个对象的proto成员指向了构造函数对象的prototype成员对象,这是最关键的一步3.将构造函数的作用域赋给新对象,this就是新对象 4.返回新对象
var zhangsan = {};
zhangsan.__proto__=person.prototype;
person.call(zhangsan);
return zhangsan;
通过构造函数创建类-------工厂函数
function Computer(yanse,jiage){
this.color = yanse;
this.price = jiage;
this.study = function(){
console.log("跶游戏")
}
}//通过new一个类,实例化一个对象
let dell =new Computer("red","9999");
console.log(dell)
//dell.color = "yellow";
//dell.price = "10000";
通过class关键字创建类
class Person{
//构造函数
constructor(arms,eye){
this.arms = arms;
this.eye = eye;
this.study = function(){
console.log("街道口");
}
}
}
let zhangsan = new Person(2,2);
console.log(zhangsan);
json(javascript object notation)直接创建对象 轻量级的数据交换格式
{
name:"李四",
age:15,
key:value
}
let mi = {
name :"小米手机",
color:"red",
price:318,
watch:function(){
console.log("看电视");
return 0;
},
cpu:"123"
}
console.log(mi.cpu)
console.log(mi)
proto 每个对象都有的属性,用来继承,指向它的构造函数的原型
查看某个对象的构造函数,通过.constructor
console.log(mi.constructor)
判断某个对象是不是属于某个构造函数 instanceof如果是,返回true;否则,返回false
console.log(zhangsan instanceof Person)
每一个函数都有一个属性.prototype
console.log(zhangsan.constructor.prototype)
每个对象的proto指向构造函数的prototype
console.log(zhangsan.__proto__=zhangsan.constructor.prototype)//true
属性? length //对象方法
查询:
charAt //获取字符串某个位置的值(0~n)
charCodeAt()//获取字符串的ASCII
search //只能配合正则使用
match //某个字符在字符串的位置情况,返回值是一个数组,它可以配合正则使用
indexOf(string) //获取某个字符在字符串首次出现的位置,如果没有找到返回值为-1
lastIindexOf(string) //获取某个字符在字符串最后出现的位置,如果没有找到返回值为-1
replace("string","string") //替换字符串中的某个字符,第一个参数为要替换的参数,第二参数为替换后的参数,可以配合正则使用
截取:
slice(int,int) //截取字符串中的一段,两个参数都是代表位置,从第一个参数的的位置截取到第二个参数的位置,包含第一个不包含第二个,如果只有开始的位置将一直截取结束;如果是负数,将倒数
substr //截取字符串中的一段,第一个参数为开始截取的位置,第二个参数为截取长度
substring(int,int) //和slice类似,但它不接收负数
其他:
toLowerCase //把里面的大写字母转化为小写字母
toUpperCase //把里面的小写字母转化为大写字母
split(string) //把字符串以某种分割符分割为数组,可以配合正则使用
trim //去掉字符串中的前后空格
concat //拼接
? concat()---数组的拼接,返回新数组,原数组不会改变,参数:可以传一个或者多个元素,也可以是其他数组字符串对象
增删
unshift// 给数组的最前面添加一个或多个元素,返回新数组,原数组发生变化.参数:要添加的元素
shift----删除数组中的第一个元素,返回删除的元素,原数组发生变化,参数:无
push-----给数组添加一个或多个元素,返回新数组的长度,原数组发生变化,参数:要添加的元素
pop------删除数组中的最后一个元素,返回被删除的元素。原数组发生变化,是删除之后的数组,参数:无
slice-----截取数组的一部分,返回被截取的部分,原数组不变,参数:参数1.截取的开始位置,参数2.截取结束的位置,不包括
??splice------万能增删 ,返回被删除的元素,原数组发生变化,参数:参数1:删除的起始位置? 参数2:删除的个数 ,如果不写,删除的结尾? 参数3[,参数4]:要添加的元素
查找
indexOf------找某元素第一次出现的下标,返回该元素第一次出现的下标,原数组不变,参数:某个元素
lastIndexOf-------找某元素最后一次出现的下标,返回该元素最后一次出现的下标,原数组不变,参数:某个元素
find--------寻找符合条件的数组元素,返回满足条件的第一个元素的值,原数组不变,参数:回调函数
findIndex------寻找符合条件的数组元素下标
some----判断数组中是否存在符合某个条件的元素,返回true/false,原数组不变,参数:回调函数
every-----判断数组中是否所有的元素都符合条件,返回true,false,原数组不变,参数:回调函数
filter------检测数组中是否有满足条件的元素,返回满足条件的新数组,原数组不变,参数:回调函数
includes---判断数组中是否包含某个元素,参数某个值
map-----数组映射,返回变化后的新数组,原数组不变,参数:回调函数
转化
toString-------把数组转化为字符串
join-----------将数组转化为字符串,返回拼接后的字符串,原数组不变,参数: 默认逗号拼接,可以自己传入拼接符号
其他
forEach--------数组遍历,得到数组中的每一个元素的值和下标/索引值,参数:回调函数
reduce------求和,原数组不发生变化,返回值,参数:回调函数
sort-------数组排序,返回排序后的新数组:参数1-参数2 从小往大,原数组发生变化, 参数:回调函数
reverse------数组翻转,返回新数组,原数组发生变化,参数:无
cancat-----数组的拼接,返回新数组,原数组不会改变,参数:可以传一个或者多个元素,也可以是其他数组
? 1,类是一个抽象的概念,它不存在于现实中的时间/空间里,类只是为所有的对象定义了抽象的属性与行为。就好像“Person(人)”这个类,它虽然可以包含很多个体,但它本身不存在于现实世界上。
? 2,对象是类的一个具体。它是一个实实在在存在的东西。
? 3,类是一个静态的概念,类本身不携带任何数据。当没有为类创建任何对象时,类本身不存在于内存空间中。
? 4,对象是一个动态的概念。每一个对象都存在着有别于其它对象的属于自己的独特的属性和行为。对象的属性可以随着它自己的行为而发生改变。
? 5.类是封装好的,像一个模型;对象是有类实例化的,也就像一个具体的样本!通俗来说吧,比如说“人”就是一个类,而你就是一个实例即对象!
构造函数中的this:是指向实例化出来的对象
dir详细情况 console.dir()对象的遍历 是for in
实例化对象就是由抽象到具体的过程,这个过程就叫实例化。
通常把用类创建对象的过程称为实例化。
方法中的this指针指向调用对象
箭头函数this从上下文中寻找
所有的普通函数中的this指的都是window
let arr=[1,2,3,4,5]
splice(下标,删除的长度【,插入的值】) 万能的增删
? console.log(arr.splice(0,1,"aa"),arr)
join 将数组转化为字符串,默认连接符“,”
? console.log(arr.join"-")
slice 截取数组的一部分,start-end(不包括end)
sort 排序
? arr.sort((a,b)=>b-a ) console.log(arr.sort((a,b)=>b-a ) ) a-b是正序 b-a是倒序
find找到第一个满足条件的元素,返回元素
findIndex 找到第一个满足条件的元素,返回元素下标
fillter 筛选符合条件的元素组成新的数组
some 判读数组中是否有一个或者多个元素满足条件 返回布尔值
every 检测数组中是否每一个元素都满足条件 返回布尔值
includes 判断数组中是否有某个元素 返回布尔值
forEach 遍历 不改变原数组 arr.forEach(v,i)
map 映射数组 /遍历数组 不改变原数组 ,返回新数组
标签:document Fix 有用 取消 this oat 循环结构 动态 验证
原文地址:https://www.cnblogs.com/aloneindefeat/p/10483965.html