昨天跟群里的朋友讨论bind的polyfill的时候,说到了instanceof操作符的作用机制,然后讨论到深夜。
function F(){}
var v = new F();
v instanceof F;
上面这段代码中,instanceof那段语句执行时是怎么运作的?我的理解如下:
执行: v instanceof F;
1、 v.__proto__;//这里并非真的能直接访问__proto__,只是便于表述与说明,实例找到原型
2、 F.prototype;//F通过prototype属性找到它创建的实例的原型
3、 v.__proto__ === F.prototype ? true : false;//最后两边比对是否相等
图示: v---->v.__proto__---->check<----F.prototype<----F
然而,那位朋友不这么认为,我们昨天以下面的代码讨论了很久:
function A(){};
function B(){};
B.prototype = A.prototype;
a = new A();
b = new B();
a instanceof B;//true,#1 做个编码标记,后面好引用说明
a instanceof A;//true,#2
b instanceof B;//true,#3
b instanceof A;//true,#4
他认为,这段代码因为B.prototype被A.prototype覆盖了,所以在各自创建实例前,原型实际上是一个了(这点我认同),所以实例a和实例b的原型都是同一个,也就是A.prototype(这点我也认同)。所以在instanceof的时候,#2和#4标记的代码会返回true(这点我认同,没问题),#1和#3标记的代码也会返回true(这就有问题了,这里不是指输出结果有误,而是指a找到原型再找到B的prototype的这种理解有误,为防止误解,故此修改)。
我理解的他的理解是这样的:
∵图示: ________________________
a--->a.__proto__--->|A.prototype/ |
b--->b.__protp__--->| /B.prototype |
—————————————————————————
∴得出#1#2#3#4都是true
我觉得在这个逻辑中有个问题:A.prototype和B.prototype以及a.__protp__和b.__protp__都只是指针,指向的一个内存中实际存在的无名对象,光是知道大家都能指向这个对象,难道经过这个无名对象就能找到大家么(所以原型链中才有“儿子知道爸爸和爷爷,但是爸爸只知道爷爷不知道儿子,爷爷不知道爸爸和儿子”,也就是单项链不是双向的)?这就好比,PersonA、PersonB都有个无名氏的电话号码,但是光凭这一点就能证明这个无名氏有PersonA、PersonB的电话号码么?
我想反驳他的就是实际上通过实例a的原型属性__proto__是找不到构造函数B的属性prototype的,更加不能找到B,因为那个(A.prototype和B.prototype都指向的)无名对象里存的constructor是指向的A这个构造函数。
刚开始,我还说除非a通过a.__proto__找到A.prototype或B.prototype,然后转为字符串截取出来B,还是说得通。可今天仔细想想,不对!还是我开始理解的那种instanceof两边的操作数指向各自的一个对象,再判断各自指向的对象是否是同一个。
抱歉,“前情概要”啰嗦了很多,敢问sf大神,在不改动变量访问者的前提下,有否方法监听变量被访问的次数?
我想通过这个方法来检测到instanceof判断实例时,B.prototype和B.prototype.constructor有没有被访问,以此作为依据来证实我的猜测/理解。
如果以上问题让各位有点绕懵了,非常抱歉!也许是我有点钻牛角尖,但是我始终没有证据证明我的理解,非常困惑,自己解决不了,才来sf求助的。感谢回答的各位。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
所以你的意思是1和3应该返回false?
下面是ECMA里面对
instanceof的说明:前面都是表达式计算和取值,关键是第7步,
x instanceof Y最后会调用内部方法:Y.HasInstance(x)。下面来看看这个方法。省掉那些检查代码,概括起来,
Y.HasInstance(x)会执行以下步骤:注意判断是递归的,直到
x的原型链到达顶端为止。结论:你的理解是对的。
a instanceof B;//true,#1instanceof操作符并不检查a是否由B构造函数创建的,而是检查B.prototype是否在a对象的原型链中.a通过A构造函数创建,而在之前B.prototype = A.prototype;导致的结果为B.prototype和A.prototype都指向同一个对象,a.__proto__指向的对象为A.prototype指向的对象;这个对象和B.prototype指向的对象相同。那么通过检查a的原型链就能发现B.prototype指向的对象能够被找到(A.prototype指向的对象),输出结果为true.同理,下面的代码,#5输出true,#6输出false。比较的实际的对象;和构造函数和名字无关,#7和#8输出的差别说明了这一点
补充:
原型链中有记录所有原型对应的构造函数的prototype属性的索引么?原型连接是通过prototype(构造函数)/__proto__(实例对象)属性将不同的对象串联起来的。原型也是对象,没有什么特别的~~就像变量赋值
看看原型链是怎么回事,如下:
[0] 执行完毕后,
E.prototype指向A的实例对象instanceA,这个实例对象instanceA.__proto__指向A.prototype;A.prototype指向B的实例对象isntanceB,这个实例对象instanceB.__proto__指向B.prototype;B.prototype指向的也是一个实例对象instance_UNKNOWN,这个实例对象instance_UNKNOWN.__proto__指向Object.prototype,而Objet.prototype指向为null;原型连接结束E.prototype-->instanceA.__proto__-->A.prototype-->instanceB.__proto__-->B.prototype-->instance_UNKNOWN.__proto__-->Object.prototype-->null
明白了这个链条,我们就好理解为什么
[1][2][3][4]都输出true了不明白你的问题的问题在哪.
为什么需要从B.prototype找到B? 如果不能会怎样?
instanceof 运算符一种实现: