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 相关文章推荐
如何用ajax来创建一个XMLHttpRequest对象
Dec 10 Javascript
Javascript Web Slider 焦点图示例源码
Oct 10 Javascript
js修改input的type属性问题探讨
Oct 12 Javascript
Javascript中判断对象是否为空
Jun 10 Javascript
详解升级react-router 4 踩坑指南
Aug 14 Javascript
React Native react-navigation 导航使用详解
Dec 01 Javascript
对Vue2 自定义全局指令Vue.directive和指令的生命周期介绍
Aug 30 Javascript
vue弹窗组件的实现示例代码
Sep 10 Javascript
Vue 图片压缩并上传至服务器功能
Jan 15 Javascript
Vue路由管理器Vue-router的使用方法详解
Feb 05 Javascript
微信小程序实现下滑到底部自动翻页功能
Mar 07 Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
Nov 05 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木马webshell扫描器代码
2012/01/25 PHP
基于PHP CURL用法的深入分析
2013/06/09 PHP
PHP自带函数给数字或字符串自动补齐位数
2014/07/29 PHP
xml 封装与解析(javascript和C#中)
2009/07/26 Javascript
JS/FLASH实现复制代码到剪贴板(兼容所有浏览器)
2013/05/27 Javascript
JavaScript对象学习小结
2015/09/02 Javascript
js实现的彩色方块飞舞奇幻效果
2016/01/27 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
2016/03/18 Javascript
html、css和jquery相结合实现简单的进度条效果实例代码
2016/10/24 Javascript
jquery判断页面网址是否有效的两种方法
2016/12/11 Javascript
nodejs个人博客开发第二步 入口文件
2017/04/12 NodeJs
JS简单实现滑动加载数据的方法示例
2017/10/18 Javascript
Vue组件开发技巧总结
2018/03/04 Javascript
vue 父组件调用子组件方法及事件
2018/03/29 Javascript
微信小程序如何再次获取用户授权的方法
2019/05/10 Javascript
vue+element导航栏高亮显示的解决方式
2019/11/12 Javascript
跟老齐学Python之网站的结构
2014/10/24 Python
对于Python编程中一些重用与缩减的建议
2015/04/14 Python
对于Python的框架中一些会话程序的管理
2015/04/20 Python
详解Python中for循环的使用方法
2015/05/14 Python
Python实现批量下载图片的方法
2015/07/08 Python
Python的Django框架中设置日期和字段可选的方法
2015/07/17 Python
如何使用VSCode愉快的写Python于调试配置步骤
2018/04/06 Python
Python3利用Dlib19.7实现摄像头人脸识别的方法
2018/05/11 Python
浅谈django的render函数的参数问题
2018/10/16 Python
Python 实现子类获取父类的类成员方法
2019/01/11 Python
关于pandas的离散化,面元划分详解
2019/11/22 Python
BookOutlet加拿大:在网上书店购买廉价折扣图书和小说
2018/10/05 全球购物
《桃林那间小木屋》教学反思
2014/05/01 职场文书
申论倡议书范文
2014/05/13 职场文书
通信工程求职信
2014/07/16 职场文书
物业公司管理制度
2015/08/05 职场文书
详解JavaScript中的执行上下文及调用堆栈
2021/04/29 Javascript
Python基础之赋值,浅拷贝,深拷贝的区别
2021/04/30 Python
如何搭建 MySQL 高可用高性能集群
2021/06/21 MySQL
纯CSS打字动画的实现示例
2022/08/05 HTML / CSS