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 相关文章推荐
用js实现的模拟jquery的animate自定义动画(2.5K)
Jul 20 Javascript
使用jQuery同时控制四张图片的伸缩实现代码
Apr 19 Javascript
原生Js实现简易烟花爆炸效果的方法
Mar 20 Javascript
js实现兼容IE、Firefox的图片缩放代码
Dec 08 Javascript
js轮播图代码分享
Jul 14 Javascript
jQuery中fadein与fadeout方法用法示例
Sep 16 Javascript
JavaScript中Math对象的方法介绍
Jan 05 Javascript
JavaScript自定义文本框光标
Mar 05 Javascript
underscore之Collections_动力节点Java学院整理
Jul 10 Javascript
JavaScript生成指定范围的时间列表
Mar 19 Javascript
详解如何使用koa实现socket.io官网的例子
Nov 04 Javascript
js验证密码强度解析
Mar 18 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版小黄鸡simsimi聊天机器人接口分享
2014/01/26 PHP
ecshop实现smtp发送邮件
2015/02/03 PHP
javascript+php实现根据用户时区显示当地时间的方法
2015/03/11 PHP
PHP中的访问修饰符简单比较
2019/02/02 PHP
document对象execCommand的command参数介绍
2006/08/01 Javascript
jQuery学习7 操作JavaScript对象和集合的函数
2010/02/07 Javascript
基于jquery的返回顶部效果(兼容IE6)
2011/01/17 Javascript
纯js实现瀑布流展现照片(自动适应窗口大小)
2013/04/08 Javascript
js获取当前页面的url网址信息
2014/06/12 Javascript
jQuery Ajax中的事件详细介绍
2015/04/16 Javascript
JavaScript实现跨浏览器的添加及删除事件绑定函数实例
2015/08/04 Javascript
drag-and-drop实现图片浏览器预览
2015/08/06 Javascript
js匿名函数作为函数参数详解
2016/06/01 Javascript
微信小程序通过api接口将json数据展现到小程序示例
2017/01/20 Javascript
在Vue环境下利用worker运行interval计时器的步骤
2019/08/01 Javascript
解决layui动态加载复选框无法选中的问题
2019/09/20 Javascript
JS addEventListener()和attachEvent()方法实现注册事件
2021/01/11 Javascript
[01:04:09]DOTA2-DPC中国联赛 正赛 iG vs VG BO3 第二场 2月2日
2021/03/11 DOTA
Python安装使用命令行交互模块pexpect的基础教程
2016/05/12 Python
python实现顺序表的简单代码
2018/09/28 Python
python实现给scatter设置颜色渐变条colorbar的方法
2018/12/13 Python
代码详解django中数据库设置
2019/01/28 Python
使用python绘制二元函数图像的实例
2019/02/12 Python
浅谈python中get pass用法
2019/03/19 Python
新手入门Python编程的8个实用建议
2019/07/12 Python
Python3环境安装Scrapy爬虫框架过程及常见错误
2019/07/12 Python
python多线程同步之文件读写控制
2021/02/25 Python
css3翻牌翻数字的示例代码
2020/02/07 HTML / CSS
世界上最具创新性的增强型知名运动品牌:Proviz
2018/04/03 全球购物
欧洲当代手工玻璃和瓷器的领先品牌:LSA International
2018/06/03 全球购物
甲方资料员岗位职责
2013/12/13 职场文书
经销商培训邀请函
2014/01/21 职场文书
庆祝儿童节标语
2014/10/09 职场文书
课题研究阶段性总结
2015/08/13 职场文书
毕业设计工作总结
2015/08/14 职场文书
信息技术远程培训心得体会
2016/01/09 职场文书