http://www.cnblogs.com/jasonxuli/p/6769282.html

这是 2014-12-10 发在 iteye 上的文章

今天突然想起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:

  1. Let lref be the result of evaluating RelationalExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating ShiftExpression.
  4. Let rval be GetValue(rref).
  5. If Type(rval) is not Object, throw a TypeError exception.
  6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
  7. 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:

  1. If V is not an object, return false.
  2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
  3. If Type(O) is not Object, throw a TypeError exception.
  4. Repeat
    1. Let V be the value of the [[Prototype]] internal property of V.
    2. If V is null, return false.
    3. 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的 instanceof 方法的更多相关文章

  1. js判断类型方法

    在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined, Null,Boolean, Number和String:复杂数据类型是Object,Object中 ...

  2. 各种实现js继承的方法总结

    昨天主要介绍了原型,在js中,原型,原型链和继承是三个很重要的概念,而这几个概念也是面试中经常会被问到的问题,今天,就把昨天还没总结的原型链和继承继续做一个整理,希望大家一起学习,一起进步呀O(∩_∩ ...

  3. 原生JS实现new方法、new一个对象发生的四部、new里面常用的优先级

    一.js中new一个对象的过程 首先了解new做了什么,使用new关键字调用函数(new ClassA(…))的具体步骤: 1.创建一个新对象: var obj = {}; 2.设置新对象的const ...

  4. TODO:Node.js pm2使用方法

    TODO:Node.js pm2使用方法 pm2 是一个带有负载均衡功能的Node应用的进程管理器. 当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, PM2是完 ...

  5. 【转载】JS中bind方法与函数柯里化

    原生bind方法 不同于jQuery中的bind方法只是简单的绑定事件函数,原生js中bind()方法略复杂,该方法上在ES5中被引入,大概就是IE9+等现代浏览器都支持了(有关ES5各项特性的支持情 ...

  6. 前端Js跨域方法汇总—剪不断,理还乱,是跨域

    1.通过jsonp跨域2.通过修改document.domain来跨子域(iframe)3.隐藏的iframe+window.name跨域4.iframe+跨文档消息传递(XDM)5.跨域资源共享 C ...

  7. 原生JS事件绑定方法以及jQuery绑定事件方法bind、live、on、delegate的区别

    一.原生JS事件绑定方法: 1.通过HTML属性进行事件处理函数的绑定如: <a href="#" onclick="f()"> 2.通过JavaS ...

  8. JS调用OC方法并传值,OC调用JS方法并传值////////////////////////zz

     iOS开发-基于原生JS与OC方法互相调用并传值(附HTML代码)     最近项目里面有有个商品活动界面,要与web端传值,将用户在网页点击的商品id 传给客户端,也就是js交互,其实再说明白一点 ...

  9. 原生JS中apply()方法的一个值得注意的用法

    今天在学习vue.js的render时,遇到需要重复构造多个同类型对象的问题,在这里发现原生JS中apply()方法的一个特殊的用法: var ary = Array.apply(null, { &q ...

随机推荐

  1. POJ1125-Stockbroker Grapevine Floyd算法多源最短路径

    这题的思路还是比较简单,用弗洛伊德算法打表后,枚举来找到最小值 代码如下 注意最后判断时候的语句 在这里错误了很多次 # include<iostream> # include<al ...

  2. 代码片段,Lucene的高亮显示

    代码高亮显示是通过在搜索到的Term中把匹配了用户输入的关键字的周围加上一些标记来实现(比如,关键字是 "中华" 查到的一个Term是 "中华人民共和国",则把 ...

  3. 三、微信小游戏开发 --- 小游戏API调用Platform

    微信小游戏API Platform主要是Egret用于来调用平台的SDK的. 在Egret中使用接口定义Platform. Egret项目中默认的platform值是DebugPlatform. 发布 ...

  4. 【BZOJ4195】[Noi2015]程序自动分析 并查集

    [BZOJ4195][Noi2015]程序自动分析 Description 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3 ...

  5. 微信小程序 --- action-sheet底部弹框

    action-sheet:从屏幕底部弹出一个菜单,选择: 使用的时候,在给不同的 action-sheet-item 添加不同的事件. 效果: (这里的确定可以有多个) 代码: <button ...

  6. 微信小程序 --- toast消息提示框

    toast:是用于进行提示用户的: 效果: 代码: <toast hidden="{{onOff}}" duration="1000" bindchang ...

  7. DCloud开发资源链接

    jQuery链接: <script src='http://libs.baidu.com/jquery/1.8.3/jquery.min.js'></script> HTML5 ...

  8. Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)

    A. k-rounding 题目意思:给两个数n和m,现在让你输出一个数ans,ans是n倍数且末尾要有m个0; 题目思路:我们知道一个数末尾0的个数和其质因数中2的数量和5的数量的最小值有关系,所以 ...

  9. Oracle等待事件之Enqueue(锁)

    1.产生原因 表示与内部队列机制相关的等待,例如对保护内部资源或者组件的锁的请求等,一种并发的保护机制,该等待意味着在访问同样的数据库资源时需要等待其他会话已经获取的锁. 2.确定产生问题的对象 死锁 ...

  10. nginx简介和配置gd

    转自:https://www.cnblogs.com/zhouxinfei/p/7862285.html nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也 ...