浅析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 instanceof 与typeof使用说明
Jan 11 Javascript
javascript学习笔记(二) js一些基本概念
Jun 18 Javascript
javascript里模拟sleep(两种实现方式)
Jan 25 Javascript
顶部缓冲下拉菜单导航特效的JS代码
Aug 27 Javascript
JavaScript函数内部属性和函数方法实例详解
Mar 17 Javascript
node.js从数据库获取数据
May 08 Javascript
js实现将json数组显示前台table中
Jan 10 Javascript
Angular2入门教程之模块和组件详解
May 28 Javascript
详谈javascript精度问题与调整
Jul 08 Javascript
微信小程序sessionid不一致问题解决
Aug 30 Javascript
vue实现扫码功能
Jan 17 Javascript
node.js使用express-fileupload中间件实现文件上传
Jul 16 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
PHP4实际应用经验篇(8)
2006/10/09 PHP
php MYSQL 数据备份类
2009/06/19 PHP
调整优化您的LAMP应用程序的5种简单方法
2011/06/26 PHP
php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法
2013/09/28 PHP
PHP数组函数知识汇总
2016/05/12 PHP
javascript中对对层的控制
2006/12/29 Javascript
Jquery阻止事件冒泡 event.stopPropagation
2011/12/11 Javascript
解析瀑布流布局:JS+绝对定位的实现
2013/05/08 Javascript
jQuery中even选择器的定义和用法
2014/12/23 Javascript
如何使用HTML5地理位置定位功能
2015/04/27 Javascript
在JavaScript中操作时间之getUTCDate()方法的使用
2015/06/10 Javascript
原生js实现数字字母混合验证码的简单实例
2015/12/10 Javascript
Vue.js动态组件解析
2016/09/09 Javascript
详解angular中如何监控dom渲染完毕
2017/01/03 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
nodejs个人博客开发第七步 后台登陆
2017/04/12 NodeJs
Node.js如何使用Diffie-Hellman密钥交换算法详解
2017/09/05 Javascript
cocos creator Touch事件应用(触控选择多个子节点的实例)
2017/09/10 Javascript
JavaScript实现封闭区域布尔运算的示例代码
2018/06/25 Javascript
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
2019/09/19 Javascript
小程序富文本提取图片可放大缩小
2020/05/26 Javascript
python实现ipsec开权限实例
2014/11/11 Python
Python 实现数据库(SQL)更新脚本的生成方法
2017/07/09 Python
Python程序员面试题 你必须提前准备!(答案及解析)
2018/01/23 Python
基于Django与ajax之间的json传输方法
2018/05/29 Python
python实现石头剪刀布小游戏
2021/01/20 Python
python实现桌面托盘气泡提示
2019/07/29 Python
新年福利来一波之Python轻松集齐五福(demo)
2020/01/20 Python
python实现将两个文件夹合并至另一个文件夹(制作数据集)
2020/04/03 Python
django 解决扩展自带User表遇到的问题
2020/05/14 Python
浅谈django不使用restframework自定义接口与使用的区别
2020/07/15 Python
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
企业投资意向书
2015/05/09 职场文书
2016猴年春节问候语
2015/11/11 职场文书
2019垃圾分类宣传口号汇总
2019/08/16 职场文书
vue实现列表拖拽排序的示例代码
2022/04/08 Vue.js