JavaScript constructor和instanceof,JSOO中的一对欢喜冤家


Posted in Javascript onMay 25, 2009

至少每个尝试JavaScriptOO的程序员都花费很多精力用在面向对象机制的模拟上而非业务本身.
这对Java,C++甚至Php的开发者来讲都是难以想象的.
更糟糕的是模拟OO对于JavaScript高级程序员都有着邪恶的吸引.
因为干这个事儿超然于业务之上,有种创造新编程语言一般的快感,可以令IQ尽情挥洒.
正如前些年大家都想把自个网站的common.js写成个框架一样.直到YUI,JQuery等等的强势推出才稍有平息.
然而虽然各个框架都有对JavaScriptOO模拟,但还未到有谁谁谁可以一桶糨糊的时候吧.
或许江湖就不需要的霸主出现,抑或大家只要等到JS2.0+就好了.
如果说可以new就是面向对象,那显然JavaScript在这方面是非常不错的.

function Person(name){ 
this.name = name; 
} 
var lenel = new person("lenel"); 
alert(lenel.constructor === Person); 
alert(lenel instanceof Person === true); 
alert(lenel instanceof Object === true);

到此为止,一切都很和谐.
对象的constructor正如字面上的意义指向构造它的Person.
对象是构造它的Person的一个实例(instance).
所有对象都是Object的实例,像极了Java.
JavaScript提供原型(prototype)的方式来实现方法拓展和继承
Person.prototype.getName = function(){ 
return this.name 
};

这样定义了之后所有对象都具有了getName的方法.
当然也可以将写在对象构造时
function Person(name){ 
this.name = name; 
this.getName = function(){ 
return this.name; 
}; 
}

但是这种做法不仅是带来额外性能损耗这点瑕疵,也不仅是带来了可以访问私有变量的特权.
它与使用prototype的写法还会其他有不同之处,不过这不是本文的重点.
接下来,我们想到继承,很常见的写法是这样的.
function Stuff(name,id){ 
this.name = name; 
this.id = id; 
} 
Stuff.prototype = new Person(); 
var piupiu = new Stuff("piupiu","007"); 
alert(piupiu.getName());

非常好,继承了getName方法;
考察下instanceof
alert(piupiu instanceof Stuff === true); 
alert(piupiu instanceof Person === true);

非常好,说明了Stuff和Person是有关系的.piupiu是它俩的实例,非常Java.
接下来再考察下constructor
alert(piupiu.constructor === Stuff);//false 
test(piupiu.constructor === Person);//true

问题出现了明明new的Stuff为啥constructor却是Person,
在这儿将道理也是强词夺理,我们只好记住结论
结论:对象的constructor属性并非指向其构造器,而是指向其构造器的prototype属性的constructor属性
文字功底太差,自己读过都觉得没说清楚
放在这里:
对象piupiu的constructor属性指向的是其构造器Stuff的prototype属性的constructor属性
因为Stuff.prototype = new Person();
所以Stuff.prototype.constructor === Person.
所以piupiu.consturctor === Person.
以上的结论不仅仅在对象继承的时候才出现,在定义对象时
function Student(name){ 
this.name = name; 
} 
Student.prototype = { 
getName:function(){ 
return this.name; 
}, 
setName:function(name){ 
this.name = name; 
} 
}

如果方法比较多,常常会这样写,看起来规矩一些.
其实这种写法同样牺牲了constructor
var moen = new Student("moen"); 
alert(moen.constructor === Student);//false 
alert(moen.constructor === Object);//true

因为在{}相当于new Object(),所以根据上面的结论prototype={}时,constructor变了.
保卫constructor!继承时我们用一个循环来把父类的方法copyto子类
function Stuff1(name,id){ 
this.name = name; 
this.id = id; 
} 
for(var fn in Person.prototype){ 
Stuff1.prototype[fn] = Person.prototype[fn]; 
} 
var piupiu1 = new Stuff1("piupiu1","008"); 
alert(piupiu1.getName() === "piupiu1"); 
alert(piupiu1.constructor === Stuff1);

It works!当我们兴冲冲的把父类的方法都继承下来的时候,我们却丢失了父子关系.
alert(piupiu1 instanceof Stuff1 === true);//true 
alert(piupiu1 instanceof Person === true);//false

显然,我们没有说过Stuff1是继承至Person啊,只一个for循环能说明什么呢.
这好像是一对矛盾..顾此必失彼.
所以叻,深入使用对象的时候,甚至你一不小心,都会让instantceof和constructor丢去字面的含义.
所以叻,在使用框架的时候,如果提供了继承功能,如果不试不会知道你为了继承放弃了哪个.
所以叻,模拟OO时就必须要提供替代这两个字面含义的属性或方法的实现,而且必须让使用者知道!
模拟OO绝对不只这个问题,在子类方法中调用父类的同名方法,这个OO语言常见的特性,
JavaScript实现起来也非常困难,大师们基本都有各自的一套,只不过有些用心去做了用起来相比之下更自然些,如Base库.
当然可以摒弃instanceof和constructor的使用,就当不知道有这么一回儿事儿,活儿仍可继续,死不了人的.
但如果你不是单枪匹马作战,那就通知你的Partner也摒弃这对冤家吧.
类似今天这点事儿,老鸟们都清楚的很,但如果不是团队中每个人都有统一的认识,那就是隐患.
一个好玩儿的现象<<JavaScript高级程序设计>>强调instanceof,而<<精通JavaScript>>强调constructor.而各自对另一个一笔带过或只字不提.怨念..甚深...
Javascript 相关文章推荐
cookie在javascript中的使用技巧以及隐私在服务器端的设置
Dec 03 Javascript
Jquery 获取对象的几种方式介绍
Jan 17 Javascript
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
Mar 08 Javascript
15款jQuery分布引导插件分享
Feb 04 Javascript
js实现点击向下展开的下拉菜单效果代码
Sep 01 Javascript
总结Javascript中的隐式类型转换
Aug 24 Javascript
JavaScript SHA-256加密算法详细代码
Oct 06 Javascript
Avalonjs 实现简单购物车功能(实例代码)
Feb 07 Javascript
基于Vue.js实现tab滑块效果
Jul 23 Javascript
JS中Attr的用法详解
Oct 09 Javascript
解决vue+ element ui 表单验证有值但验证失败问题
Jan 16 Javascript
Vue实现可移动水平时间轴
Jun 29 Javascript
jQuery 图像裁剪插件Jcrop的简单使用
May 22 #Javascript
document.compatMode介绍
May 21 #Javascript
各种常用浏览器getBoundingClientRect的解析
May 21 #Javascript
简单的js分页脚本
May 21 #Javascript
input+select(multiple) 实现下拉框输入值
May 21 #Javascript
一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
May 21 #Javascript
Javascript 兼容firefox的一些问题
May 21 #Javascript
You might like
雄兵连三大错觉:凯莎没了,凉冰阵亡了,华烨觉得自己又行了
2020/04/09 国漫
PHP 表单提交给自己
2008/07/24 PHP
PHP程序员基本要求和必备技能
2014/05/09 PHP
php获取textarea的值并处理回车换行的方法
2014/10/20 PHP
php+mysql实现用户注册登陆的方法
2015/01/03 PHP
php+mysqli使用面向对象方式更新数据库实例
2015/01/29 PHP
PHP实现在线阅读PDF文件的方法
2015/06/17 PHP
PHP给文字内容中的关键字进行套红处理
2016/04/12 PHP
JavaScript学习笔记之获取当前目录的实现代码
2010/12/14 Javascript
根据IP的地址,区分不同的地区,查看不同的网站页面的js代码
2013/02/26 Javascript
对Jquery中的ajax再封装,简化操作示例
2014/02/12 Javascript
JavaScript中获取高度和宽度函数总结
2014/10/08 Javascript
JavaScript字符串对象split方法入门实例(用于把字符串分割成数组)
2014/10/16 Javascript
jQuery模拟黑客帝国矩阵效果实例
2015/06/28 Javascript
JavaScript 函数用法详解【函数定义、参数、绑定、作用域、闭包等】
2020/05/12 Javascript
解决vue-photo-preview 异步图片放大失效的问题
2020/07/29 Javascript
Vue+Element-U实现分页显示效果
2020/11/15 Javascript
[01:43]3.19DOTA2发布会 三代刀塔人第三代
2014/03/25 DOTA
Python中使用item()方法遍历字典的例子
2014/08/26 Python
Python编程深度学习计算库之numpy
2018/12/28 Python
Python使用random模块生成随机数操作实例详解
2019/09/17 Python
Django框架教程之中间件MiddleWare浅析
2019/12/29 Python
Python 剪绳子的多种思路实现(动态规划和贪心)
2020/02/24 Python
Python 输出详细的异常信息(traceback)方式
2020/04/08 Python
OpenCV 表盘指针自动读数的示例代码
2020/04/10 Python
Scrapy 配置动态代理IP的实现
2020/09/28 Python
python 爬取小说并下载的示例
2020/12/07 Python
详解Python中的Lock和Rlock
2021/01/26 Python
Origins悦木之源香港官网:雅诗兰黛集团高端植物护肤品牌
2018/03/21 全球购物
意大利领先的奢侈品在线时装零售商:MCLABELS
2020/10/13 全球购物
维德科技C#面试题笔试题
2015/12/09 面试题
安全标语大全
2014/06/10 职场文书
毕业典礼邀请函
2015/01/31 职场文书
党务工作者主要事迹材料
2015/11/03 职场文书
spring boot项目application.properties文件存放及使用介绍
2021/06/30 Java/Android