彻底理解JavaScript中this指向
JavaScript中this的指向
情况1: 如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
情况2: 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象.
情况3: this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的
情况4: 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题。
情况5: 匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window
情况6: 箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window
详见代码,如下:
function a() {
var name = 'Tom'
console.log(this.name); //undefined (window下没有name这个属性)
console.log(this); //window
}
a(); //相当于window.a(),也就是window调用了a()方法,所以a方法中的this指向了window
//情况1:
var b = {
say:{
name: 'Tom',
fn:function(){
console.log(this.name); //Tom (say下有name这个属性)
}
}
};
b.say.fn(); //fn方法中的this指向了say
//情况2:
var c = {
name: 'Tom',
say:{
fn:function(){
console.log(this.name); //undefined (say下没有name这个属性)
}
}
};
c.say.fn(); //fn方法中的this指向了say
//情况3:
var name = 'Jon'
var d = {
name: 'Tom',
say:{
fn:function(){
console.log(this.name); // Jon (this指向window)
}
}
};
var j = d.say.fn; //fn虽然被say引用,但是没有被执行调用,所以this不是指向的say,而是指向调用的j()方法的window
j()
//情况4:
var name = "The Window";
var object = {
name: "The Object",
getNameFunc: function () {
return function () {
return this.name;
};
}
};
alert(object.getNameFunc()()); //The Window
//匿名函数的自我执行,没有被上级对象调用,所以this指向window
var name = "The Window";
var object = {
name: "The Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
}
};
alert(object.getNameFunc()()); //The Object
//在getNameFunc方法中将this绑定到that对象上,而that属于getNameFunc函数的内部变量,而这个函数的执行域是object。所以结果是"The Object"
//情况5:
var obj = {
say: function () {
setTimeout(function () {
console.log(this == window)
});
}
}
obj.say();
//true
//情况6:
var obj = {
say: function () {
setTimeout(() => {
console.log(this)
});
}
}
obj.say(); // this指向obj
构造函数中的this:
function Fn(){
this.user = "bing";
}
var a = new Fn(); //new关键字可以改变this的指向,将这个this指向实例化对象a
console.log(a.user); //bing
为什么this会指向a?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn() {
this.user = 'bing';
return {user:'xia'};//返回的是对象
}
var a = new fn;
console.log(a.user); //xia
function fn() {
this.user = 'bing';
return function(){};//返回的是对象
}
var a = new fn;
console.log(a.user); //undefined
function fn() {
this.user = 'bing';
return false; //返回的是布尔值
}
var a = new fn;
console.log(a.user); //bing
function fn() {
this.user = 'bing';
return 1; //返回的是数字
}
var a = new fn;
console.log(a.user); //bing
function fn() {
this.user = 'bing';
return 'xia'; //返回的是字符串
}
var a = new fn;
console.log(a.user); //bing
function fn() {
this.user = 'bing';
return undefined; //返回的是undefined
}
var a = new fn;
console.log(a.user); //bing
function fn() {
this.user = 'bing';
return null; //返回的是null
}
var a = new fn;
console.log(a.user); //bing
改变this指向
我们在js中可以使用document.write()
方法向网页中输入文本内容。如
document.write("test");
网页中就会被加入’test’文本。
但是如果我们像下面这么写呢?
var myWrite = document.write;
myWrite("test"); //报错
上面的代码首先是我将document.write方法赋值给myWrite方法。然后使用myWrite()方法向网页中输入文本内容。但是这里会报错,为什么呢?
原因就在这个write方法的this指针的域被改变啦!
document.write()方法的this是指向document的,所以可以向网页中输入文本内容。
但是我们将document.write方法赋值给myWrite对象,然后在调用myWrite()方法。调用myWrite()方法的对象域是全局变量window,相当于window.myWrite()。此时this指向window,而不指向document.所以会报错。
遇到上面的this指向被改变了,该怎么办呢?
这时候就要设置this的指针指向了,JavaScript有三个方法bind()、call()、apply()。
1.使用bind方法
a.bind(b); 就是将a()方法的this指针的作用域绑定到b对象的作用域上,也就是现在a的this指针的作用域就是b
如是上面的代码就可以改成:
var myWrite = document.write;
myWrite.bind(document)("test"); //此时的this指针指向了bind()的document,网页中正常输出test。
2.使用call方法
call(a, b);
: a是当前方法需要指向的域,后面的b是当前方法的参数,可以传多个参数,多个参数直接用逗号隔开即可,如 :call(a, b, c, d);
, b, c, d都是方法的参数(arguments)。
var myWrite = document.write;
myWrite.call(document, "test"); //此时的this指针指向了bind()的document,网页中正常输出test。
3.使用apply方法
apply(a, b);
:a是当前方法需要指向的域,后面的b是当前方法的参数,可以传多个参数,多个参数需要使用数组来传入。如apply(a, [b, c, d]);
,b、c、d为参数(数组)。
var myWrite = document.write;
myWrite.apply(document, "test"); //此时的this指针指向了bind()的document,网页中正常输出test。