浅析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 相关文章推荐
JavaScript中继承的一些示例方法与属性参考
Aug 07 Javascript
关于firefox的ElementTraversal 接口 使用说明
Nov 11 Javascript
js+jquery实现图片裁剪功能
Jan 02 Javascript
JavaScript实现信用卡校验方法
Apr 07 Javascript
JavaScript操作XML文件之XML读取方法
Jun 09 Javascript
高性能JavaScript循环语句和条件语句
Jan 20 Javascript
AngularJS表单验证中级篇(3)
Sep 28 Javascript
Vue.js学习教程之列表渲染详解
May 17 Javascript
使用html+js+css 实现页面轮播图效果(实例讲解)
Sep 21 Javascript
浅析Vue中method与computed的区别
Mar 06 Javascript
layui的table单击行勾选checkbox功能方法
Aug 14 Javascript
element-ui中按需引入的实现
Dec 25 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
《斗罗大陆》六翼天使武魂最强,为什么老千家不是上三宗?
2020/03/02 国漫
PHP正确配置mysql(apache环境)
2011/08/28 PHP
php二维数组排序详解
2013/11/06 PHP
php判断邮箱地址是否存在的方法
2016/02/13 PHP
JS实现日期加减的方法
2013/11/29 Javascript
谷歌地图打不开的解决办法
2014/08/07 Javascript
javascript父、子页面交互技巧总结
2014/08/08 Javascript
javascript与Python快速排序实例对比
2015/08/10 Javascript
js实现兼容性好的微软官网导航下拉菜单效果
2015/09/07 Javascript
微信小程序 http请求详细介绍
2016/10/09 Javascript
javascript容错处理代码(屏蔽js错误)
2017/01/20 Javascript
BetterScroll 在移动端滚动场景的应用
2017/09/18 Javascript
vue单元格多列合并的实现
2020/11/26 Vue.js
以一段代码为实例快速入门Python2.7
2015/03/31 Python
Python中文竖排显示的方法
2015/07/28 Python
Python 基础教程之包和类的用法
2017/02/23 Python
Python实现将文本生成二维码的方法示例
2017/07/18 Python
Python实现打印螺旋矩阵功能的方法
2017/11/21 Python
python 接口返回的json字符串实例
2018/03/27 Python
python 遍历目录(包括子目录)下所有文件的实例
2018/07/11 Python
centos6.8安装python3.7无法import _ssl的解决方法
2018/09/17 Python
python try except 捕获所有异常的实例
2018/10/18 Python
用Python实现筛选文件脚本的方法
2018/10/27 Python
Python实现京东秒杀功能代码
2019/05/16 Python
python实现将文件夹内的每张图片批量分割成多张
2019/07/22 Python
python3中pip3安装出错,找不到SSL的解决方式
2019/12/12 Python
戴尔加拿大官网:Dell加拿大
2016/09/17 全球购物
建筑工程专业毕业生自荐信
2013/10/19 职场文书
文明餐桌活动方案
2014/02/11 职场文书
授权委托书怎么写
2014/04/03 职场文书
社保委托书怎么写
2014/08/02 职场文书
离婚代理词范文
2015/05/23 职场文书
大学生饮品店创业计划书范文
2019/07/10 职场文书
python爬虫--selenium模块
2021/03/31 Python
Python代码风格与编程习惯重要吗?
2021/06/03 Python
vue整合百度地图显示指定地点信息
2022/04/06 Vue.js