浅析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 相关文章推荐
js 强制弹出窗口代码研究-又一款代码
Mar 20 Javascript
jQuery版Tab标签切换
Mar 16 Javascript
javascript动画对象支持加速、减速、缓入、缓出的实现代码
Sep 30 Javascript
获取元素距离浏览器周边的位置的方法getBoundingClientRect
Apr 17 Javascript
Firefox中通过JavaScript复制数据到剪贴板(Copy to Clipboard 跨浏览器版)
Nov 22 Javascript
js检测用户输入密码强度
Oct 22 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
Feb 16 Javascript
angularJs中json数据转换与本地存储的实例
Oct 08 Javascript
vue 输入电话号码自动按3-4-4分割功能的实现代码
Apr 30 Javascript
微信小程序实现分页加载效果
Nov 19 Javascript
超详细小程序定位地图模块全系列开发教学
Nov 24 Javascript
JS实现点击掉落特效
Jan 29 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与XML的PDF文档生成技术
2006/10/09 PHP
phpMyAdmin 安装教程全攻略
2007/03/19 PHP
javascript fullscreen全屏实现代码
2009/04/09 Javascript
js实现简单的联动菜单效果
2015/08/19 Javascript
javascript求日期差的方法
2016/03/02 Javascript
JavaScript中windows.open()、windows.close()方法详解
2016/07/28 Javascript
Angular 4依赖注入学习教程之组件服务注入(二)
2017/06/04 Javascript
js实现图片轮播效果学习笔记
2017/07/26 Javascript
vue.js数据绑定操作详解
2018/04/23 Javascript
浅谈在react中如何实现扫码枪输入
2018/07/04 Javascript
vue中v-for通过动态绑定class实现触发效果
2018/12/06 Javascript
小程序从手动埋点到自动埋点的实现方法
2019/01/24 Javascript
微信小程序实现点击卡片 翻转效果
2019/09/04 Javascript
Python过滤函数filter()使用自定义函数过滤序列实例
2014/08/26 Python
听歌识曲--用python实现一个音乐检索器的功能
2016/11/15 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
解决Python网页爬虫之中文乱码问题
2018/05/11 Python
Python+OpenCV实现图像融合的原理及代码
2018/12/03 Python
python 实现selenium断言和验证的方法
2019/02/13 Python
python 设置输出图像的像素大小方法
2019/07/04 Python
Python3并发写文件与Python对比
2019/11/20 Python
python speech模块的使用方法
2020/09/09 Python
python 实现socket服务端并发的四种方式
2020/12/14 Python
详解使用scrapy进行模拟登陆三种方式
2021/02/21 Python
处理HTML5新标签的浏览器兼容版问题
2017/03/13 HTML / CSS
英国优质鞋类专家:Robinson’s Shoes
2017/12/08 全球购物
工商管理专业实习大学生自我鉴定
2013/09/19 职场文书
六一节目主持词
2014/04/01 职场文书
课例研修方案
2014/05/31 职场文书
商业项目策划方案
2014/06/05 职场文书
电话客服专员岗位职责
2014/06/28 职场文书
出差报告怎么写
2014/11/06 职场文书
医务人员医德考评自我评价
2015/03/03 职场文书
婚庆司仪开场白
2015/05/29 职场文书
信仰观后感
2015/06/03 职场文书
七年级作文(600字3篇)
2019/09/24 职场文书