一、箭头函数与普通函数(function)的区别是什么?构造函数(function)可以使用 new 生成实例,那么箭头函数可以吗?为什么?
箭头函数是普通函数的简写,可以更优雅的定义一个函数,和普通函数相比,有以下几点差异:
1、函数体内的 this 对象,就是定义时所在的作用域中的 this 值,而不是使用时所在的对象。this 相当于一个普通变量会向作用域链中查询结果,同时定义时所在对象也并不等于所在对象中的 this 值。
2、不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
3、不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
4、不可以使用 new 命令,因为:
- 没有自己的 this,无法调用 call,apply。
- 没有 prototype 属性 ,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 __ proto __
检验箭头函数中的rest参数及普通函数的arguments对象
注:
1、箭头函数必须以解构
的形式传rest参数(相当于普通函数的arguments),否则会报错,或者是undefined
2、普通函数有默认的arguments,不支持解构,不需要传arguments
3、rest参数和 arguments对象的区别
- rest参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参。
- arguments对象不是一个真正的数组,只是可以下标访问而已, 而rest参数是真正的Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如
sort,map,forEach或pop
。 - arguments对象还有一些附加的属性 (如callee属性)。
更多【ES6】函数默认参数与rest参数
请看https://www.jianshu.com/p/9078fdffd810
检验Generator 函数与yield 命令
注:
1、Generator函数是es6提供的一种异步编程
的解决方案,语法行为与传统函数完全不一样。
2、Generator函数有多种理解角度,从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。
3、执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了是状态机还是一个遍历器对象生成函数。 返回遍历器对象,可以依次遍历Generator函数内部的每一个状态。
4、形式上Generator函数是一个普通函数,但是有两个特征。一是,function关键字与函数之间有一个 * ,二是,函数体内部使用yield表达式,定义不同的内部状态
。
Generator函数是分段执行的。yield表达式只是暂停的标志,而next方法可以恢复执行。
function* gen(){
yield "hello";
yield "world";
return "ends"
}
let g1=gen()
console.log(g1.next()); // {value:'hello',done:false}
console.log(g1.next()) // {value:"world",done:false}
console.log(g1.next()) // {value:"ends",done:true}
console.log(g1.next()) // {value:undefined,done:true}
console.log(g1.next()) // {value:undefined,done:true}
解析过程
- 第一次调用,Generator函数开始执行,直到遇到第一个yield表达式为止。 next方法返回一个对象,它的value属性就是当前yield表达式的值hello,done属性值false,表示遍历还没结束。
- 第二次调用,Generator函数从上一次yield表达式停下来的地方,一直执行到下一个yield表达式。 next方法返回的对象的value属性就是当前yield表达式的值world,done属性值false表示当前遍历还没结束。
- 第三次调用,Generator函数从上一次yield表达式停下来的地方,一直执行到return语句(如果没有return语句,就执行到函数结束)。next返回的对象的value属性,就是紧跟在return语句后面的表达式的值。如果没有return语句,则属性的值为undefined
5、Generator函数的传参
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
var a = foo(1)
function* demo() {
foo(yield 'a'); // OK
let input = yield; // OK
console.log(input,'********************')
}
demo().next()
// {value: "a", done: false}
总结一下,调用Generator函数,返回的都是一个遍历器对象,代表Generator函数内部指针。 以后每次调用Generator函数的next方法,就会返回一个有着value和done两个属性的对象。 value属性表示当前内部状态的值,是yield表达式后面那个表达式的值;done属性值是一个布尔值,表示当前遍历是否结束。
更多Generator函数的语法
请看https://www.jianshu.com/p/f703d3f54ebd
检验new 命令
普通函数new 过程大致是这样的:
function newFunc(father, ...rest) {
var result = {};
result.__proto__ = father.prototype;
var result2 = father.apply(result, rest);
if (
(typeof result2 === 'object' || typeof result2 === 'function') &&
result2 !== null
) {
return result2;
}
return result;
}
箭头函数特点:
1.不可以使用new 命令
二、如何用for of 遍历对象
如何遍历对象,一般来说都会想到 for-in
let obj = {
a: 1 ,
b: 2 ,
c: 3 ,
d: 4
} ;
for( let k in obj ){
console.log(k, obj[k]);
}
// 输出结果
// a 1
// b 2
// c 3
// d 4
但是当有一些继承关系的时候,就有些麻烦了,遍历的时候会把继承的属性也遍历出来,这就得加些判断了
let newObj = Object.create(obj) ;
newObj.e = 5;
newObj.f = 6;
for( let k in newObj ){
console.log(k, newObj[k]);
}
// 输出结果
// e 5
// f 6
// a 1
// b 2
// c 3
// d 4
for( let k in newObj ){
if( newObj.hasOwnProperty(k) ){
console.log(k, newObj[k]);
}
}
// 输出结果
// e 5
// f 6
可以省略一层,变成下面这样
for( let k in newObj ) if( newObj.hasOwnProperty(k) ){
console.log(k, newObj[k]);
}
在 ES6 中提供了 for-of,可以很方便的遍历数组和类数组,但是却不能遍历对象,这是为什么,与 for-in 仅仅相差一个单词,用途也是遍历,为什么却不能使用在对象上?
原来 ES6 中引入了 Iterator,只有提供了 Iterator 接口的数据类型才可以使用 for-of 来循环遍历
,而 Array、Set、Map、某些类数组如 arguments 等数据类型都默认提供了 Iterator 接口,所以它们可以使用 for-of 来进行遍历
ES6 同时提供了 Symbol.iterator
属性,只要一个数据结构有这个属性,就会被视为有 Iterator 接口,接着就是如何实现这个接口了,如下就是一个最简实现:
var newObj = {e:5,f:6}
newObj[Symbol.iterator] = function* (){
let keys = Object.keys( this ) ;
for(let i = 0, l = keys.length; i < l; i++){
yield {
key: keys[i],
value: this[keys[i]]
};
}
}
for(let v of newObj){
console.log( v );
}
// 输出结果
// {key: "e", value: 5}
// {key: "f", value: 6}
三、for,forEach,for of 和 for in 的区别
let arr=[1,2,3,4,5];
arr.b='100';
for
for是编程式
for(let i=0;i<arr.length;i++){
console.log(arr[i]);
}
forEach
forEach是声明式(不关心如何实现),没办法使用 break 语句跳出循环,或者使用return从函数体内返回。
arr.forEach(function(i){
console.log(item);
});
for in
- 一般用于
遍历对象
的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。 - 不建议使用for in 遍历数组,因为输出的顺序是不固定的。
- 如果迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环之前,先检查该对象的值是不是null或者undefined
- key会变成字符串(String)类型。
- 包括数组的私有属性也可以打印出来,即循环不仅会遍历数组元素,还会遍历任意其他自定义添加的属性,如,arr上面包含自定义属性,arr.b,那这次循环中也会出现此b属性。
for(let key in arr){
console.log(key);
}
for of
for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
支持return,并且是值 of 数组(不能遍历对象,可通过Iterator接口实现)
- 可以避免所有 for-in 循环的陷阱
- 不同于 forEach(),可以使用 break, continue 和 return
- for-of 循环不仅仅支持数组的遍历。同样适用于很多类似数组的对象
- 它也支持字符串的遍历
- for-of 并不适用于处理原有的原生对象
for(let val of arr){
console.log(val);
}