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宝典学习笔记(下)
Jan 10 Javascript
javascript之可拖动的iframe效果代码
Aug 01 Javascript
js 代码集(学习js的朋友可以看下)
Jul 22 Javascript
jQuery EasyUI API 中文文档 - Documentation 文档
Sep 29 Javascript
DOM2非标准但却支持很好的几个属性小结
Jan 21 Javascript
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
Apr 15 Javascript
深入剖析JavaScript面向对象编程
Jul 12 Javascript
js 判断各种数据类型的简单方法(推荐)
Aug 29 Javascript
纯js实现悬浮按钮组件
Dec 17 Javascript
jquery实现图片上传前本地预览
Apr 28 jQuery
vue.js根据代码运行环境选择baseurl的方法
Feb 28 Javascript
JavaScript组合模式---引入案例分析
May 23 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之第五天
2006/10/09 PHP
PHP字符串处理的10个简单方法
2010/06/30 PHP
解析百度搜索结果link?url=参数分析 (全)
2012/10/09 PHP
PHP实现多文件上传的方法
2015/07/08 PHP
PHP实现的线索二叉树及二叉树遍历方法详解
2016/04/25 PHP
PHP Filter过滤器全面解析
2016/08/09 PHP
PHP下 Mongodb 连接远程数据库的实例代码
2017/08/30 PHP
laravel5.2表单验证,并显示错误信息的实例
2019/09/29 PHP
javaScript 读取和设置文档元素的样式属性
2009/04/14 Javascript
网页打开自动最大化的js代码
2012/08/22 Javascript
jquery分割字符串的方法
2015/06/24 Javascript
JS实现的仿淘宝交易倒计时效果
2015/11/27 Javascript
jQuery实现图片预加载效果
2015/11/27 Javascript
Node.js实现JS文件合并小工具
2016/02/02 Javascript
jQuery实现表格行和列的动态添加与删除方法【测试可用】
2016/08/01 Javascript
使用base64对图片的二进制进行编码并用ajax进行显示
2017/01/03 Javascript
jquery validation验证表单插件
2017/01/07 Javascript
用js将long型数据转换成date型或datetime型的实例
2017/07/03 Javascript
JS数组去重常用方法实例小结【4种方法】
2018/05/28 Javascript
最适应的vue.js的form提交涉及多种插件【推荐】
2018/08/27 Javascript
vue-cli3+typescript新建一个项目的思路分析
2019/08/06 Javascript
python常用知识梳理(必看篇)
2017/03/23 Python
Python爬虫基础之XPath语法与lxml库的用法详解
2018/09/13 Python
python3 线性回归验证方法
2019/07/09 Python
numpy ndarray 取出满足特定条件的某些行实例
2019/12/05 Python
Python 多进程、多线程效率对比
2020/11/19 Python
瑞典廉价机票预订网站:Seat24
2018/06/19 全球购物
在网络中有两台主机A和B,并通过路由器和其他交换设备连接起来,已经确认物理连接正确无误,怎么来测试这两台机器是否连通?如果不通,怎么来判断故障点?怎么排
2014/01/13 面试题
自我鉴定的范文
2013/10/03 职场文书
秋季婚礼证婚词
2014/01/11 职场文书
数控个人求职信范文
2014/02/03 职场文书
暑期培训随笔感言
2014/03/10 职场文书
党性锻炼的心得体会
2014/09/03 职场文书
领导班子四风对照检查材料范文
2014/09/27 职场文书
党员干部三严三实心得体会
2014/10/13 职场文书
python实现简易名片管理系统
2021/04/11 Python