this指向及call.apply.bind问题
开发和面试中都免不了不到函数指向的问题,并伴随着改变this指向的call.apply.bind的方法的使用。
一、this的指向
- 记住这句话:
this永远指向最后调用他的那个对象
- 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
- 所有函数内部都有一个变量this
//代码示例 1:
var name = "window_Name";
function show() {
var name = "watson";
console.log(this.name);
console.log("inner:" + this);
}
a();
console.log("outer:" + this)
//输出为: window_Name inner: Window outer: Window
①:代码示例1中,最后调用的a(),前面没有对象,相当于在全局内调用的,可以理解为在当前window环境下面调用的a() --->window.a,所以根据前面说的 this永远指向最后调用他的那个对象
,注意在严格模式下,全局对象是undefined,那么会报错:Uncaught TypeError: Cannot read property 'name' of undefined
。
//代码示例 2:
var name = "window_Name";
var a = {
name: "watson",
fn : function () {
console.log(this.name);
}
}
a.fn();
window.a.fn();
//输出为: watson watson
② 代码示例2中 a.fn()其实就是在window下面调用的,所以在a.fn()和window.a.fn()中的fn函数的指向都是a (this永远指向最后调用他的那个对象
) 所以输出都是一样的 watson。
//代码示例 3:
var name = "window_Name";
var a = {
// name: "watson",
fn : function () {
console.log(this.name);
}
}
a.fn();
//输出 undefined
③:代码示例3中,fn函数的直接调用对象是a,也就是说他所指向的内部的this指向,指向的是a对象,但是在a对象中并没有对name进行定义,所以输出的是undefined
//代码示例 4:
var name = "window_Name";
var a = {
name: "watson",
fn : function () {
console.log(this.name);
}
}
var f = a.fn;
f();
//输出 window_Name
在代码示例 4 中,我们将a对象中的方法fn赋值到了变量f中,然后在外层的window环境下面调用,其实就是window.f(),所以fn函数里面的fn其实指向的是window,this永远指向最后调用他的那个对象
,那么输出的便是 window_Name,而不是watson。
//代码示例 5:
var name = "window_Name";
function fn() {
var name = 'watson';
a();
function a() {
console.log(this.name);
}
}
fn()
//输出 window_Name
代码示例5 中fn调用是,执行了当前的a函数,在a函数而言,还是在当前的window对象下面执行的,所以this.name还是指向的是window_Name
二、改变this指向
- 使用 ES6 的箭头函数
- 在函数内部使用 _this = this
- 使用 apply、call、bind 。参考 MDN 中定义
- new 实例化一个对象
①:箭头函数
var name = "window_Name";
var a = {
name : "watson",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100);
}
func3: function () {
setTimeout( () =>{
this.func1()
},100);
}
};
a.func2()
//输出: 1、this.func1 is not a function 2、watson
- 函数的情况下,是会报错的,因为最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数,
箭头函数的 this 始终指向函数定义时的 this,而非执行时
。箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。
② 使用_this = this
var name = "window_Name";
var a = {
name : "watson",
func1: function () {
console.log(this.name)
},
func2: function () {
var _this = this;
setTimeout( function() {
_this.func1()
},100);
}
};
a.func2()
//输出 : watson
- 首先设置 var _this = this;,
- 这里的 this 是调用 func2 的对象 a,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this(指向变量 a) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 a 了。
③ 使用 apply、call、bind
- apply
var a = {
name : "watson",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100);
}
};
a.func2() // watson
- call
var a = {
name : "watson",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100);
}
};
a.func2() // watson
- bind
var a = {
name : "watson",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // watson
④ call.apply.bind的区别?
- call 方法接受的是若干个参数列表,apply 接收的是一个包含多个参数的数组
- bind 是创建一个新的函数,我们必须要手动去调用
//代码示例:
//call的使用
var a ={
name : "watson",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
//apply的使用
var a ={
name : "watson",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1,2]) // 3
//bind的使用
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3