JavaScript原型继承的陷阱

JavaScript原型继承的陷阱

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 = true

console.log(child)
console.log(parent)

结果如下

即修改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,结果如下

可以看到,此时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)
时间: 2024-09-28 19:30:29

JavaScript原型继承的陷阱的相关文章

[JavaScript原型继承理解一]

转:http://www.cnblogs.com/harolei/p/3740354.html 对于JavaScript的继承和原型链,虽然之前自己看了书也听了session,但还是一直觉得云里雾里,不禁感叹JavaScript真是一门神奇的语言.这次经过Sponsor的一对一辅导和自己回来后反复思考,总算觉得把其中的精妙领悟一二了. 1. JavaScript创建对象 在面向对象语言中,通常通过定义类然后再进行实例化来创建多个具有相同属性和方法的对象.但是在JavaScript中并没有类的概念

彻底理解Javascript原型继承

彻底理解Javascript原型继承 之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入. 本文试图进一步思考,争取彻底理解Javascript继承原理 实例成员与原型成员 举一个<高性能Javascript>书中例子 var book={ title :"High Performance JavaScript", publisher:"Yahoo!Press" }; alert(book.toString());/

JavaScript 原型继承开端

1.原型继承本质       就javascript对象系统的实现来讲,对象并没有原型,而构造器有原型(构造器.prototype指向其原型).对象只有构造自某个原型的说法,并没有持有某个原型的说法.原型其实也是一个对象实例.原型的含义是指:如果构造器有一个原型对象A,则由该构造器创建的实例都必然复制自A. 2.空的对象是所有对象的基础 来看看以下代码: 1 <html> 2 <head> 3 <meta http-equiv="content-type"

Javascript原型继承容易忽略的错误

编写Javascript的开发者都知道,JS虽然没有类(ES6添加了class语法),但是可以模拟出OOP语言的类和面向对象的概念,比如我们都知道的一句话,Javascript中处处是对象,而面向对象语言的特性是继承,封装,多态,抽象,而本文讨论的是Javascript的继承,Javascript的继承方式有原型继承,组合继承,寄生继承等等,在日常开发中,哪种继承方式更好用在于开发者对于程序的结果以及性能的考虑.笔者在下面列举出原型继承中经常容易被忽略的错误. 常见错误一: function F

javascript原型继承圣杯模式

javascript纯面向对象开发需要使用到的一个模式,来对对象之间原型继承做中间层代理避免重复继承与代码杂乱 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"

javascript --- 原型继承与属性拷贝的综合应用

对于继承来说,主要目标就是将一些现有的功能据为己有.也就是说,我们在新建一个对象的时候,通常首先继承现有对象,然后再为其添加额外的属性和方法. 对此,我们可以通过一个函数调用来完成. 具体而言就是: 1. 使用原型继承的方式,将一个已有对象设置成新对象的原型. 2. 新建一个对象后,将另一个已有对象的属性拷贝过来. function objectPlus(o, stuff){ var n; function F(){}; F.prototype = o.prototype; n = new F(

javascript原型继承

用一张图来表示新的原型链: 封装一个inherits()函数,函数F用于桥接 function inherits(Child, Parent) { var F = function () {}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; } 这样inherits()函数就可以重复使用了 function Student(props) { this.

【转载】Javascript原型继承-学习笔记

阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html 笔记如下: 一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(p

Javascript 原型继承(续)—从函数到构造器的角色转换

对于每一个声明的函数,里边都会带有一个prototype成员,prototype会指向一个对象,现在我们来聚焦prototype指向的这个对象,首先我们会认为,这个对象是一个该函数对应的一个实例对象,因为我们在new一个对象的时候,通常都会继承该原型prototype对象的属性和方法.比如: 1 <html> 2 <head> 3 <meta http-equiv="content-type" charset="utf-8"/>