浅析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判断两个元素是否有重叠部分的代码
Jul 25 Javascript
javascript中setTimeout使用指南
Jul 26 Javascript
javascript学习总结之js使用技巧
Sep 02 Javascript
AngularJS入门教程之双向绑定详解
Aug 18 Javascript
ASP.NET jquery ajax传递参数的实例
Nov 02 Javascript
vue2.0移除或更改的一些东西(移除index key)
Aug 28 Javascript
微信小程序自定义toast实现方法详解【附demo源码下载】
Nov 28 Javascript
微信小程序 功能函数小结(手机号验证*、密码验证*、获取验证码*)
Dec 08 Javascript
Vue手把手教你撸一个 beforeEnter 钩子函数
Apr 24 Javascript
JS实现倒计时图文效果
Nov 17 Javascript
详解Webpack抽离第三方类库以及common解决方案
Mar 30 Javascript
Node.js 中判断一个文件是否存在
Aug 24 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语法(2)
2006/10/09 PHP
curl不使用文件存取cookie php使用curl获取cookie示例
2014/01/26 PHP
PHP goto语句简介和使用实例
2014/03/11 PHP
Zend Framework动作助手Redirector用法实例详解
2016/03/05 PHP
PHP PDO和消息队列的个人理解与应用实例分析
2019/11/25 PHP
javascript 带有滚动条的表格,标题固定,带排序功能.
2009/11/13 Javascript
JQuery优缺点分析说明
2010/06/09 Javascript
基于JQuery的浮动DIV显示提示信息并自动隐藏
2011/02/11 Javascript
javascript编码的几个方法详细介绍
2013/01/06 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
2013/05/08 Javascript
js过滤HTML标签以及空格的思路及代码
2013/05/24 Javascript
使用jquery动态加载js文件的方法
2014/12/24 Javascript
jQuery中[attribute]选择器用法实例
2014/12/31 Javascript
PHP结合jQuery实现红蓝投票功能特效
2015/07/22 Javascript
JavaScript中闭包的写法和作用详解
2016/06/29 Javascript
大型JavaScript应用程序架构设计模式
2016/06/29 Javascript
BootStrap学习系列之Bootstrap Typeahead 组件实现百度下拉效果(续)
2016/07/07 Javascript
Bootstrap模态框禁用空白处点击关闭
2016/10/20 Javascript
JS ES6多行字符串与连接字符串的表示方法
2017/04/26 Javascript
Textarea输入字数限制实例(兼容iOS&安卓)
2017/07/06 Javascript
详解从0开始搭建微信小程序(前后端)的全过程
2019/04/15 Javascript
IE浏览器下JS脚本提交表单后,不能自动提示问题解决方法
2019/06/04 Javascript
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
2013/11/27 Python
python中日志logging模块的性能及多进程详解
2017/07/18 Python
Python2实现的图片文本识别功能详解
2018/07/11 Python
python 提取key 为中文的json 串方法
2018/12/31 Python
python如何解析配置文件并应用到项目中
2019/06/27 Python
python实现根据文件格式分类
2019/10/31 Python
Python之指数与E记法的区别详解
2019/11/21 Python
Python基于类路径字符串获取静态属性
2020/03/12 Python
爱尔兰电子产品购物网站:Komplett.ie
2018/04/04 全球购物
如何判断一段程序是由C 编译程序还是由C++编译程序编译的
2013/08/04 面试题
运动会解说词100字
2014/01/31 职场文书
高中学生会竞选演讲稿
2014/08/25 职场文书
2019如何书写演讲稿?
2019/07/01 职场文书
比较node.js和Deno
2021/04/27 Javascript