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打印iframe内容示例代码
Aug 20 Javascript
JS中如何设置readOnly的值
Dec 25 Javascript
谈一谈javascript闭包
Jan 28 Javascript
JavaScript兼容性总结之获取非行间样式案例
Aug 07 Javascript
js CSS3实现卡牌旋转切换效果
Jul 04 Javascript
简单实现js鼠标跟随效果
Aug 02 Javascript
Javascript中 toFixed四舍六入方法
Aug 21 Javascript
使用DataTable插件实现异步加载数据
Nov 19 Javascript
vue实现tab切换外加样式切换方法
Mar 16 Javascript
关于AngularJS中几种Providers的区别总结
May 17 Javascript
JS定时器如何实现提交成功提示功能
Jun 12 Javascript
详解Vue的mixin策略
Nov 19 Vue.js
理解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/11/25 PHP
php快速查找数据库中恶意代码的方法
2015/04/01 PHP
WordPress中用于获取文章信息以及分类链接的函数用法
2015/12/18 PHP
php生成0~1随机小数的方法(必看)
2017/04/05 PHP
php实现基于pdo的事务处理方法示例
2017/07/21 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
PHP vsprintf()函数格式化字符串操作原理解析
2020/07/14 PHP
isArray()函数(JavaScript中对象类型判断的几种方法)
2009/11/26 Javascript
javascript cookies操作集合
2010/04/12 Javascript
深入探寻seajs的模块化与加载方式
2015/04/14 Javascript
javascript数组对象常用api函数小结(连接,插入,删除,反转,排序等)
2016/09/20 Javascript
JavaScript验证知识整理
2017/03/24 Javascript
react-native组件中NavigatorIOS和ListView结合使用的方法
2017/09/30 Javascript
解决Angular.js中使用Swiper插件不能滑动的问题
2018/02/26 Javascript
Vue表单demo v-model双向绑定问题
2018/06/29 Javascript
对vue中v-on绑定自定事件的实例讲解
2018/09/06 Javascript
Vuex的API文档说明详解
2020/02/05 Javascript
element中el-container容器与div布局区分详解
2020/05/13 Javascript
JS实现网站楼层导航效果代码实例
2020/06/16 Javascript
Python基于matplotlib实现绘制三维图形功能示例
2018/01/18 Python
python将一个英文语句以单词为单位逆序排放的方法
2018/12/20 Python
python+opencv实现霍夫变换检测直线
2020/10/23 Python
Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签
2019/12/04 Python
Python request使用方法及问题总结
2020/04/26 Python
伦敦剧院门票:London Theatre Direct
2018/11/21 全球购物
俄罗斯儿童和青少年服装、鞋子及配件的在线商店:Orby
2020/02/20 全球购物
Android笔试题总结
2014/11/29 面试题
助学感谢信范文
2015/01/21 职场文书
银行大堂经理培训心得体会
2016/01/09 职场文书
委托书范本格式
2019/04/18 职场文书
MySQL中连接查询和子查询的问题
2021/09/04 MySQL
vue项目中的支付功能实现(微信支付和支付宝支付)
2022/02/18 Vue.js
Lakehouse数据湖并发控制陷阱分析
2022/03/31 Oracle
Python中文分词库jieba(结巴分词)详细使用介绍
2022/04/07 Python
Java设计模式之代理模式
2022/04/22 Java/Android