理解js中的this

114 阅读2分钟

作为js中一个很难解释清楚的概念,this的问题一直困扰着前端的初学者们,在不同的语境里,this的含义不同,那么究竟怎么理解js中的this呢?

全局环境下

  • this指向window node环境指向global
  • 普通函数里的this 指向window 严格模式下指向undefined
function f() {
    console.log(this === window);
}
f() // true

function f() {
    'use strict';
    console.log(this === undefined);
}
f() // true

构造函数里 指的是实例

var Obj = function (p) {
  this.p = p;
};
var 0 = new Obj('hello');
0.p // 'hello'

对象的方法里,指的是引用它的对象 且不能被继承

var obj ={
  foo: function () {
    console.log(this);
  }
};

obj.foo() // obj

// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window

很难理解吧,上面代码中,obj.foo就是一个值。这个值真正调用的时候,运行环境已经不是obj了,而是全局环境,所以this不再指向obj

可以这样理解,JavaScript 引擎内部,objobj.foo储存在两个内存地址,称为地址一地址二

obj.foo()这样调用时,是从地址一调用地址二,因此地址二的运行环境是地址一this指向obj

但是,上面三种情况,都是直接取出地址二进行调用,这样的话,运行环境就是全局环境,因此this指向全局环境。上面三种情况等同于下面的代码

   // 情况一
(obj.foo = function () {
  console.log(this);
})()
// 等同于
(function () {
  console.log(this);
})()

// 情况二
(false || function () {
  console.log(this);
})()

// 情况三
(1, function () {
  console.log(this);
})()

不能被继承指的是

var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};

a.b.m() // undefined

箭头函数中的this

箭头函数中的this指向它所在的执行上下文的this

    function person() {
        setTimeout(() => {
            console.log(this);
        }, 1000)
    }
    
    const Person = new person(); // Person
    
    let a = () => {
       console.log(this); // window
    }

call apply bind改变this指向

call apply bind的区别

  • call apply绑定this之后会立刻执行,bind返回绑定后的函数
  • call的参数是一个一个的参数,apply是一个数组,bind的参数也是一个数组

实现一个call

    Function.prototype.call = (ctx, ...args) => {
        const context = ctx || window;
        let symbol = Symbol();
        context[symbol] = this;
        let res = context[symbol](args);
        delete context[symbol];
        return res
    }

实现一个apply

    Function.prototype.apply = (ctx, ...args) {
        const context = ctx || window;
        let symbol = Symbol();
        context[symbol] = this;
        let res = context[symbol](args);
        delete context[symbol];
        return res
    }

实现一个bind

    Function.prototype.bind = (context, ...args) => {
        const ctx = context || window;
        const fn = this;
        return function() {
            return fn.apply(ctx, args);
        }
    }