林秀栋的技术博客

this的指向

作为函数调用

function test() {
  this.x = 1;
  alert(this.x);
}
test(); //this指向全局对象Global,返回结果1

//稍做修改
var x = 1;
function test() {
  this.x = 0;
}
test();
alert(x); //this指向全局对象Global,改变了全局变量x,返回0

//匿名函数的this通常指向windows
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function () {
    return function () {
      return this.name;
    };
  },
};
alert(object.getNameFunc()()); //this指向windows,返回"The Window"(在非严格模式下)

//解决方法
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function () {
    var that = this;
    return function () {
      return that.name;
    };
  },
};
alert(object.getNameFunc()()); //返回"My Object"

//上面解决方法只是为了说明this的指向,更简单的解决方法:
var name = "The Window";
var object = {
  name: "My Object",
  getNameFunc: function () {
    return this.name;
  },
};
alert(object.getNameFunc()); //返回"My Object"

作为对象方法调用

function test() {
  alert(this.x);
}
var o = {};
o.x = 1;
o.m = test;
o.m(); //this作为对象o的方法,指向对象o,返回1

作为构造函数调用

function test() {
  this.x = 1;
}
var o = new test();
alert(o.x); //this指向对象o,返回1

//稍做修改
var x = 2;
function test() {
  this.x = 1;
}
var o = new test();
alert(x); //因为this指向对象o,所以全局变量x的值不变,返回2

一些面试题

1

var length = 10;
function fn() {
    console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};

obj.method(fn, 1);//输出是什么?

输出 10 和 2

这里的 this 绑定到了全局对象上,即 window 对象上。

var length = 10;
function fn() {
  console.log(this.length);
}

var obj = {
  length: 5,
  method: function () {
    fn.call(this);
  },
};

obj.method();

当我利用 call 方法改变 this 的绑定后,输出就是 5 了,说明 this 绑定到了 obj 对象上。

此时这个问题就需要回到那句”this 永远指向调用他的对象”了,在执行 obj.method()方法时,如果函数内部有 this,则 this 确实是指向 obj,但是 method()内部执行的是 fn()函数,而 fn()函数绑定的对象是 window,即 window.fn()。还是用例子来说明。

var length = 10;
function fn() {
  console.log(this.length);
}

var obj = {
  length: 5,
  method: function () {
    console.log(this.length); //输出5,执行method方法时,this绑定到调用对象obj上
    fn(); //输出10,执行method方法时,内部执行的是fn()函数,this绑定到了window上,即window.fn();
  },
};

obj.method(); //输出5 10

然后别忘了全局函数 fn 同时也属于 arguments 数组中的一员,即当作为 arguments 成员之一调用的时候,其作用域就绑定到了 arguments 上,this 也就是指向了 arguments 对象,所以 arguments[0]()这段代码调用了身为成员的 fn()函数,this.length 就等于是 arguments.length,又因为 method 传入的参数为 2 个,所以最后输出 2。

2

var x = 3;
var y = 4;
var obj = {
  x: 1,
  y: 6,
  getX: function () {
    var x = 5;
    return (function () {
      return this.x;
    })();
  },
  getY: function () {
    var y = 7;
    return this.y;
  },
};
console.log(obj.getX()); //3
console.log(obj.getY()); //6

3

var name = "the window";

var object = {
  name: "My Object",
  getName: function () {
    return this.name;
  },
};

object.getName(); //"My Object"

object.getName(); //"My Object"

(object.getName = object.getName)(); //"the window",函数赋值会改变内部this的指向,这也是为什么需要在 React 类组件中为事件处理程序绑定this的原因;

4

var a = 10;
var obt = {
  a: 20,
  fn: function () {
    var a = 30;
    console.log(this.a);
  },
};
obt.fn(); // 20

obt.fn.call(); // 10

obt.fn(); // 20

(obt.fn, obt.fn)(); // 10

new obt.fn(); // undefined

5

function a(xx) {
  this.x = xx;
  return this;
}
var x = a(5);
var y = a(6);

console.log(x.x); // undefined
console.log(y.x); // 6