一、对象字面量扩展
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
声明也不例外。
也就是说,使用let
或const
声明的变量,只有在声明语句之后才能被访问。
思考题
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| 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
语句 在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
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')}`);
|