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 相关文章推荐
[原创]静态页面也可以实现预览 列表不同的显示方式
Oct 14 Javascript
纯js实现的论坛常用的运行代码的效果
Jul 15 Javascript
AngularJS中的模块详解
Jan 29 Javascript
使用JavaScript开发IE浏览器本地插件实例
Feb 18 Javascript
firefox浏览器用jquery.uploadify插件上传时报HTTP 302错误
Mar 01 Javascript
小心!AngularJS结合RequireJS做文件合并压缩的那些坑
Jan 09 Javascript
基于jQuery倒计时插件实现团购秒杀效果
May 13 Javascript
浅谈移动端之js touch事件 手势滑动事件
Nov 07 Javascript
JS实现汉字与Unicode码相互转换的方法详解
Apr 28 Javascript
layer弹出层扩展主题的方法
Sep 11 Javascript
微信公众号网页分享功能开发的示例代码
May 27 Javascript
JavaScript实现网页跨年倒计时
Dec 02 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
使用phpexcel类实现excel导入mysql数据库功能(实例代码)
2016/05/12 PHP
使用自定义setTimeout和setInterval使之可以传递参数和对象参数
2009/04/24 Javascript
多个datatable共存造成多个表格的checkbox都被选中
2013/07/11 Javascript
javascript右下角弹层及自动隐藏(自己编写)
2013/11/20 Javascript
jQuery制作的别致导航有阴影背景高亮模式窗口
2014/04/15 Javascript
jquery实现类似淘宝星星评分功能有截图
2014/09/15 Javascript
JavaScript必知必会(二) null 和undefined
2016/06/08 Javascript
js判断radiobuttonlist的选中值显示/隐藏其它模块的实现方法
2016/08/25 Javascript
jquery 手势密码插件
2017/03/17 Javascript
nodejs使用http模块发送get与post请求的方法示例
2018/01/08 NodeJs
vue如何判断dom的class
2018/04/26 Javascript
Vue移动端用淘宝弹性布局lib-flexible插件做适配的方法
2020/05/26 Javascript
[04:23]DOTA2上海特锦赛小组赛第一日 TOP10精彩集锦
2016/02/27 DOTA
python3+mysql查询数据并通过邮件群发excel附件
2018/02/24 Python
Windows环境下python环境安装使用图文教程
2018/03/13 Python
Python requests发送post请求的一些疑点
2018/05/20 Python
Scrapy-Redis结合POST请求获取数据的方法示例
2019/05/07 Python
python hough变换检测直线的实现方法
2019/07/12 Python
django ModelForm修改显示缩略图 imagefield类型的实例
2019/07/28 Python
澳大利亚相机之家:Camera House
2017/11/30 全球购物
泰国演唱会订票网站:StubHub泰国
2018/02/26 全球购物
教师自我鉴定范文
2013/11/10 职场文书
药品质量检测应届生求职信
2013/11/14 职场文书
警示教育活动总结
2014/05/05 职场文书
团结就是力量演讲稿
2014/05/21 职场文书
幼儿园大班区域活动总结
2014/07/09 职场文书
物业消防安全责任书
2014/07/23 职场文书
教师优秀党员事迹材料
2014/08/14 职场文书
个人自我剖析材料
2014/09/30 职场文书
班子群众路线教育实践个人对照检查材料思想汇报
2014/09/30 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
投资入股合作协议书
2014/10/28 职场文书
会议室使用管理制度
2015/08/06 职场文书
《风筝》教学反思
2016/02/23 职场文书
警用民用对讲机找不同
2022/02/18 无线电
Python 避免字典和元组的多重嵌套问题
2022/07/15 Python