3

this的几种用法

关于this

this是什么?

理论上this是执行上下文的一个属性,this的值在进入到执行上下文的时候就已经确定了,且不会再改变。这一点很重要。

this的作用?

this 的机制提供了一个优雅的方式,隐式地传递一个对象,这可以让函数设计的更加简洁,并且复用性更好。

总览

  • new绑定,this指向由new创建的对象

  • 显示绑定,this指向apply或者call函数的第一个参数

  • 隐式绑定,this指向函数的调用者。

  • 默认绑定,严格模式下指向undefinded,非严格模式this指向全局对象。

  • 箭头函数绑定,this指向箭头函数外边包裹的普通函数

new绑定

当用new创建一个新的对象的时候,this指向了由new关键字声明创建的对象。

class Person(name){
    constructor(name){
        this.name = name;
    }
    showThis(){
        return this;
    }
}
var p1 = new Person('zhang');
var p2 = new Person('zhao');
console.log(p1.showThis() === p1);    //true
console.log(p2.showThis() === p2);    //true
console.log(p1.showThis() === Persion)    //false

可以看到,这种情况下this的值指向了由new创建的对象的引用。this会被绑定到这个对象上去。

显式绑定

所谓的显式绑定,指的是通过apply或者call方法的第一个参数。

call和apply的不同,两个方法的第一个参数都是this赋给的对象。不同在于,之后的参数被当作call方法的形参依次传进去,而apply则是接受一个数组。

看代码:

function foo(){
    console.log(this === obj);     //true
    console.log(this.a === 2);     //true
}

var obj = {
    a:2
}

foo.call(obj);

隐式绑定

隐式绑定用的次数比较多。一个最重要的特点就是,this的指定顺序和在哪里定义没有关系,而是取决于调用者。

严格意义来说,this是上下文里的一个属性(存放各种变量的变量对象同样也是上下文里的属性),this的值总是指向当前上下文的父级上下文,其实也就是当前上下文的调用者。

看代码:

//第一个简单的例子
var obj = {
    a : 1,
    foo : function(){
        console.log(this === obj);     //trun
        console.log(this.a === 1);     //true
    },
    bar : bar
}

//假如把一个属性定义在对象外边
function bar(){
    console.log(this === obj);      //true
}

obj.foo();
obj.bar();     //都是true

再来一个例子

function bar(){
    console.log(this === obj1);
    console.log(this === obj2);
}
function foo(){
    console.log(this === obj1);
    console.log(this === obj2);
}

var obj1 = {
    bar: bar,
    foo: foo
}

var obj2 = {
    bar: obj1.bar,
    foo: obj1.foo,
}

obj1.foo();     //true  false
obj2.foo();     //false  true
obj1.bar();     //true  false
obj2.foo();     //false  true

很简单,foo和bar两个方法分别由obj1和obj2调用,哪怕obj2中的foo和bar是obj1的也没关系,与在哪里定义没有关系,纯粹看是看谁调用的,obj2.foo()就是obj2调用的foo方法,所以,这个时候this指向obj2。

多说一句,如果既有显示绑定又有隐式绑定,当然是以显示绑定为准。

默认绑定

这种情况下,this不属于任何一个函数方法内,即在全局作用域下,这种情况下称为默认绑定。

非严格模式下,这个时候this值为window全局对象。

function foo(){
    console.log(this === window);
}

foo();

严格模式下,this的值是undefined

"use strict";

function foo() {
  console.log( this === undefined );
}

foo();               // true
foo.call(undefined); // true
foo.call(null);      // false

箭头函数

箭头函数其实是一个语法躺,箭头函数的里的this指向包裹箭头函数的那个函数的this值。很好理解。

// ES6
function foo() {
  setTimeout(() => {
    console.log(this === obj); // true
  }, 100);
}

const obj = {
  a : 1
}

foo.call(obj);

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log(_this === obj); // true
  }, 100);
}

var obj = {
  a : 1
}

foo.call(obj);

最后的总结

用伪代码的形式来表示


if (`newObj = new Object()`) {
  this = newObj
} else if (`bind/call/apply(thisArgument,...)`) {
  if (`use strict`) {
    this = thisArgument
  } else {
    if (thisArgument == null || thisArgument == undefined) {
      this = window || global
    } else {
      this = ToObject(thisArgument)
    }
  }
} else if (`Function Call`) {
  if (`obj.foo()`) {
    // base value . Reference = base value + reference name + strict reference
    // 例外: super.render(obj).  this = childObj ?
    this = obj 
  } else if (`foo()`) {
    // 例外: with statement. this = with object
   
    this = `use strict` ? undefined : window || global
  }
}

本文参考


张小草1018
285 声望8 粉丝