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. Bootstrap篇:弹出框和提示框效果以及代码展示

     前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编辑功能,一般常见的主要有两种处理方式:行内编辑和弹出框编辑.在增加用户体验方面,弹出框和提示框起着重要的作用,如果你 ...

  2. Go基础---->go的基础学习(五)

    这里是go中关于io的一些知识.有时不是你装得天衣无缝,而是我愿意陪你演得完美无缺. go中关于io的使用 一.Reader中的Read方法 Read 用数据填充指定的字节 slice,并且返回填充的 ...

  3. struts2基础---->自定义拦截器

    这一章,我们开始struts2中拦截器的学习. 自定义拦截器

  4. 【Java nio】java nio笔记

    缓冲区操作:缓冲区,以及缓冲区如何工作,是所有I/O的基础.所谓“输入/输出”讲的无非就是把数据移出货移进缓冲区.进程执行I/O操作,归纳起来也就是向操作系统发出请求,让它要么把缓冲区里的数据排干,要 ...

  5. Gallery 里面怎么设置ImageView的OnClick事件

    Gallery g=this.findViewById(R.id.gallery); g.setOnItemClickListener(new OnItemClickListener(){ @Over ...

  6. oracle的分页查询,mabatis的sql配置

    <select id="getCardcaseByPage" resultType="Cardcase" > select * from ( sel ...

  7. PHP中文字数限制:中文字符串截取(mb_substr)

    一.中文截取:mb_substr() mb_substr( $str, $start, $length, $encoding ) $str,需要截断的字符串 $start,截断开始处,起始处为0 $l ...

  8. 容斥原理解决某个区间[1,n]闭区间与m互质数数量问题

    首先贴出代码(闭区间[1,n]范围内和m互质的数) 代码: int solve(II n,II m){ vector<II>p; ;i*i<=m;i++){ ){ p.push_ba ...

  9. idea 设置

    1.代码提示不区分大小写 2.自动导入 抽取成接口-push members up 你可能不知道的IDEA使用技巧

  10. DrawLayout使用侧滑抽屉

    布局:fg_left_drawer <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...