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. cocos2dx游戏--欢欢英雄传说--添加触摸响应

    主要的调整就是将HelloWorldScene改成了MainSecne,然后将Player作为了MainScene的私有成员变量来处理.修改了人物图片,使用了网上找到的三国战纪的人物素材代替我之前画的 ...

  2. 重装Delphi10.2的IDE必要设置

    重装Delphi10.2的IDE必要设置: 1,Tools->Options Editor Options->Display 右侧的 Right margin: 设为200 这个设置是为右 ...

  3. Neutron SDN 手动实现手册

    安装架构介绍 本文旨在通过自己搭建类似neutron (openvswitch + gre) 实现SDN 的环境,学习了解其工作原理,模拟核心原理,比如:同一租户自定义网络 instance 互通,手 ...

  4. 简单的网络爬虫程序(Web Crawlers)

    程序比较简单,但是能体现基本原理. package com.wxisme.webcrawlers; import java.io.*; import java.net.*; /** * Web Cra ...

  5. tomcat配置JMX

    最近看JDK的命令行工具,使用Java VisualVM和Jconsole工具都可以监控java程序的运行情况(包括CUP和内存等的使用情况,线程的运行状态等) 在Java VisualVM 工具里可 ...

  6. 【BZOJ4099】Trapped in the Haybales Gold STL

    [BZOJ4099]Trapped in the Haybales Gold Description Farmer John has received a shipment of N large ha ...

  7. 【BZOJ2938】[Poi2000]病毒 AC自动机+DFS

    [BZOJ2938][Poi2000]病毒 Description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码 ...

  8. having使用的时机

    where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行. having 子句的作用是筛选满足条件的 ...

  9. 自定义Realm解析

    自定义Realm解析---------------------------------------> /* * Copyright 2005-2013 shopxx.net. All right ...

  10. Kafka Consumer接口

    对于kafka的consumer接口,提供两种版本,   high-level 一种high-level版本,比较简单不用关心offset, 会自动的读zookeeper中该Consumer grou ...