浅析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 相关文章推荐
使用jquery中height()方法获取各种高度大全
Apr 02 Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
Jan 31 Javascript
jQuery实现鼠标点击弹出渐变层的方法
Jul 09 Javascript
一个字符串中出现次数最多的字符 统计这个次数【实现代码】
Apr 29 Javascript
基于Bootstrap重置输入框内容按钮插件
May 12 Javascript
JavaScript ES6的新特性使用新方法定义Class
Jun 28 Javascript
JS检测数组类型的方法小结
Mar 14 Javascript
教你如何编写Vue.js的单元测试的方法
Oct 17 Javascript
Vue项目页面跳转时浏览器窗口上方显示进度条功能
Mar 26 Javascript
vue实例的选项总结
Jun 09 Javascript
简单了解前端渐进式框架VUE
Jul 20 Javascript
Vue如何实现验证码输入交互
Dec 07 Vue.js
解析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
提高PHP编程效率 引入缓存机制提升性能
2010/02/15 PHP
Yii使用ajax验证显示错误messagebox的解决方法
2014/12/03 PHP
php文件上传你必须知道的几点
2015/10/20 PHP
window.dialogArguments 使用说明
2011/04/11 Javascript
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
javascript学习笔记(二) js一些基本概念
2012/06/18 Javascript
jQuery筛选数组之grep、each、inArray、map的用法及遍历json对象
2016/06/20 Javascript
浅谈js中test()函数在正则中的使用
2016/08/19 Javascript
js 作用域和变量详解
2017/02/16 Javascript
bootstrap table使用入门基本用法
2017/05/24 Javascript
iscroll动态加载数据完美解决方法
2017/07/18 Javascript
Vue.js仿微信聊天窗口展示组件功能
2017/08/11 Javascript
Vue中正确使用jQuery的方法
2017/10/30 jQuery
详解用webpack的CommonsChunkPlugin提取公共代码的3种方式
2017/11/09 Javascript
浅谈Vuejs中nextTick()异步更新队列源码解析
2017/12/31 Javascript
vue裁切预览组件功能的实现步骤
2018/05/04 Javascript
微信小程序实现留言功能
2018/10/31 Javascript
Elasticsearch实现复合查询高亮结果功能
2019/09/10 Javascript
你不可不知的Vue.js列表渲染详解
2019/10/01 Javascript
Element Carousel 走马灯的具体实现
2020/07/26 Javascript
[49:13]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第一局
2016/02/27 DOTA
Python实现抓取百度搜索结果页的网站标题信息
2015/01/22 Python
Python机器学习算法之k均值聚类(k-means)
2018/02/23 Python
Python中关键字global和nonlocal的区别详解
2018/09/03 Python
对python 多个分隔符split 的实例详解
2018/12/20 Python
Django 实现将图片转为Base64,然后使用json传输
2020/03/27 Python
Python基于execjs运行js过程解析
2020/11/27 Python
python 实现汉诺塔游戏
2020/11/28 Python
英国人最爱的饰品网站:Accessorize
2016/08/22 全球购物
美国嘻哈首饰购物网站:Hip Hop Bling
2016/12/30 全球购物
Europcar美国/加拿大:预订汽车或卡车租赁服务
2018/11/13 全球购物
大学生就业自荐信
2013/10/26 职场文书
xxx同志考察材料
2014/02/07 职场文书
计算机应用应届生求职信
2014/07/12 职场文书
群众路线个人对照检查材料
2014/09/23 职场文书
MySQL多表查询机制
2022/03/17 MySQL