javascript instanceof 内部机制探析


Posted in Javascript onOctober 15, 2010

比如:

// 代码 1 
function Pig() {} 
var pig = new Pig(); 
alert(pig instanceof Pig); // => true function FlyPig() {} 
FlyPig.prototype = new Pig(); 
var flyPig = new FlyPig(); 
alert(flyPig instanceof Pig); // => true

来看另一段代码:
// 代码 2 
function Pig() { Pig.prototype = {/* some code */} } 
var pig = new Pig(); 
alert(pig instanceof Pig); // => false

为何上面的猪 pig 不再是猪 Pig 了呢?
当一个对象是某个类的实例时,意味着这个对象具有该类的方法和属性。在 JavaScript 中,一个猪类的特性体现在原型中:
// 代码 3 
function Pig() {} 
Pig.prototype = { 
"吃猪食": function() {}, 
"睡觉": function() {}, 
"长膘": function() {} 
}; 
var pig = new Pig(); 
alert(pig instanceof Pig); //=> true

如果动态改变了猪的特性,让猪变成了牛:
// 代码 4 
Pig.prototype = { 
"吃草": function() {}, 
"犁田": function() {} 
}; 
var niu= new Pig(); 
alert(pig instanceof Pig); //=> false 
alert(niu instanceof Pig); //=> true

当未改变 Pig 的 prototype 时,猪还是猪,因此代码 3 中 pig 是 Pig 的实例。当改变 prototype 后,猪已经不是猪,而是披着猪皮的牛了。因此代码 4 中 pig 不再是 Pig 的实例,niu 反而是 Pig 的实例。

进一步分析前,先回顾一下 new 的内部机制。代码 2 中的 new Pig() 实际上等价为:

// var pig = new Pig() 的等价伪代码: 
var pig = (function() { 
var o = {}; 
o.__proto__ = Pig.prototype; // line 2 
Pig.call(o); 
Pig.prototype = {/* some code */}; // line 4 
return o; // line 5 
})();

可以看出,在 line 2 时,o.__proto__ 指向了 Pig.prototype 指向的值。但在 line 4 时,Pig.prototype 指向了新值。也就是说,在 line 5 返回时,pig.__proto__ !== Pig.prototype. 正是这个变化,导致了代码 2 中的 pig 不是 Pig.

已经可以大胆推论出:instanceof 判断 pig 是不是 Pig 的依据是:看隐藏的 pig.__proto__ 属性是否等于 Pig.prototype !

为了进一步确认,我们可以在 Firefox 下模拟 instanceof 的内部实现代码:

/** 
* Gecko 引擎下,模拟 instanceof 
*/ 
function _instanceof(obj, cls) { 
// instanceof 的左操作数必须是非null对象或函数对象 
if((typeof obj !== "object" || obj === null) 
&& typeof obj !== "function") { 
return false; 
} // instanceof 的右操作数必须是函数对象 
if(typeof cls !== "function") { 
throw new Error("invalid instanceof operand (" + cls + ")"); 
} 
// 向上回溯判断 
var p = obj.__proto__, cp = cls.prototype; 
while(p) { 
if(p === cp) return true; 
p = p.__proto__; 
} 
return false; 
}

测试页面:simulate-intanceof.html

最后考考大家:

function Bird() {} 
var bird = new Bird(); 
var o = {}; 
bird.__proto__ = o; 
Bird.prototype = o; 
alert(bird instanceof Bird); // true or false?
Javascript 相关文章推荐
写出更好的JavaScript之undefined篇(上)
Nov 22 Javascript
node.js使用require()函数加载模块
Nov 26 Javascript
javascript Slip.js实现整屏滑动的手机网页
Nov 25 Javascript
form表单转Json提交的方法(推荐)
Sep 23 Javascript
JavaScript中this的四个绑定规则总结
Sep 26 Javascript
easyui combobox开启搜索自动完成功能的实例代码
Nov 08 Javascript
javaScript+turn.js实现图书翻页效果实例代码
Feb 16 Javascript
微信小程序实战之仿android fragment可滑动底部导航栏(4)
Apr 16 Javascript
vue 实现移动端键盘搜索事件监听
Nov 06 Javascript
JavaScript中this的学习笔记及用法整理
Feb 17 Javascript
微信公众号中的JSSDK接入及invalid signature等常见错误问题分析(全面解析)
Apr 11 Javascript
微信小程序实现音乐播放页面布局
Dec 11 Javascript
理解Javascript_07_理解instanceof实现原理
Oct 15 #Javascript
JavaScript 对象模型 执行模型
Oct 15 #Javascript
理解Javascript_06_理解对象的创建过程
Oct 15 #Javascript
JavaScript聚焦于第一个字段的代码
Oct 15 #Javascript
JavaScript访问样式表代码
Oct 15 #Javascript
IE下js调试工具Companion.JS
Oct 15 #Javascript
jquery $.ajax各个事件执行顺序
Oct 15 #Javascript
You might like
PHP中for循环语句的几种变型
2007/03/16 PHP
thinkphp 一个页面使用2次分页的实现方法
2013/07/15 PHP
微信支付PHP SDK ―― 公众号支付代码详解
2016/09/13 PHP
PHP基于面向对象实现的留言本功能实例
2018/04/04 PHP
javascript 支持ie和firefox杰奇翻页函数
2008/07/22 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
2012/12/12 Javascript
让新消息在网页标题闪烁提示的jQuery代码
2013/11/04 Javascript
Javascript MVC框架Backbone.js详解
2014/09/18 Javascript
基于jquery实现表格内容筛选功能实例解析
2016/05/09 Javascript
使用three.js 画渐变的直线
2016/06/05 Javascript
node.js 中国天气预报 简单实现
2016/06/06 Javascript
js时间戳格式化成日期格式的多种方法介绍
2017/02/16 Javascript
angular 动态组件类型详解(四种组件类型)
2017/02/22 Javascript
深入研究jQuery图片懒加载 lazyload.js使用方法
2017/08/16 jQuery
Vue 多层组件嵌套二种实现方式(测试实例)
2017/09/08 Javascript
js实现二级菜单点击显示当前内容效果
2018/04/28 Javascript
js动态引入的四种方法
2018/05/05 Javascript
react koa rematch 如何打造一套服务端渲染架子
2019/06/26 Javascript
vue表单中遍历表单操作按钮的显示隐藏示例
2019/10/30 Javascript
vue父子组件的通信方法(实例详解)
2019/11/10 Javascript
jQuery实现日历效果
2020/09/11 jQuery
浅谈python 里面的单下划线与双下划线的区别
2017/12/01 Python
Python面向对象程序设计类的多态用法详解
2019/04/12 Python
浅谈python 中的 type(), dtype(), astype()的区别
2020/04/09 Python
使用python计算三角形的斜边例子
2020/04/15 Python
python缩进长度是否统一
2020/08/02 Python
Pytest单元测试框架如何实现参数化
2020/09/05 Python
德国狗狗用品在线商店:Schecker
2017/03/17 全球购物
Pop In A Box英国:Funko POP搪胶公仔
2019/05/27 全球购物
写出SQL四条最基本的数据操作语句(DML)
2012/12/12 面试题
经济信息管理专业大学生求职信
2013/09/27 职场文书
自我鉴定三原则
2014/01/13 职场文书
财务总监管理岗位职责
2014/03/08 职场文书
2014年教师节演讲稿范文
2014/09/10 职场文书
亲情作文之母爱
2019/09/25 职场文书
Nginx配置根据url参数重定向
2022/04/11 Servers