0x01:this究竟指向什么?

普通函数的this

简单的法则:

  • 有对象就指向调用对象
  • 没调用对象就指向全局对象
  • 用new构造就指向新对象
  • 通过 apply 或 call 或 bind 可以改变this的指向

简单的例子:

var name = 'global';
var ob = {
    name: 'ob1',
    getName_1: function(){
        console.log(name);
    },
    getName_2: function(){
        console.log(this.name);//this指向调用的对象
    }
}

var getName_3 = ob.getName_2;

ob.getName_1();//global
ob.getName_2();//ob1,因为函数的调用对象是ob
getName_3();//global,因为调用对象是window

js只有函数作用域,没有块级作用域,因此定义在对象中的属性在对象的函数中并不能直接查找到。

箭头函数的this

参考资料:MDN:箭头函数
然而伴随着 ECMAScript 诞生的箭头函数在 this 的处理与以往不同。箭头函数并非单纯的匿名函数语法糖,匿名函数的this指向全局对象(浏览器中应该是window),而箭头函数的this指向定义该函数时所在上下文的this,举个例子:

var ob1 = {
     birth: 1990,
     getAge: function (year) { 
          var fn = function(y){
               return y - this.birth; // this指向window或undefined
          }; 
          return fn(year); 
     }
};
var ob2 = {
     birth: 1990,
     getAge: function (year) {
          var fn = (y) => y - this.birth; // this.birth为1990
          return fn(year);
     }
};

在调用ob1.getAge(2018)的时候,getAge 中直接调用了 fn,此时 fn 中的this指向 window。而在ob2中,定义fn这个箭头函数的时候,fn所在的上下文中this其实是 getAge 的this,即 ob2。

箭头函数不能通过 call/apply/bind 修改this.

0x02:普通函数的 call / apply / bind

Function.prototype.apply()

在 Javascript 中每个函数都有两个非继承来的方法:call()allpy()。通过调用这两个方法可以使该函数在特定的作用域中执行,也就意味着this的变化。同时这两个方法被用于设定函数运行的作用域。

语法

fun.apply(thisArg[, argsArray])//第一个参数是设定的this值,第二个参数是传给该函数的参数数组
fun.call(thisArg, arg1, arg2,...)//与apply不同的地方在于参数一一列出
fun.bind(thisArg[, arg1[, arg2[, ...]]])//ECMA5新增

设定作用域的例子

var color = 'red';//也即window.color
var ob = {color:'blue'};
function getColor(){
    console.log(this.color);
}

getColor();//red
getColor.call(ob);//blue

var getInstanceColor = getColor.bind(ob);
getInstanceColor();//blue