浅析JavaScript原型继承的陷阱


Posted in Javascript onDecember 03, 2013

JavaScript默认采用原型继承。虽然没有类(class)的概念,它的函数(function)可以充当构造器(constructor)。构造器结合this,new可以构建出类似Java的类。因此,JavaScript通过扩展自身能模拟类式(class-based)继承。

JavaScript和其它面向对象语言一样,对象类型采用引用方式。持有对象的变量只是一个地址,而基本类型数据是值。当原型上存储对象时,就可能有一些陷阱。

先看第一个例子

var create = function() { 
    function Fn() {} 
    return function(parent) { 
        Fn.prototype = parent 
        return new Fn 
    } 
}() var parent = { 
    name: 'jack', 
    age: 30, 
    isMarried: false
} 
var child = create(parent) 
console.log(child)

create工具函数实现了一个基本的原型继承,每次调用create都会根据parent对象去复制一个新对象,新对象全部的属性都来自于parent。这里parent有三个属性,都是基本数据类型:字符串,数字,布尔。

这时修改child看看会不会影响parent

child.name = 'lily'
child.age = 20, 
child.isMarried = trueconsole.log(child) 
console.log(parent)

结果如下

浅析JavaScript原型继承的陷阱

即修改child不会影响到parent。

再看看另外一个例子

var create = function() { 
    function Fn() {} 
    return function(parent) { 
        Fn.prototype = parent 
        return new Fn 
    } 
}() var parent = { 
    data: { 
        name: 'jack', 
        age: 30, 
        isMarried: false
    }, 
    language: ['Java'] 
} 
var child = create(parent) 
child.data.name = 'lily'
child.data.age = 20 
child.data.isMarried = true
child.language.push('javascript') 
console.dir(child) 
console.dir(parent)

注意这里的parent的两个属性data,language都是引用类型,一个是对象,一个是数组。child仍然继承与parent,随后修改了child,结果如下

浅析JavaScript原型继承的陷阱

可以看到,此时parent也被修改了,和child的name,age等都一样了。这是使用原型继承时需要注意的。

使用继承时比较好的方式是:

1,数据属性采用类式继承(挂在this上),这样new时也可以通过参数配置

2,方法采用原型继承,这样能节省内存,同时子类重写方法也不会影响父类

下面是一个满足以上2点的写类工具函数

/** 
 * @param {String} className 
 * @param {String/Function} superCls 
 * @param {Function} factory 
 */
function $class(name, superClass, factory) { 
    if (superClass === '') superClass = Object 
    function clazz() { 
        if (typeof this.init === 'function') { 
            this.init.apply(this, arguments) 
        } 
    } 
    var p = clazz.prototype = new superCls 
    clazz.prototype.constructor = clazz 
    clazz.prototype.className = className 
    var supr = superCls.prototype 
    window[className] = clazz 
    factory.call(p, supr) 
}

对象类型放在父类原型上时务必小心子类修改其,这时继承于该父类的所有子类的实例都将被修改。而这造成的bug很不容易发现。

ES5中加入了一个新API用来实现原型继承:Object.create。可以用它替代上面自实现的create函数,如下

var parent = { 
    name: 'jack', 
    age: 30, 
    isMarried: false
} 
var child = Object.create(parent) 
console.log(child)
Javascript 相关文章推荐
JScript中的"this"关键字使用方式补充材料
Mar 08 Javascript
Javascript & DHTML 实例编程(教程)DOM基础和基本API
Jun 02 Javascript
JavaScript 核心参考教程 内置对象
Oct 13 Javascript
jQuery 绑定事件到动态创建的元素上的方法实例
Aug 18 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
Jul 27 Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 Javascript
微信小程序实现分享到朋友圈功能
Jul 19 Javascript
jQuery轻量级表单模型验证插件
Oct 15 jQuery
Express结合Webpack的全栈自动刷新
May 23 Javascript
layui多iframe页面控制定时器运行的方法
Sep 05 Javascript
iview form清除校验状态的实现
Sep 19 Javascript
vue实现学生信息管理系统
May 30 Javascript
解析JavaScript中instanceof对于不同的构造器或许都返回true
Dec 03 #Javascript
探讨JavaScript中声明全局变量三种方式的异同
Dec 03 #Javascript
解析JavaScript中delete操作符不能删除的对象
Dec 03 #Javascript
解析Javascript小括号“()”的多义性
Dec 03 #Javascript
解析Javascript中中括号“[]”的多义性
Dec 03 #Javascript
jquery将一个表单序列化为一个对象的方法
Dec 02 #Javascript
jQuery获得内容和属性方法及示例
Dec 02 #Javascript
You might like
世界上第一台立体声收音机
2021/03/01 无线电
实现树状结构的两种方法
2006/10/09 PHP
在WIN98下以apache模块方式安装php
2006/10/09 PHP
用PHP代替JS玩转DOM的思路及示例代码
2014/06/15 PHP
常见的四种POST 提交数据方式(小总结)
2015/10/08 PHP
WordPress中重置文章循环的rewind_posts()函数讲解
2016/01/11 PHP
PHP上传文件及图片到七牛的方法
2018/07/25 PHP
jQuery 一个图片切换的插件
2011/10/09 Javascript
IE与Firefox在JavaScript上的7个不同句法分享
2011/10/30 Javascript
JS实现仿中关村论坛评分后弹出提示效果的方法
2015/02/23 Javascript
js实现文本框宽度自适应文本宽度的方法
2015/08/13 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
2015/12/02 Javascript
jq给页面添加覆盖层遮罩的实例
2017/02/16 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
vue基于mint-ui的城市选择3级联动的示例
2017/10/25 Javascript
JavaScript中EventBus实现对象之间通信
2020/10/18 Javascript
vue+element_ui上传文件,并传递额外参数操作
2020/12/05 Vue.js
python生成器,可迭代对象,迭代器区别和联系
2018/02/04 Python
解决python多行注释引发缩进错误的问题
2019/08/23 Python
使用pandas 将DataFrame转化成dict
2019/12/10 Python
英国花园药房: The Garden Pharmacy
2017/12/28 全球购物
次世代生活态度:Hypebeast
2018/07/05 全球购物
使用Vue.js和MJML创建响应式电子邮件
2021/03/23 Vue.js
日语专业推荐信
2013/11/12 职场文书
人力资源管理毕业生自荐信
2013/11/21 职场文书
护士试用期自我鉴定
2014/02/08 职场文书
军训自我鉴定范文
2014/02/13 职场文书
元旦活动感言
2014/03/08 职场文书
詹天佑教学反思
2014/04/30 职场文书
国际政治学专业推荐信
2014/09/26 职场文书
表扬通报怎么写
2015/01/16 职场文书
红色经典电影观后感
2015/06/18 职场文书
2015年民兵整组工作总结
2015/07/24 职场文书
班干部竞选演讲稿(精选5篇)
2019/09/24 职场文书
Win10此设备不支持接收Miracast无法投影的解决方法
2022/07/07 数码科技
CSS实现鼠标悬浮动画特效
2023/05/07 HTML / CSS