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 伪数组实现方法
Oct 11 Javascript
js FLASH幻灯片字符串中有连接符&的处理方法
Mar 01 Javascript
jquery的相对父元素和相对文档定位示例代码
Aug 02 Javascript
jquery的trigger和triggerHandler的区别示例介绍
Apr 20 Javascript
jQuery设置Easyui校验规则(推荐)
Nov 21 Javascript
详解JavaScript RegExp对象
Feb 04 Javascript
详谈Ajax请求中的async:false/true的作用(ajax 在外部调用问题)
Feb 10 Javascript
bootstrap的工具提示实例代码
May 17 Javascript
写给小白看的JavaScript异步
Nov 29 Javascript
vue 中swiper的使用教程
May 22 Javascript
vue单页缓存存在的问题及解决方案(小结)
Sep 25 Javascript
vue-router的两种模式的区别
May 30 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
javascript 小型动画组件与实现代码
2010/06/02 PHP
php获取根域名方法汇总
2014/10/28 PHP
php中preg_replace_callback函数简单用法示例
2016/07/21 PHP
thinkphp中的多表关联查询的实例详解
2017/10/12 PHP
Ubuntu上安装yaf扩展的方法
2018/01/29 PHP
PHP使用SMTP邮件服务器发送邮件示例
2018/08/28 PHP
php实现银联商务公众号+服务窗支付的示例代码
2019/10/12 PHP
jquery 模拟类搜索框自动完成搜索提示功能(改进)
2010/05/24 Javascript
基于jquery实现的上传图片及图片大小验证、图片预览效果代码
2011/04/12 Javascript
js模拟点击以提交表单为例兼容主流浏览器
2013/11/29 Javascript
jquery中子元素和后代元素的区别示例介绍
2014/04/02 Javascript
angularjs实现与服务器交互分享
2014/06/24 Javascript
jquery动态创建div与input的实例代码
2016/10/12 Javascript
JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
2017/06/19 Javascript
浅谈Vue.js应用的四种AJAX请求数据模式
2017/08/30 Javascript
vue-cli开发时,关于ajax跨域的解决方法(推荐)
2018/02/03 Javascript
vue脚手架及vue-router基本使用
2018/04/09 Javascript
JS简单生成由字母数字组合随机字符串示例
2018/05/25 Javascript
[01:13:51]TNC vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python开发简易版在线音乐播放器
2017/03/03 Python
Python中max函数用于二维列表的实例
2018/04/03 Python
对pandas通过索引提取dataframe的行方法详解
2019/02/01 Python
pyqt5 获取显示器的分辨率的方法
2019/06/18 Python
Python 实现PS滤镜中的径向模糊特效
2020/12/03 Python
matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域
2021/01/05 Python
SmartBuyGlasses台湾:名牌眼镜,名牌太阳眼镜及隐形眼镜
2017/01/04 全球购物
俄罗斯最大的隐形眼镜销售网站:Ochkov.Net
2021/02/07 全球购物
金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)-> (一千零一拾一元整)输出
2015/05/29 面试题
企划专员岗位职责
2013/12/09 职场文书
中层干部竞争上岗演讲稿
2014/01/13 职场文书
大学信息公开实施方案
2014/03/09 职场文书
职工代表大会主持词
2014/04/01 职场文书
大学活动总结模板
2014/07/10 职场文书
安徽导游词
2015/02/12 职场文书
销售经理助理岗位职责
2015/04/13 职场文书
前端与RabbitMQ实时消息推送未读消息小红点实现示例
2022/07/23 Java/Android