浅析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中的var_dump函数实现代码
Sep 07 Javascript
用Javascript实现锚点(Anchor)间平滑跳转
Sep 08 Javascript
js的写法基础分析
Jan 17 Javascript
不用锚点也可以平滑滚动到页面的指定位置实现代码
May 08 Javascript
js简单实现HTML标签Select联动带跳转
Oct 23 Javascript
原始XMLHttpRequest方法详情回顾
Nov 28 Javascript
JavaScript异步加载浅析
Dec 28 Javascript
jQuery使用before()和after()在元素前后添加内容的方法
Mar 26 Javascript
jQuery鼠标经过方形图片切换成圆边效果代码分享
Aug 20 Javascript
pc加载更多功能和移动端下拉刷新加载数据
Nov 07 Javascript
element-ui中Table表格省市区合并单元格的方法实现
Aug 07 Javascript
layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法
Sep 21 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
PHP伪造referer实例代码
2008/09/20 PHP
浅析PHP程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
PHP页面中文乱码分析
2013/10/29 PHP
php学习笔记之基础知识
2014/11/08 PHP
讲解WordPress开发中一些常用的debug技巧
2015/12/18 PHP
PHP中的session安全吗?
2016/01/22 PHP
支持ie与FireFox的剪切板操作代码
2009/09/28 Javascript
Asp.net下利用Jquery Ajax实现用户注册检测(验证用户名是否存)
2010/09/12 Javascript
用jQuery toggleClass 实现鼠标移上变色
2014/05/14 Javascript
js实现div闪烁原理及实现代码
2014/06/24 Javascript
javascript中innerText和innerHTML属性用法实例分析
2015/05/13 Javascript
举例简介AngularJS的内部语言环境
2015/06/17 Javascript
详解JavaScript编程中的数组结构
2015/10/24 Javascript
JavaScript代码实现左右上下自动晃动自动移动
2016/04/08 Javascript
Vue Transition实现类原生组件跳转过渡动画的示例
2017/08/19 Javascript
关于JavaScript的单双引号嵌套问题
2017/08/20 Javascript
vue 之 .sync 修饰符示例详解
2018/04/21 Javascript
vue如何安装使用Quill富文本编辑器
2018/09/21 Javascript
jquery无缝图片轮播组件封装
2020/11/25 jQuery
python实现simhash算法实例
2014/04/25 Python
Eclipse和PyDev搭建完美Python开发环境教程(Windows篇)
2016/11/16 Python
基于Django用户认证系统详解
2018/02/21 Python
Python实现爬虫设置代理IP和伪装成浏览器的方法分享
2018/05/07 Python
Python将一个CSV文件里的数据追加到另一个CSV文件的方法
2018/07/04 Python
Python中单线程、多线程和多进程的效率对比实验实例
2019/05/14 Python
python Tkinter的图片刷新实例
2019/06/14 Python
Tensorflow: 从checkpoint文件中读取tensor方式
2020/02/10 Python
windows下python 3.9 Numpy scipy和matlabplot的安装教程详解
2020/11/28 Python
Sperry官网:帆船鞋创始品牌
2016/09/07 全球购物
草莓网化妆品加拿大网站:Strawberrynet Canada
2016/09/20 全球购物
盖尔斯工厂店:GUESS Factory
2020/01/21 全球购物
大学生就业自荐信
2013/10/26 职场文书
教师旷工检讨书
2014/01/18 职场文书
篮球比赛策划方案
2014/06/05 职场文书
创业计划书之农家乐
2019/10/09 职场文书
详解Node.js如何处理ES6模块
2021/05/15 Javascript