浅析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 获得选中文本内容的方法
Feb 15 Javascript
批量实现面向对象的实例代码
Jul 01 Javascript
一个判断抢购时间是否到达的简单的js函数
Jun 23 Javascript
JavaScript动态修改网页元素内容的方法
Mar 21 Javascript
jQuery实现dialog设置focus焦点的方法
Jun 10 Javascript
JS实现的另类手风琴效果网页内容切换代码
Sep 08 Javascript
jquery+css实现动感的图片切换效果
Nov 25 Javascript
js处理包含中文的字符串实例
Oct 11 Javascript
浅谈jquery中ajax跨域提交的时候会有2次请求的问题
Nov 10 jQuery
Vue.JS项目中5个经典Vuex插件
Nov 28 Javascript
vue 2.0 购物车小球抛物线的示例代码
Feb 01 Javascript
vue awesome swiper异步加载数据出现的bug问题
Jul 03 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的declare控制符和ticks教程(附示例)
2014/03/21 PHP
简单谈谈php中ob_flush和flush的区别
2014/11/27 PHP
php获取访问者IP地址汇总
2015/04/24 PHP
PHP抽奖算法程序代码分享
2015/10/08 PHP
微信公众平台DEMO(PHP)
2016/05/04 PHP
PHP 访问数据库配置通用方法(json)
2018/05/20 PHP
静态图片的十一种滤镜效果--不支持Ie7及非IE浏览器。
2007/03/06 Javascript
JavaScript 事件记录使用说明
2009/10/20 Javascript
用Javascript同时提交多个Web表单的方法
2009/12/26 Javascript
用客户端js实现带省略号的分页
2013/04/27 Javascript
js算法中的排序、数组去重详细概述
2013/10/14 Javascript
jquery仿QQ登录账号选择下拉框效果
2016/03/22 Javascript
关于数据与后端进行交流匹配(点亮星星)
2016/08/03 Javascript
JavaScript条件判断_动力节点Java学院整理
2017/06/26 Javascript
nodejs Assert中equal(),strictEqual(),deepEqual(),strictDeepEqual()比较
2017/09/18 NodeJs
利用angular、react和vue实现相同的面试题组件
2018/02/19 Javascript
JavaScript forEach中return失效问题解决方案
2020/06/01 Javascript
[51:22]Fnatic vs IG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python实现根据指定端口探测服务器/模块部署的方法
2014/08/25 Python
用Python编写分析Python程序性能的工具的教程
2015/04/01 Python
python简单的函数定义和用法实例
2015/05/07 Python
Python爬取三国演义的实现方法
2016/09/12 Python
深入理解python中函数传递参数是值传递还是引用传递
2017/11/07 Python
Request的中断和ErrorHandler实例解析
2018/02/12 Python
python+POP3实现批量下载邮件附件
2018/06/19 Python
Python机器学习之scikit-learn库中KNN算法的封装与使用方法
2018/12/14 Python
使用TensorFlow实现二分类的方法示例
2019/02/05 Python
anaconda升级sklearn版本的实现方法
2021/02/22 Python
彻底解决pip下载pytorch慢的问题方法
2021/03/01 Python
乌克兰机票、铁路和巴士票、酒店搜索、保险:Tickets.ua
2020/01/11 全球购物
生物化工工艺专业应届生求职信
2013/10/08 职场文书
食堂个人先进事迹
2014/01/22 职场文书
社区母亲节活动记录
2014/03/06 职场文书
先进人物事迹材料
2014/12/29 职场文书
2015年护士工作总结范文
2015/03/31 职场文书
合同审查法律意见书
2015/06/04 职场文书