箭头函数跟普通函数的this

390 阅读2分钟

箭头函数跟普通函数this的区别

  1. 指向不同
普通函数的this指向方法调用时的对象,可以通过call,apply,bind来改变this指向

箭头函数不会创建自己的this,他只会从自己作用域的上一层继承this。
call,aply,bind,不能改变this指向,只能用来传递参数
  var obj = {
        a: 10,
        b: () => {
            console.log(this.a) // undefined
            console.log(this) // Window
        },
        c: function () {
            console.log(this.a) // 10
            console.log(this) // {a:10, b:()=>{},c:f()}
        }
    }
    console.log(obj.b())
    console.log(obj.c())
  1. 箭头函数没有原型
 var a = () => { }
    console.log('原型', a) // ()=>{}
    console.log('原型', a.prototype) // undefined
  1. 箭头函数不能绑定argument,取而代之的事rest参数...来解决
     let A = () => {
         console.log(arguments); // arguments is not defined
      }
        A(1, 2, 3, 4, 5, 8);
   
   let B = (...rest) => {
        console.log(rest); // [1, 2, 3, 4, 5, 8]
        console.log(Object.prototype.toString.call(rest)) // [object Array]
    }
    B(1, 2, 3, 4, 5, 8);
   

这也说明,es6中的rest(...)参数,返回的是一个数组类型,不像arguments返回的是类数组

  1. 箭头函数是匿名函数,不能作为构造函数,不能new
无法实例化的原因:
没有自己的this,无法调用call,apply来改变this指向。如果非要改变,那就直接该父类的this
没有prototype属性,而new命令执行的时候需要将构造函数的prototype赋值给新的对象的_proto

手写call,apply,bind

// call实现
Function.prototype._call = function (context, ...args) {
        const fn = Symbol('fn')
        let ctx = context || window
        ctx.fn = this
        let res = args.length > 0 ? ctx.fn(...args) : ctx.fn()
        delete ctx.fn
        return res
    }
    // apply实现
    Function.prototype._apply = function (context, args = []) {
        const fn = Symbol('fn')
        let ctx = context || window
        ctx.fn = this
        if (!(args && args instanceof Array)) {
            throw ('请传入数组')
        }
        let res = args.length > 0 ? ctx.fn(...args) : ctx.fn()
        delete ctx.fn
        return res
    }
    // bind实现
    Function.prototype._bind = function (context, ...args) {
        let that = this
        return function () {
            return that._call(context, ...args)
        }
    }
    var name = "1";
    var obj = {
        name: 2,
        prop: {
            name: 3,
            getName: function (age, s) {
                return {
                    name: this.name,
                    age: age,
                    s: s
                }
            }
        }
    }
    console.log(obj.prop.getName(3, 4)); //  3, 3, 4
    console.log(obj.prop.getName.call(obj, 3, 4)); //this是obj 2, 3, 4 
    console.log('_call实现', obj.prop.getName._call(this, 3, 4)); //this是window 1, 3, 4
    console.log('_apply实现', obj.prop.getName._apply(this, [2, 3])); //this是window 1, 2, 3
    let bindHandle = obj.prop.getName._bind(this, 2, 3)
    console.log('bindHandle()', bindHandle())//this是window 1, 2, 3

类数组转化为数组

 let A = function () {
      console.log('类数组', arguments); // Arguments(6) [1, 2, 3]
      console.log('法一', Array.prototype.slice.call(arguments)); // [1, 2, 3]
      console.log('法二', Array.from(arguments)); // [1, 2, 3]
      console.log('法三', [...arguments]); // [1, 2, 3]
  }
  A(1, 2, 3);

行文思考

  1. bind的实现,其实是利用了闭包,和延迟执行(柯里化)这两个特性。

闭包文章输出地址

柯里化文章地址