浅析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 Ajax功能时需要注意的一个问题(内存溢出)
May 30 Javascript
JS画线(实例代码)
Nov 20 Javascript
jquery选择器原理介绍($()使用方法)
Mar 25 Javascript
javascript判断是手机还是电脑访问网页的简单实例分享
Jun 03 Javascript
基于Bootstrap+jQuery.validate实现Form表单验证
Dec 16 Javascript
基于JavaScript实现简单的随机抽奖小程序
Jan 05 Javascript
聊一聊jQuery插件uploadify使用方法
Aug 24 Javascript
详解用webpack的CommonsChunkPlugin提取公共代码的3种方式
Nov 09 Javascript
详解vue渲染函数render的使用
Dec 12 Javascript
Vue中使用sass实现换肤功能
Sep 07 Javascript
用 js 写一个 js 解释器过程详解
Aug 02 Javascript
Vue路由之JWT身份认证的实现方法
Aug 26 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
用函数读出数据表内容放入二维数组
2006/10/09 PHP
php缓存技术详细总结
2013/08/07 PHP
使用CodeIgniter的类库做图片上传
2014/06/12 PHP
js jq 单击和双击区分示例介绍
2013/11/05 Javascript
jQery使网页在显示器上居中显示适用于任何分辨率
2014/06/09 Javascript
jQuery实现长按按钮触发事件的方法
2015/02/02 Javascript
详解AngularJS中的表达式使用
2015/06/16 Javascript
jQuery表单验证功能实例
2015/08/28 Javascript
你一定会收藏的Nodejs代码片段
2016/02/04 NodeJs
jQuery progressbar通过Ajax请求实现后台进度实时功能
2016/10/11 Javascript
javascript入门之window对象【新手必看】
2016/11/22 Javascript
jQuery查找dom的几种方法效率详解
2017/05/17 jQuery
es6新特性之 class 基本用法解析
2018/05/05 Javascript
深入理解NodeJS 多进程和集群
2018/10/17 NodeJs
Vue使用Clipboard.JS在h5页面中复制内容实例详解
2019/09/03 Javascript
Layui Form 自定义验证的实例代码
2019/09/14 Javascript
JavaScript实现轮播图效果代码实例
2019/09/28 Javascript
vue 通过 Prop 向子组件传递数据的实现方法
2020/10/30 Javascript
[04:44]显微镜下的DOTA2第二期——你所没有注意到的细节
2014/06/20 DOTA
[02:32]【DOTA2亚洲邀请赛】iceice,梦开始的地方
2017/03/13 DOTA
用ReactJS和Python的Flask框架编写留言板的代码示例
2015/12/19 Python
python实现生命游戏的示例代码(Game of Life)
2018/01/24 Python
Python和Java的语法对比分析语法简洁上python的确完美胜出
2019/05/10 Python
Opencv python 图片生成视频的方法示例
2020/11/18 Python
Python爬取酷狗MP3音频的步骤
2021/02/26 Python
思想汇报范文
2013/11/04 职场文书
写自荐信要注意什么
2013/12/26 职场文书
音乐教育感言
2014/03/05 职场文书
募捐倡议书怎么写
2014/05/14 职场文书
董事长助理工作职责范本
2014/07/01 职场文书
乡镇食品安全责任书
2014/07/28 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
活动费用申请报告
2015/05/15 职场文书
如何用python绘制雷达图
2021/04/24 Python
python利用while求100内的整数和方式
2021/11/07 Python
如何在Python中妥善使用进度条详解
2022/04/05 Python