Es6--ECMAScript 新增语法

一、对象字面量扩展

1、属性的定义

ES6之前

|---------------------|------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | var name = 'zs'; var age = 18; var user = {"name":name,"age":age} ; console.log(user); |

ES6之后

|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 | var name = 'zs'; var age = 18; // 生成的user对象中,属性名就是变量名,属性值为对应变量的值。 // 当然,必须先定义相关的变量 var user = {name,age} ; console.log(user); |

2、方法的定义

|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var user = { // ES6之前 eat:function() { console.log('吃'); }, // ES6后,省略冒号和functon关键字 sleep() { console.log("睡觉"); } } user.eat() ; user.sleep() ; |

3、属性表达式

ES6之前

访问属性和方法有两种方式,分别为:

  • 点操作符
    • 对象.属性
    • 对象.方法()
  • \]操作符 * 对象\[属性名

    • 对象[方法名]()
    • 注意,中括号中的名称支持使用表达式运算

|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var user = { user_name: 'zs', user_age: 18, user_login: function () { console.log('登录'); } } // 在中括号中,编写表达式,连接字符串,访问相关的属性和方法 // 点操作符 console.log(user.user_name); // 中括号操作,支持表达式运算 console.log(user['user_' + 'age']); user['user_' + 'login'](); |

ES6之后

对象的属性定义,支持使用表达式进行运算。

|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 定义前缀字符串 var prefix = 'user_' ; var user = { // 定义属性时,支持使用表达式运算 [prefix+'name']: 'zs', [prefix+'age']: 18, [prefix+'login']: function () { console.log('登录'); } } // 在中括号中,编写表达式,连接字符串,访问相关的属性和方法 console.log(user.user_name); console.log(user['user_' + 'age']); user['user_' + 'login'](); |

4、属性访问器

简化了Object.defineProperty()的存取数据描述的定义。

|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var user = { // 访问时,直接访问age即可,而_age是一种编程规范,并没有实现对外隐藏,外部依然可以直接访问 _age:0, get id() { return this._age ; }, set id(value) { this._age = value ; } } user.age = 18 ; console.log(user.age); |

5、直接指定原型

|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 | var person = { name:'匿名' } var user = { // 直接通过 __proto__ 属性指定原型对象 __proto__:person } console.log(user); console.log(user.name); |

__proto__属性已在ES6中标准化。在文本标记法中,__proto__只是语法糖,可以方便的指定原型对象。本质上还是使用构造方法的prototype属性来指定原型对象的,即Object.prototype

另外,以下方法,也可以指定原型对象

|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | var user1 = {} Object.setPrototypeOf(user1,person); console.log(user1); var user2 = Object.create(person) ; console.log(user2); |

6、super关键字

|---------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | var animal = { name:'动物' , show() { // 输出当前对象,查看this的指向 console.log(this); console.log('我是一只 ' + this.name); } } var cat = { // 直接通过 __proto__ 属性指定原型对象 __proto__:animal , // 覆盖属性 name:'猫', show() { // 调用原型中的方法,有以下三种方式 // 方式一:在原型的show()方法中,this指向的还是cat对象 // super.show() ; // 方式二:区别于super,在原型的show()方法中,this的还是cat对象 // Object.getPrototypeOf(this).show() ; // 方法三:使用call方法调用,重新指定this的指向,使其指定cat对象,完全等同于super。 // 因此,super是一个语法糖,方便调用 Object.getPrototypeOf(this).show.call(this) ; console.log('喵喵...'); } } cat.show() ; |

二、块级作用域

1、Hoisting

变量和函数的提升(Hoisting),是JavaScript中执行上下文(特别是创建和执行阶段)一种特殊的工作方式。

1)变量提升

|-------------------------|--------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 | // undefined console.log(a); // b is not defined console.log(b); var a = 100 ; b = 200 ; |

在JavaScript中,var声明的变量具有Hoisting特性,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面。上面代码编译后的结果为:

|---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | // var声明的变量具有Hoisting特性,会在程序最前面进行声明,并初始值为undefined var a = undefined; // undefined console.log(a); // b is not defined console.log(b); a = 100 ; // 未使用var声明的变量,不具有Hoisting特性 b = 200 ; |

2)函数提升

|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | fun1() ; console.log(fun2); fun2() ; // 声明函数 function fun1() { console.log('fun1'); } // var定义的函数表达式 -- 文本标记定义,与变量var声明一样 var fun2 = function() { console.log('fun2'); } |

声明的函数具有hoisting特性,而var定义的函数表达式与变量一样会提升且赋值为undefined。上面代码编译后的结果为:

|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 声明式函数会提升在最前面 function fun1() { console.log('fun1'); } // 与变量声明一样,var声明的函数会提升在前面,且初始值为undefined var fun2 = undefined ; // 成功调用 fun1() ; // 输出undefined console.log(fun2); // 因为fun2现在为undefined,因此报错 fun2() ; |

注意:函数和变量的提升中,函数优秀级更高一点,即函数要比变量的提升到更高的位置。

2、let

var一样,是用于声明变量的关键字(ES6新增)

1)作用域

let声明的变量支持块级作用域,只作用于当前块

|-----------------------|------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | if(true) { var m = 100 ; let n = 200 ; } console.log(m) ; console.log(n) ; |

2)变量提升

let声明的变量不会被"提升"

|-----------------|-----------------------------------------------------|
| 1 2 3 4 | // undefined console.log(m) ; let m = 100 ; |

3)重复定义

let不允许重复定义相同的变量

|-----------------|-----------------------------------------------------|
| 1 2 3 4 | let m = 100 ; let m = 100 ; // var可以,后者覆盖前者 |

4)暂时性死区

利用let声明的变量会绑定在这个块级作用域,不会受外界的影响。

|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 | var tmp = 123; if (true) { tmp = 'abc'; // 思考:输出结果为?why? // console.log(tmp); let tmp; } // 思考2:输出结果为?why? // console.log(tmp) ; |

暂时性死区指的是在当前作用域中,在使用 let 声明变量之前访问该变量会抛出 ReferenceError 错误,即使变量使用var声明也不例外。

也就是说,使用letconst声明的变量,只有在声明语句之后才能被访问。

思考题

|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 | var arr = []; for (var i = 0; i < 2; i++) { arr[i] = function () { console.log(i); } } // 以下两行代码,输出结果为? arr[0](); arr[1](); |

说明:变量i是全局的,在调用函数之前,循环已经执行完毕,此时的循环变量的值为2。因此,在调用函数时,函数使用的变量i是最新的值。

|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 | let arr = []; // let声明的变量i,在循环中都会产生一个块级作用域 for (let i = 0; i < 2; i++) { arr[i] = function () { console.log(i); } } // 以下两行代码,输出的结果为? arr[0](); arr[1](); |

说明:let关键字声明的变量具有块级作用域。每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的。因此,调用函数时输出对应作用域下的i值。

课堂练习

在页面中,定义以下的无序列表:

  • 你好
  • 我好
  • 大家好,才是真的好

编写JS,实现当用户单击以上无序列表时,弹出对应的文本内容及其下标索引。

提示:var实现 、let实现、闭包实现

3、const

声明常量,常量就是值(内存地址)不能变化的量。

|-------------|-----------------------------------------------------------|
| 1 2 | // 在声明常量的同时,必须初始化值,且值在后面的使用中不能改变 const 常量名称 = 值 ; |

const与let基本相同,产生块级作用域,不会提升,存在暂时性死区,必须先声明后使用,不允许重复定义。

const限制的只是常量指向的内存地地不变,但地址所引用的对象是允许被修改的。因为简单类型的数据直接存放在内存地址中,而复杂类型(如对象各数组)的数据是间接存储的。如:

|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 | // 定义一个常量数组 const LIST = [100, 200]; LIST.push(300); // 常量对应的数组是允许进行相关的操作 console.log(LIST); // 错误,常量不允许重新赋值 LIST = [100,200,300]; |

小结

  • const用于声明常量

  • 在声明常量的同时,必须初始值

  • 常量不能重新进行赋值

    • 如果是基本数据类型,不能更改值;
    • 如果是复杂数据类型,不能更改地址值,但复杂类型的数据是允许修改的。

4、var、let、const区别

  • 使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
  • 使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
  • 使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值

三、函数默认值

1、默认参数值

ES6之前

|---------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function fun(m, n) { // 参数默认值处理 m = m || 100 ; n = n || 200 ; console.log('m=' + m + ',n=' + n); } fun(1) ; fun(1,2) ; fun(1,undefined) ; fun(undefined,2) ; // 结果为? fun(0,0) ; |

ES6之后

在声明函数时,允许直接把默认值定义在形参中,如:

|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 | // 设置参数的默认值 function fun(m=100, n=200) { console.log('m=' + m + ',n=' + n); } fun(1) ; fun(1,2) ; fun(1,undefined) ; fun(undefined,2) ; // 结果为? fun(0,0) ; |

如果没有传递实参,则使用默认值,否则使用传递的实参数据。

2、默认值表达式

1)函数默认值支持表达式运算

|-----------------------|-----------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | // 设置参数的默认值 function fun(m=100*2, n=200+m) { console.log('m=' + m + ',n=' + n); } // 结果为? fun() ; |

2)函数默认值为自调用函数

|-------------------------|----------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 | function fun(m=100*2, n=(function(v){ return v + 200 })(200)) { console.log('m=' + m + ',n=' + n); } fun() ; |

四、spread与rest

1、spread:展开

语法:...名称

注意:

  • 名称必须是一个可iterable的对象。
  • 其中可iterable的对象有:数组、字符串、生成器(Generators)、集合(Collections)
  • 作用:把可iterable的对象展开,并返回展开的内容
1)数组操作

|---------------------|----------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | var arr1 = [1, 2, 3]; // 展开arr1数组,并把展开的内容添加到arr2中 var arr2 = ['AA', ...arr1, 'BB']; console.log(arr2); |

2)对象操作

|---------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var obj1 = {name:'zs',age:18} var obj2 = { sex:'男' , ...obj1 , weight:100 } var obj3 = { ...obj1, weight:200, // 如果存在相同的属性,则后者把前者覆盖 name:'张三' } console.log(obj2); console.log(obj3); |

3)参数传递

|-------------------------|------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 | function sum(a,b,c) { console.log(a + b + c); } var arr = [1,2,3] ; // 展开数组,依次把数据传递到函数的参数中 sum(...arr) ; |

2、rest:收集

rest与spread是相对的操作,rest可以收集剩余的参数,形成可变参数的函数,与Java中的...类似。

|------------------------------|--------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 | function sum(a,...args) { // 分别输出参数的值 console.log(a) ; console.log(args); } // sum(1) ; sum(1,2,3,4) |

在JS中,函数内置的数组对象(arguments),也可以收集函数的参数值。它们的区别如下:

  • rest只包含那些没有给出名称的参数,而arguments包含全部参数
  • arguments对象不是数组,它是一个像是数组的对象,而rest是数组对象
  • arguments是内置对象,默认存在于函数中,而rest必须使用...显式声明

另外,rest的参数必须定义在函数的最后一个参数中;函数对象的length属性不计算rest参数。

|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function sum(a,b,...args) { // 分别输出参数的值 console.log(a); console.log(b); console.log(args); console.log(arguments instanceof Array) ; console.log(args instanceof Array) ; } sum(1,2,3,4) // 返回1,rest不在length属性的计算范围内 console.log(sum.length); |

五、解构

解构(Destructuring)是ES6新增的一个赋值方法。按归对应的位置,从数组或对象中提取值,然后赋值给变量。使用解构将极大的方便从数组或对象中取值。

1、数组解构

语法:let|var|const [变量1,...,变量N] = 数组 ;

按顺序把数组的元素赋值给变量1,变量2,...

|-----------------|------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 | let [a, b, c] = [100, 200, 300]; console.log(a) // 100 console.log(b) // 200 console.log(c) // 300 |

如果变量数据与数组无数不匹配,多了忽略,少了变量赋值为undefined

|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 | let [a, b, c] = [100, 200]; let [aa,bb] = [10,20,30] console.log(a) // 100 console.log(b) // 200 console.log(c) // undefined console.log(a) // 10 console.log(b) // 20 |

特殊使用

|------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 按顺序对应赋值,逗号表示跳过 let [a, , b, , c] = [100, 200, 300, 400, 500, 600]; console.log(a) // 100 console.log(b) // 300 console.log(c) // 500 // 数组中的元素可以是任意类型的数据 let [aa, bb, cc, dd] = ['AA', [true, 20], { name: 'zs' }, function () { console.log('函数'); }]; console.log(aa); console.log(bb); console.log(cc); dd() ; // 结合rest使用 let [aaa,...bbb] = [1,2,3,4,5] ; console.log(aaa); console.log(bbb); |

2、对象解构

语法:let|var|const {属性名1[:别名],...,属性名N[:别名]} = 对象 ;

按顺序把对象的属性值赋值给属性名1,属性2,...。或赋值给相应的别名变量。

|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | let person = {name:'zs',age:18} // 变量名称必须与对象的属性名称一致 let {name,age} = person ; console.log(name); // zs console.log(age); // 18 // 可以把获取的属性值赋值给指定的变量名称 let {name:xingMing,age:nianLing} = person ; console.log(xingMing); // zs console.log(nianLing); // 18 // 允许重复使用属性,允许使用表达式,可以把取出的值赋值给对象的属性 // 当不是赋值操作时,必须使用括号,转换为表达式 let obj = {} ; ({name:obj.x,age:obj['user_'+'age'],name:obj.z} = person) ; console.log(obj); // {x: "zs", user_age: 18, z: "zs"} //结合rest的使用 let {username,...attrs} = {username:'小四',age:20,sex:'女'} console.log(username); // 小四 console.log(attrs); // {age:20,sex:'女'} |

3、解构函数参数

解构赋值也可以结合函数参数进行使用。

|------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 数组解构作为参数 function sum1( [m,n] ) { return m + n ; } // 对象解构作为参数 function sum2( {m,num:n} ) { return m + n ; } // 对象解构结合默认值作为参数 function sum3({m=100},{n=300}) { return m + n ; } console.log( sum1([1,2]) ); console.log( sum2({m:10,num:20}) ); console.log(sum3({},{})); console.log(sum3({m:300},{})); console.log(sum3({},{n:500})); console.log(sum3({m:500},{})); |

六、箭头函数

箭头函数(Arrow Function)简化了函数的定义,它不仅是语法糖,同时也更正了this复杂不可控的情况。

1、语法

|-------------------------|---------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 | // ():代表是函数; // =>:必须要的符号,指向哪一个代码块; // {}:函数体 ([参数列表]) => { 函数体 } // 代表把一个函数赋值给fn const fn = () => {} |

2、特点

1)省略大括号

函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号

|---------------------|-------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | function sum(num1, num2) { return num1 + num2; } // ES6写法 const sum = (num1, num2) => num1 + num2 ; |

2)省略小括号

如果形参只有一个,可以省略小括号

|-----------------------|-------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | function add (n) { return ++n ; } // ES6写法 // const add = (n) => ++n ; const add = n => ++n ; |

3)this关键字

箭头函数不动态绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this(父作用域)

由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值

|------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <button>点我看看</button> <script> var obj = { name:'测试', fun1 : function() { // 这里的this,根据调用此方法动态绑定的,由其调用的上下文決定this关键字的指向 // 即,谁调用fun1方法,this表示的就是谁 console.log(this); } , fun2 : () => { // 箭头函数不动态绑定this,在这里,fun2函数定义的位置上下文中,当前对象指定的是window对象 console.log(this); } } // this指的是obj对象 obj.fun1() ; // this指的是window对象 obj.fun2() ; // this指的是button对象 document.querySelector("button").onclick = obj.fun1 ; // 注意:不能通过call方法的调用,改变this的指向 // obj.fun2.call({name:'zs'}) ; </script> |

4)改变this的指向
  • 不能通过call、apply或bind调用方法,从而改变箭头方法中this的指向
  • 可以通过改变箭头函数定义上下文的this对象,从而改变箭头方法中的this指向

|---------------|----------------------------------------------------------------|
| 1 2 3 | // 接上例 // this仍然是window对象 obj.fun2.call({name:'zs'}) ; |

思考一

|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | const user = { name: '张三' } function fun() { // console.log(this); return () => { // 这里的this指向的是什么对象? console.log(this); } } // 通过call调用fun方法,并重新设置this的引用(指向) var reFun = fun.call(user) ; reFun() ; |

思考二

|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | var num = 100; var obj = { num : 200, fun : () => { console.log(this.num) } } // 输出的结果为? // 箭头函数this指向的是被声明的作用域里面,而对象没有作用域的, // 所以箭头函数虽然在对象中被定义,但是this指向的是全局作用域 obj.fun(); |

5)arguments、caller、callee在箭头函数中不存在

6)prototype属性在箭头函数中不存在

7)箭头函数不能作为构造器(构造方法)

8)不可以使用yield命令,因为箭头函数不能用作Generator函数。

七、循环

1、for...in

for...in语句 以任意顺序遍历一个对象的除Symbol以外的可枚举属性。

1)语法

|---------------|------------------------------------------------|
| 1 2 3 | for (variable in object) { statement } |

  • variable

    在每次迭代时,variable会被赋值为不同的属性名。

  • object

    非Symbol类型的可枚举属性被迭代的对象。

2)循环遍历数组

|-----------------------|---------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | var arr = [100,200,300] ; // 在循环遍历数组时,迭代变量指向的是数组的下标索引 for(let i in arr) { // console.log(i) console.log(arr[i]) } |

3)循环遍历对象

|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 | var obj = {name:'zs',age:18,sex:'男'} // 在循环遍历对象时,迭代变量指向的是对象的属性 for(let attr in obj) { // 输出属性名称:name,age,sex // console.log(attr) // 获取对象属性对应的值 console.log(obj[attr]) } |

说明:for ... in是为遍历对象属性而构建的,不建议与数组一起使用。

2、for...of

for...of语句可迭代对象(包括 ArrayMapSetStringTypedArrayarguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

1)语法

|---------------|-----------------------------------------------------|
| 1 2 3 | for (variable of iterable) { //statements } |

  • variable

    在每次迭代中,将不同属性的值分配给变量。

  • iterable

    被迭代枚举其属性的对象。

2)迭代数组

|------------------------------|------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 | let iterable = [10, 20, 30]; for (let value of iterable) { value += 1; console.log(value); } // 11 // 21 // 31 |

3)迭代字符串

|-----------------------|------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | let iterable = "hello"; for (let value of iterable) { console.log(value.toUpperCase()); } // HELLO |

4)迭代arguments对象

|---------------------------|------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 | (function() { for (let argument of arguments) { console.log(argument); } })(1, true, 'hello'); // 1 // true // hello |

5)迭代Map

|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]); // let iterable = [["a", 1], ["b", 2], ["c", 3]] ; for (let entry of iterable) { console.log(entry); } // ["a", 1] // ["b", 2] // ["c", 3] for (let [key, value] of iterable) { console.log(key + '=' + value); } // a=1 // b=2 // c=3 |

3、forEach

forEach() 方法对数组的每个元素执行一次给定的函数。

语法

|-----------|----------------------------------------------------------------------------|
| 1 | arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) |

callback为数组中每个元素执行的函数,该函数接收一至三个参数:

  • currentValue

    数组中正在处理的当前元素。

  • index 可选

    数组中正在处理的当前元素的索引。

  • array 可选

    forEach() 方法正在操作的数组。

  • thisArg 可选

    可选参数。当执行回调函数 callback 时,用作 this 的值。

|-----------------------|---------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 | var arr = ['你好', '我好', '大家好']; arr.forEach(function (v,i,a) { console.log(v); console.log(i); console.log(a); }); |

注意:forEach不能停止或退出

4、filter

过滤数组

|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 | var arr = [11, 22, 33, 44, 55, 66]; // 参数同forEach var newArr = arr.filter(function (value, index, array) { // 参数一是:数组元素 // 参数二是:数组元素的索引 // 参数三是:当前的数组 return value >= 50; }); // [55,66],返回经过滤后的一个新数组 console.log(newArr); |

计算购物车中,选中商品的总价

|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // 定义数组,判断数组各元素中的status属性是否都为 true const arr = [ { id:1, name:'苹果', status:true, price:10, count:1 }, { id:2, name:'雪梨', status:false, price:20, count:2 }, { id:3, name:'草莓', status:true, price:30, count:3 } } ; // 过滤选中的商品 // arr.filter(item=>item.status) ; // 方法一 // 定义累加变量 let total = 0 ; arr.filter(item=>item.status).forEach(item=>{ total = total + item.price * item.count ; }) ; console.log(total); // 方法二 // arr.filter(item=>item.status).reduce((累加变量,循环的当前元素)=>{},初始值); arr.filter(item=>item.status).reduce((total,item)=>{ total = total + item.price * item.count ; return total ; },0); // 简化 // arr.filter(item=>item.status).reduce((total,item)=>total = total + item.price * item.count,0); |

5、some

**查找数组中是否有满足条件的元素 **

|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var arr = [11, 22, 33, 44, 55, 66]; // 参数同forEach // 查找数组中是否有满足条件的元素 // 如果不满足,则返回false // 如果查找到满足条件的一个元素,则返回true var bl = arr.some(function (value, index, array) { // 参数一是:数组元素 // 参数二是:数组元素的索引 // 参数三是:当前的数组 return value >= 50; }); // true,返回是否存在满足条件的元素 console.log(bl); |

注意:区别forEach

  • forEach循环:一旦循环开始,不能终止循环
  • som循环:返回true时,终止循环

6、every

|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | // 定义数组,判断数组各元素中的status属性是否都为 true const arr = [ { id:1, name:'苹果', status:true }, { id:2, name:'雪梨', status:true }, { id:3, name:'草莓', status:true } } const r = arr.every(function(item){ return item.status== true; }) ; //const r = arr.every(item => item.status) ; console.log(r); |

八、Symbol

symbol 是一种基本数据类型 (primitive data type)。Symbol()函数会返回symbol 类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。

Symbol的主要目的是为了解决属性名冲突的问题,每个从Symbol()返回的symbol值都是唯一的。symbol值能作为对象属性的唯一标识,防止冲突。如果一个对象已经使用了某个属性名,再定义就会覆盖。

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。

ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol 。

1、创建Symbol

语法

|---------------|--------------------------------------------------------------------------------------------------------------------|
| 1 2 3 | // 使用Symbol函数返回Symbol类型的值 // description:可选的,字符串或数字类型。对symbol的描述,可用于调试但不是访问symbol本身。 Symbol([description]) |

创建

|---------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | var sym1 = Symbol(); var sym2 = Symbol('name'); var sym3 = Symbol(123456); console.log(sym1) ; console.log(typeof sym1) ; |

Symbol()函数返回的值都是唯一的,哪怕描述字符串相同也是不一样的

|-------------------|------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 | const sym1 = Symbol('name') ; const sym2 = Symbol('name') ; console.log(sym1 == sym2) ; console.log(sym1 === sym2) ; |

使用Symbol类型数据作为对象属性名时,必须加上中括号,如[symbole]

|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 | const sym_name = Symbol('name') ; const sym_age = Symbol('age') ; var obj = { [sym_name] : 'zs' , [sym_age] : 18 } console.log(obj[sym_name]) ; console.log(obj[sym_age]) ; console.log(obj) ; |

其它操作

|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | var sym = Symbol('name') ; // 输出Symbol的描述信息 console.log(sym.description); // boolean运算,返回false console.log(!sym); // 转换为字符串输出 console.log(sym.toString()); // 错误,进行加法运算,无法自动转换为字符串 console.log(sym + '-'); |

2、全局Symbol

1)Symbol.for

Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。

|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 创建一个全局 Symbol let name = Symbol.for('name') ; // 创建一个对象,使用Symbol作为属性 let user = { [name] : 'tom' } ; // 在全局注册表中,获取Symbol let uname = Symbol.for('name') ; // 输出对象的属性 console.log(user[uname]); // 判断从全局注册中获取的Symbol类型数据是否一样 console.log(name === uname); |

2)Symbol.keyFor

**Symbol.keyFor(sym) ** 方法用来获取全局symbol 注册表中与某个 symbol 关联的键。

如果全局注册表中查找到该symbol,则返回该symbol的key值,返回值为字符串类型。否则返回undefined

|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 | // 创建一个全局 Symbol var globalSym = Symbol.for("foo"); // 'foo' Symbol.keyFor(globalSym); // string Symbol.keyFor(typeof globalSym); // 非全部Symbol var localSym = Symbol(); // undefined, Symbol.keyFor(localSym); |

3、应用

实现枚举

|------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 定义一个对象,实现枚举的作用 let TYPES = { HIGH : Symbol() , MIDDLE : Symbol() , LOW : Symbol() } ; // 三个属性使用了Symbol类型数据,虽然都一样,但返回的是唯一的值 console.log(TYPES.HIGH); console.log(TYPES.HIGH==TYPES.MIDDLE); // 逻辑判断 var type = TYPES.HIGH ; if(type == TYPES.HIGH) { console.log('高'); } |

九、模板字符串

在ES6中新增的创建字符串的方式,使用反引号定义。在模板字符串,使用${变量名}的形式访问变量的值。在大括号中也支持表达式,大大提高程序的灵活性。

|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 | let obj = { name : 'zs' , age : 18 , sex : '男' } let info = `姓名:${obj.name},年龄:${obj.age + 1},性别:${obj.sex}` ; console.log(info) ; |

在模板字符串中可以调用函数

|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 | const sayHello = function (name) { return '你好,' + name; }; let info = `${sayHello('李四')}. I LOVE YOU`; console.log(info); // 注意可读性 console.log(`${(function(v){return v})('hello,world')}`); |

相关推荐
vvilkim20 分钟前
深入理解 TypeScript 中的 implements 和 extends:区别与应用场景
前端·javascript·typescript
GISer_Jing26 分钟前
前端算法实战:大小堆原理与应用详解(React中优先队列实现|求前K个最大数/高频元素)
前端·算法·react.js
武昌库里写JAVA1 小时前
SpringCloud
vue.js·spring boot·毕业设计·layui·课程设计
写代码的小王吧2 小时前
【安全】Web渗透测试(全流程)_渗透测试学习流程图
linux·前端·网络·学习·安全·网络安全·ssh
小小小小宇2 小时前
CSS 渐变色
前端
snow@li3 小时前
前端:开源软件镜像站 / 清华大学开源软件镜像站 / 阿里云 / 网易 / 搜狐
前端·开源软件镜像站
小小小小宇3 小时前
配置 Gemini Code Assist 插件
前端
one 大白(●—●)4 小时前
前端用用jsonp的方式解决跨域问题
前端·jsonp跨域
刺客-Andy4 小时前
前端加密方式 AES对称加密 RSA非对称加密 以及 MD5哈希算法详解
前端·javascript·算法·哈希算法
记得早睡~4 小时前
leetcode122-买卖股票的最佳时机II
javascript·数据结构·算法·leetcode