This指向问题
本文代码尽可能在浏览器环境下运行
面向对象语言中 this 表示当前对象的一个引用。
但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
举个例子:
function fn(){
console.log(this.x)
}
var obj = {
x:1,
f:fn
}
var x = 2
obj.f()
fn()
思考一下,上面的例子 obj.f()
和 fn()
会输出什么
答案是 1 2
在我们预想中,两次调用同一个函数,输出的值肯定是一样的,但是输出的值却不一样,这是因为this的环境不是固定不变的,而是随着执行环境的改变而改变的。
obj.f()
的this实在obj对象中的所以输出是1
fn()
的this是全局作用下调用的所以输出是2
在学习之前说一句通俗的判断this的指向规则:谁调用,this就指向谁 。下面就这句话实现解释。
直接用习题讲解,不再过多概述含义等。分了6种情况来讲解this指向问题
this的执行环境
1.全局作用域中(浏览器环境)
示例一:
function someFun(a) {
this.a = a;
}
someFun(5); //函数被调用时,this绑定的是全局对象 window,相当于直接声明了一个全局变量x,并赋值为5
console.log(a);
输出的是 5, 函数被调用时,this
绑定的是全局对象 window
,相当于直接声明了一个全局变量x
,并赋值为5
this.a => window.a
2.对象中的方法
示例二:
var o = {
a: 10,
b: {
a: 12,
fn: function () {
console.log(this.a); // 输出结果是 12
console.log(this); // 输出结果是 b 对象
}
}
}
o.b.fn();
调用时,调用的对象是 o.b
找到 o
对象中的b
对象,这时调用fn
这个方法的对象就是 o.b
所以此时的this
执行环境就时b
这个对象里面的环境
b: {
a: 12,
fn: function () {
console.log(this.a);
console.log(this);
}
}
所以自然而然的输出是 12 和 b 这个对象
示例三:
var o = {
a: 10,
b: {
a: 12,
fn: function () {
console.log(this.a); //undefined 若在对象o外定义a,则输出的就是其在外定义的值(全局变量)
console.log(this); // window
}
}
}
var j = o.b.fn;
j();
看上面的例子 j
这个变量储存了 o.b
对象方法fn
,之后调用。这时候的输出就是 undefined 和 window
这个对象
还是句话 谁调用,this就指向谁,j
储存了方法之后调用,在运行环境中有一个window
对象(包裹着代码中的变量方法等),这时候fn
这个方法就是window这个对象去调用
this.a
=> 找的是 window下面的 a
this
=> 则是 window
如果将代码改成以下
var a = 1
var o = {
a: 10,
b: {
a: 12,
fn: function () {
console.log(this.a); // 1 全局作用下有一个变量a
console.log(this); // window
}
}
}
var j = o.b.fn;
j();
示例四:
var point = {
x: 0,
y: 0,
moveTo: function (x, y) {
this.x = this.x + x;
this.y = this.y + y;
console.log(this.x);
console.log(this.y);
}
};
point.moveTo(1, 1)
这个如果看懂了上面的例子 ,很快就能得出答案
还是那句话 谁调用,this就指向谁
point
这个对象调用,this
就指向point
这个对象的内部
所以答案是 1 1 , 调用之后让我们来看看point
这个对象的内部
示例五:
var point = {
x: 0,
y: 0,
moveTo: function (x, y) {
this.x = x; //这里就等于改变了point对象里面的x变量
console.log(this.x); // 1
console.log(this); // point对象
// 内部函数
var moveX = function (x) {
this.x = x; //相当于给全局window定义了一个x并且为1
};
// 内部函数
var moveY = function (y) {
this.y = y; //相当于给全局window定义了一个y并且为2
}
moveX(x); // 这里是全局调用
moveY(y);
}
};
point.moveTo(1, 1);
console.log(point.x); // 1
console.log(point.y); // 0
console.log(x); // 1
console.log(y);// 1
还是那句话 谁调用,this就指向谁
point.moveTo(1, 1)
=>this
指向point
的内部
moveX(x)
和 moveY(y)
其实就相当于 示例一 这个例子,全局调用这两个函数, this
指的环境是全局环境
会给 window
这个对象 添加两个变量 x
y
3特殊情况
3.1立即执行函数
示例六:
var a = 10;
var foo = {
a: 20,
fn: (function () {
console.log(this); // window
console.log(this.a); // 10
})()
}
foo.fn
立即执行函数的this
指向window
3.2计时器
示例七:
var a = 10;
var oTimer1 = setInterval(function () {
var a = 20;
console.log(this.a); // 10
clearInterval(oTimer1);
}, 100);
计时器的this
指向window
示例八:
4显示函数改变this的指向
call、apply、bind (区别上网查找资料,本文暂不分析)
function foo() {
console.log(this.a);
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); //2
obj2.foo(); //3
obj1.foo.call(obj2); //3
obj2.foo.apply(obj1); //2
var bindFn = obj1.foo.bind(obj2)
bindFn()//3
还是那句话 谁调用,this就指向谁
这里的显示函数绑定
obj1.foo.call(obj2)
=> 将this的指向环境变成了 obj2
输出3
obj2.foo.call(obj1)
=> 将this的指向环境变成了 obj1
输出2
var bindFn = obj1.foo.bind(obj2)
=> bind
使用就是 拷贝一个函数给一个新的变量进行调用
5构造函数
示例九:
var name = 'Nicolas';
function Person() {
this.name = 'Smiley';
this.sayName = function () {
console.log(this);
console.log(this.name); //Person Smiley
};
setTimeout(this.sayName, 0); //window Smiley
}
var person = new Person();
person.sayName();
这里我们要小心,这是构造函数内部的this
我粗暴点的说 new
实例化一个对象 this
就指向那个实例化对象
实例化这个对象 person
之后, 其内部就包含 构造函数Person
的方法属性
但是万变不离其中 谁调用,this就指向谁
这里会输出两个结果
person Smiley
这个就是person
对象的输出结果 我们能理解
window Smiley
这个则是定时器 setTimeout
输出的结果,可以参考示例七
6箭头函数
示例十:
var obj1 = {
a: 10,
b: function() {
console.log('普通函数:', this)
}
}
var obj2 = {
a: 20,
b: () => {
console.log('箭头函数:', this)
}
}
obj1.b(); // 输出 {a:10, b:f} 即 obj1对象
obj2.b(); // 输出 window 对象
箭头函数本身是没有this
和 arguments
的,在箭头函数中引用 this
实际上调用的是定义上一层作用域的 this
,这里强调一下是上一层作用域,因为对象是不能形成独立的作用域。
总结:
1、还是那句话,谁调用,this就指向谁
2、看清楚this是在那种情况下使用的,是构造函数中、还是对象中、又或者是箭头函数。
3、显示函数(call、apply、bind)的区别,本文不够详细可以查阅其他资料。
4、灵活变通处理this指向
以上如有错误欢迎指正,一起学习 LOVE&&PEACE