前端常见题汇总(二)

一、箭头函数与普通函数(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接口实现)

  1. 可以避免所有 for-in 循环的陷阱
  2. 不同于 forEach(),可以使用 break, continue 和 return
  3. for-of 循环不仅仅支持数组的遍历。同样适用于很多类似数组的对象
  4. 它也支持字符串的遍历
  5. for-of 并不适用于处理原有的原生对象
for(let val of arr){
    console.log(val);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值