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 相关文章推荐
基于jQuery的公告无限循环滚动实现代码
May 11 Javascript
jQuery之排序组件的深入解析
Jun 19 Javascript
getAsDataURL在Firefox7.0下无法预览本地图片的解决方法
Nov 15 Javascript
深入浅析JavaScript字符串操作方法 slice、substr、substring及其IE兼容性
Dec 16 Javascript
js多功能分页组件layPage使用方法详解
May 19 Javascript
js实现统计字符串中特定字符出现个数的方法
Aug 02 Javascript
Vue.js 和 MVVM 的注意事项
Nov 07 Javascript
jQuery实现select模糊查询(反射机制)
Jan 14 Javascript
JavaScript原生数组Array常用方法
Apr 06 Javascript
Vue之Watcher源码解析(1)
Jul 19 Javascript
layui写后台表格思路和赋值用法详解
Nov 14 Javascript
vue 中url 链接左边的小图标更改问题
Dec 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
apache+php完美解决301重定向的两种方法
2011/06/08 PHP
php实现的操作excel类详解
2016/01/15 PHP
php实现HTML实体编号与非ASCII字符串相互转换类实例
2016/11/02 PHP
jquery的颜色选择插件实例代码
2008/10/02 Javascript
javascript实用小函数使用介绍
2013/11/11 Javascript
js判断undefined类型,undefined,null, 的区别详细解析
2013/12/16 Javascript
js 判断浏览器使用的语言示例代码
2014/03/22 Javascript
js 获取元素下面所有li的两种方法
2014/04/14 Javascript
jquery 表格排序、实时搜索表格内容(附图)
2014/05/19 Javascript
jQuery中prependTo()方法用法实例
2015/01/08 Javascript
基于Vue2的移动端开发环境搭建详解
2016/11/03 Javascript
浅谈Angular4实现热加载开发旅程
2017/09/08 Javascript
vue 扩展现有组件的操作
2020/08/14 Javascript
vue编写简单的购物车功能
2021/01/08 Vue.js
使用pdb模块调试Python程序实例
2015/06/02 Python
Python 判断 有向图 是否有环的实例讲解
2018/02/01 Python
Python中单例模式总结
2018/02/20 Python
浅谈Python里面小数点精度的控制
2018/07/16 Python
在Python中给Nan值更改为0的方法
2018/10/30 Python
Python之循环结构
2019/01/15 Python
python的pytest框架之命令行参数详解(下)
2019/06/27 Python
PyCharm2020.1.2社区版安装,配置及使用教程详解(Windows)
2020/08/07 Python
如何基于matlab相机标定导出xml文件
2020/11/02 Python
python实现简单猜单词游戏
2020/12/24 Python
详解CSS3 Media Queries中媒体属性的使用
2016/02/29 HTML / CSS
J.Crew官网:美国知名休闲服装品牌
2017/05/19 全球购物
Mio Skincare英国官网:身体紧致及孕期身体护理
2018/08/19 全球购物
雅诗兰黛澳大利亚官网:Estée Lauder澳大利亚
2019/05/31 全球购物
办公室保洁员岗位职责
2013/12/02 职场文书
公司营业员的自我评价
2014/03/04 职场文书
人力资源主管职责范本
2014/03/05 职场文书
《数星星的孩子》教学反思
2014/04/11 职场文书
农村党员对照检查材料
2014/09/24 职场文书
护士个人总结范文
2015/02/13 职场文书
2016元旦晚会主持词开场白和结束语
2015/12/04 职场文书
远程教育集中轮训基层干部培训班学习心得体会
2016/01/09 职场文书