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代码
Jul 01 Javascript
JavaScript 继承详解 第一篇
Aug 30 Javascript
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js
Aug 14 Javascript
js+html5实现的自由落体运动效果代码
Jan 28 Javascript
js无法获取到html标签的属性的解决方法
Jul 26 Javascript
12 款 JS 代码测试必备工具(翻译)
Dec 13 Javascript
微信小程序 自定义对话框实例详解
Jan 20 Javascript
JavaScript 中 apply 、call 的详解
Mar 21 Javascript
Angular事件之不同组件间传递数据的方法
Nov 15 Javascript
微信小程序实现左侧滑栏过程解析
Aug 26 Javascript
vue导航栏部分的动态渲染实例
Nov 01 Javascript
详解node和ES6的模块导出与导入
Feb 19 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+mysql)
2007/11/23 PHP
PHP使用feof()函数读文件的方法
2014/11/07 PHP
php过滤所有的空白字符(空格、全角空格、换行等)
2015/10/27 PHP
PHP基于phpqrcode类生成二维码的方法详解
2018/03/14 PHP
PHP使用PDO实现mysql防注入功能详解
2019/12/20 PHP
Prototype使用指南之dom.js
2007/01/10 Javascript
IE iframe的onload方法分析小结
2010/01/07 Javascript
json2.js的初步学习与了解
2011/10/06 Javascript
javascript 数字格式化输出的实现代码
2013/12/10 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
JavaScript面向对象程序设计教程
2016/03/29 Javascript
D3.js实现文本的换行详解
2016/10/14 Javascript
JS实现css hover操作的方法示例
2017/04/07 Javascript
socket.io与pm2(cluster)集群搭配的解决方案
2017/06/02 Javascript
JavaScript队列函数和异步执行详解
2017/06/19 Javascript
webpack教程之webpack.config.js配置文件
2017/07/05 Javascript
微信小程序使用Promise简化回调
2018/02/06 Javascript
webpack源码之loader机制详解
2018/04/06 Javascript
前端面试知识点目录一览
2019/04/15 Javascript
使用vue实现多规格选择实例(SKU)
2019/08/23 Javascript
python书籍信息爬虫实例
2018/03/19 Python
Python中@property的理解和使用示例
2019/06/11 Python
Django 限制访问频率的思路详解
2019/12/24 Python
Python namedtuple命名元组实现过程解析
2020/01/08 Python
解决pycharm中opencv-python导入cv2后无法自动补全的问题(不用作任何文件上的修改)
2020/03/05 Python
Python3标准库之threading进程中管理并发操作方法
2020/03/30 Python
python中可以声明变量类型吗
2020/06/18 Python
python 使用openpyxl读取excel数据
2021/02/18 Python
html5 canvas 实现光线沿不规则路径运动
2020/04/20 HTML / CSS
美国网上鞋城:Shoeline.com
2016/11/17 全球购物
职高毕业生自我鉴定
2013/10/21 职场文书
酒店管理毕业生自我鉴定
2014/03/02 职场文书
教师自查自纠工作情况报告
2014/10/29 职场文书
幼儿园教研工作总结2015
2015/05/12 职场文书
在职证明书模板
2015/06/15 职场文书
2015年中秋节主持词
2015/07/30 职场文书