阅读数:

认清js this链

0

说明

js中少不了继承、引用,this的指向理解正确与否直接决定了结果的准确性,我们先看一道某公司的变态
面试题

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = { demo: 5 };
this.show = function () {
console.log(this.a , this.b , this.c.demo );
}
}
function Child() {
this.a = 2;
this.change = function () {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show();
child1.show();
child2.show();
child1.change();
child2.change();
parent.show();
child1.show();
child2.show();

运行结果如下

jsfun1

分析

我们先不着急看这个,我们来个变种,将后半部分改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show();
child1.show();
child2.show();
child1.change();
child1.show();
child2.change();
child2.show();
parent.show();

运行结果如下

jsfun2

这样是不是好理解点呢:

首先,需要明确一个原则:就近原则,取决于this调用时的位置,谁调用方法,this就指向哪个对象;
具体来说:

  • 每个new会重新分配内存
  • 当实例上存在属性时, 用实例上的
  • 如果实例不存在,顺在原型链,往上查找,如果存在,就使用原型链的
  • 如果原型链都不存在,就用Object原型对象上的
  • 如果Object原型对象都不存在, 就是undefined

具体分析:
1、第一个 p.show
console.log(this.a , this.b , this.c.demo ); this指parent,this.a就近找指为1,this.b就近是[1, 2, this.a] 而this.a就近是1,所以this.b是[1,2,1]
this.c.demo不用多说,所以最终是 1 [ 1, 2, 1 ] 5

2、c1.change
c1.show

1
2
3
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;

this.a就近应该是child1.this.a,被赋值为11,this.b就近child里没有定义往上找到parent,this.b为[1,2,1],
push(this.a)及push(11)所以最终 this.b为[1,2,1,11],this.a=this.b.length=4;
this.c.demo=this.a++=4++=4;而此时 this.a变成了5(因为++)所以最终是 5 [ 1, 2, 1 ,11] 4

3、c2.change
c2.show

this.a就近应该是child2.this.a,被赋值为12,this.b就近child里没有定义往上找到parent,this.b为[1,2,1,11],
push(this.a)及push(12)所以最终 this.b为[1,2,1,11,12],this.a=this.b.length=5;
this.c.demo=this.a++=5++=5;而此时 this.a变成了6(因为++)所以最终是 6 [ 1, 2, 1 ,11,12] 5

4、第二个 p.show

this指parent,this.a就近找指为1,this.b就近是[1, 2, this.a] 而this.a就近是1,所以this.b是[1,2,1]
this.c.demo不用多说,所以最终是 1 [ 1, 2, 1 ] 5

至此大家应该明白点了吧,接着我们分析原题:
区别在于,两change在一起,结果就发生了变化,我们按照上面思路分析看看:

具体分析:
1、第一个 p.show
console.log(this.a , this.b , this.c.demo ); this指parent,this.a就近找指为1,this.b就近是[1, 2, this.a] 而this.a就近是1,所以this.b是[1,2,1]
this.c.demo不用多说,所以最终是 1 [ 1, 2, 1 ] 5

2、c1.change

1
2
3
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;

this.a就近应该是child1.this.a,被赋值为11,this.b就近child里没有定义往上找到parent,this.b为[1,2,1],
push(this.a)及push(11)所以最终 this.b为[1,2,1,11],this.a=this.b.length=4;
this.c.demo=this.a++=4++=4;而此时 this.a变成了5(因为++)

3、c2.change

1
2
3
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;

this.a就近应该是child1.this.a,被赋值为12,this.b就近child里没有定义往上找到parent,this.b为[1,2,1,11],
push(this.a)及push(12)所以最终 this.b为[1,2,1,11,12],this.a=this.b.length=5;
this.c.demo=this.a++=5++=5;而此时 this.a变成了6(因为++)

4、c1.show

console.log(this.a , this.b , this.c.demo ); this.a就近应该吃child1.this.a为5,this.b就近child
里没有定义往上找到parent,this.b为[1,2,1,11,12],this.c.demo就近child里没有定义往上找到parent,this.c为5,
所以最终是 5 [ 1, 2, 1,11,12] 5

5、c2.show

console.log(this.a , this.b , this.c.demo ); this.a就近应该吃child2.this.a为6,this.b就近child里没有定义往上找到parent,this.b为
[1,2,1,11,12],this.c.demo就近child里没有定义往上找到parent,this.c为5,所以最终是 6 [ 1, 2, 1,11,12] 5

6、第二个 p.show

this指parent,this.a就近找指为1,this.b就近是[1, 2, this.a] 而this.a就近是1,所以this.b是[1,2,1]
this.c.demo不用多说,所以最终是 1 [ 1, 2, 1 ] 5

最后

是不是清楚了呢,js继承引用中的变态this,万变不离其宗,就近就近


^-^欢迎回复交流^-^


0
赏点咖啡钱^.^