javascript中this的指向初探
在前端开发中this
的指向问题是一个非常基础也很重要的知识点,是开发人员绕不过去的一个问题。那么今天用几个面试题来聊一聊前端中this
问题吧.
首先需要知道一点:this 永远指向最后调用它的那个对象,通俗一点就是指向他爹。
this 指向
案例 1
this.value = "value";
function fn() {
var value = "innerValue";
console.log(this.value);
}
fn(); // value
这个题大家应该都知道答案肯定是打印value
,那么为什么打印的结果是value
呢?看刚才那句话this 永远指向最后调用它的那个对象,这个时候我们就想了究竟是谁调用了fn
呢?其实就是window
,这个时候我们就清楚了,哦原来是widnow
调用了fn
,所以这个this
就指向了window
,因此就输出打印value
。
案例 2
this.num = 30;
const obj = {
num: 20,
fn: function () {
console.log(this.num);
},
};
obj.fn(); // 20
var fn = obj.fn;
fn(); // 30
分析:
- 默读三遍this 永远指向最后调用它的那个对象,this 永远指向最后调用它的那个对象,this 永远指向最后调用它的那个对象
- 根据
案例1
的思路,是obj
调用的fn
,函数内部this
指向的是obj
,所有打印输出obj.num
的值20
- 接下来我们声明了一个全局变量
fn=obj.fn
,调用fn()
等同于调用window.fn()
,所有打印输出window.num
的值30
案例 3
难度加大一点
this.a = 20;
function go() {
console.log(this.a);
this.a = 30;
}
go.prototype.a = 40;
var test = {
a: 50,
init: function (fn) {
fn();
console.log(this.a);
return fn;
},
};
//输出1
console.log(new go().a);
// 输出2
test.init(go);
var p = test.init(go);
p();
在做这个题目之前,首先有一个知识点需要清楚,代码如下,首先会找对象的值,然后再去找原型对象的值。也就是说p.a
的时候会先在对象上获取这个值,没有则在原型对象上获取,明白了这个就好了。
function P() {
this.a = 1
}
P.prototype = 2
let p = new P()
console.log(p.a) // 1
分析:
-
首先实例化一个对象
new go()
,同时调用函数go
,代码执行console.log(this.a)
,此时的this
是指向实例化对象,按照 刚才的所说的,先找对象上的key值,发现没有,然后找原型对象上的a
,发现go.prototype.a = 40
所以打印40,同时this.a = 30
,然后获取new go().a
重复上一步的思路,先读取对象的key值发现存在且为30,所以整个的结果就是先输出40,然后输出30 -
调用
test.init(go)
,首先调用go
方法,我们可以这里理解test.init(window.go)
,其实就是调用window.go()
,首先打印this.a
,也就是window.a
,发现全局声明了this.a=20
,所以打印20
,同时注意接下来的this.a=30
,已经将全局的a
改变了此时的window.a=30
,接下来执行console.log(this.a);
,此时的this
指向test
,所以输出打印50
,因此最后的结果就是先输出20,然后50 -
执行
var p = test.init(go)
,重复步骤2首先调用全局函数go
,打印全局的a
,步骤2中更改了全局a
的值为30
,所以先输出30
,然后调用test
对象的init
方法,执行console.log(this.a)
,因此打印50
,最后定义了一个全局p
,并返回了一个函数go
,执行p()
,也就是执行window.p()
,此时的window.a===30
所以打印30
,最终的输出就是30,50,30 -
综合以上分析最终的输出就是40,30,20,50,30,50,30