昨天跟群里的朋友讨论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求助的。感谢回答的各位。
所以你的意思是1和3应该返回false?
下面是ECMA里面对
instanceof
的说明:前面都是表达式计算和取值,关键是第7步,
x instanceof Y
最后会调用内部方法:Y.HasInstance(x)
。下面来看看这个方法。省掉那些检查代码,概括起来,
Y.HasInstance(x)
会执行以下步骤:注意判断是递归的,直到
x
的原型链到达顶端为止。结论:你的理解是对的。