今天突然想起js的原型继承模型和相关的prototype,constructor,觉得有点模糊,就写了个例子:
var log = console.log; function A(){ this.value = 1; } var a = new A(); log('a.value = ', a.value); // a.value = 1 log('a instanceof A: ', a instanceof A); // a instanceof A: true function B(){ this.value = 2; } var b = new B(); A.prototype = b; var aa = new A(); log(aa.constructor == b.constructor); // true log('a.value = ', a.value); // a.value = 1 log('b.value = ', b.value); // b.value = 2 log('aa.value = ', aa.value); // aa.value = 1 log('a instanceof A: ', a instanceof A); // a instanceof A: false log('a instanceof B: ', a instanceof B); // a instanceof B: false
其他的都没问题,最后两行突然有点让我恍惚:
为什么在A继承了B之后,a就不是A的实例了呢?
于是就去查instanceof的文档,ECMA 262 5.1版:
11.8.6The instanceof operator
The production RelationalExpression : RelationalExpression instanceof
ShiftExpression is evaluated as follows:
- Let lref be the result of evaluating RelationalExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating ShiftExpression.
- Let rval be GetValue(rref).
- If Type(rval) is not Object, throw a TypeError exception.
- If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
- Return the result of calling the [[HasInstance]] internal method of rval with argument lval.
2, 4 条提到的GetValue又是一个坑,暂且不管,去看6, 7提到的内部方法[[HasInstance]]:
15.3.5.3[[HasInstance]] (V)
Assume F is a Function object.
When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:
- If V is not an object, return false.
- Let O be the result of calling the [[Get]] internal method of F with property name
"prototype"
. - If Type(O) is not Object, throw a TypeError exception.
-
Repeat
- Let V be the value of the [[Prototype]] internal property of V.
- If V is
null
, return false. - If O and V refer to the same object, return true.
这一条大概等同于下面的逻辑:
F为instanceof表达式的右值,也就是constructor;V是左值,也就是instance;
HasInstance(V){ if(typeof(V) != 'object') return false; var O = F.get('prototype'); // get 为内部方法 if(typeof(O) != Object) throw new TypeError(); while(1){ // 循环实例V的原型链 V = V.__proto__; // 获取实例V的内部属性prototype,可以用Object.getPrototypeOf(V)获取 if(V == null) // Object.prototype.__proto__ 为null,这也是最终的跳出语句 return false; if(O === V) return true; } } F.HasInstance(V);
查了文档,算是搞明白了:
比较时使用的是实例的内部属性__proto__和构造函数的prototype,而实例内部属性__proto__只在被初始化的时候被设置为构造函数的prototype,因此
A.prototype = b; // A 继承了 B
而a的内部的__proto__还是A{},也就是a记得自己的亲爹是A{},但是现在的A认B做父了,所以a不承认是A的直系了。
a instanceof A; // false
a instanceof B; // false
有点儿刻舟求剑的感觉不?!
相关推荐
JS中typeof与instanceof的区别
JS:typeof instanceof constructor prototype区别
ES5的instanceof手写实现
JavaScript 手动实现instanceof的方法 1. instanceof的用法 instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。 function Person() {} function Person2() {} const usr = ...
typeof用以获取一个变量的类型,typeof一般只能返回如下几个结果... 如果我们希望获取一个对象是否是数组,或判断某个变量是否是某个对象的实例则要选择使用instanceof。instanceof用于判断一个变量是否某个对象的实例
instanceof使用详细说明 最详细的 不看后悔的
NULL 博文链接:https://yueyemaitian.iteye.com/blog/858108
那么instanceof的这种行为到底是如何实现的呢,现在让我们揭开instanceof背后的迷雾。 instanceof原理 照惯例,我们先来看一段代码: 代码如下: function Cat(){} Cat.prototype = {} function Dog(){} Dog.prototype...
判断一个变量的类型尝尝会用 typeof 运算符而他毕竟有些缺陷,就是无论引用的是什么类型的对象,它都返回object,这时就要用到instanceof来检测某个对象是不是另一个对象的实例
使用方法:result = object instanceof class其中result是必选项。任意变量。object是必选项。任意对象表达式。class是必选项。任意已定义的对象类。 说明如果 object 是 class 的一个实例,则 instanceof 运算符...
instanceof 运算符简介 在 JavaScript 中,判断一个变量的类型尝尝会用 ...与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如: 清单 1. instanceof 示例 var oStringObject
理解Javascript理解instanceof实现原理
js代码-instanceof的实现
主要介绍了JavaScript中instanceof运算符的使用示例,instanceof的使用是JavaScript入门学习中的基础知识,需要的朋友可以参考下
instanceof:用来判断实例是否是属于某个对象,这个判断依据是什么呢? 首先,了解一下javascript中的原型继承的基础知识: javascript中的对象都有一个__proto__属性,这个是对象的隐式原型,指向该对象的父对象的...
js代码-实现一个 instanceof
JavaScript中的instanceof运算符可以用来判断对象类型,而更重要的是instanceof能够判断对象的继承关系,这里我们就来以实例讲解JavaScript中instanceof运算符的用法
pig instanceof Pig); // => true function FlyPig() {} FlyPig.prototype = new Pig(); var flyPig = new FlyPig(); alert(flyPig instanceof Pig); // => true 来看另一段代码: 代码如下: // 代码 2 ...