`
zhouyrt
  • 浏览: 1161982 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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} classImp
 */
function $class(className, superCls, classImp) {
    var p, supr
    if(superCls === '') superCls = Object
    function clazz() {
        if(typeof this.init == "function") {
            this.init.apply(this, arguments)
        }
    }
    p = clazz.prototype = new superCls()
    clazz.prototype.constructor = clazz
    clazz.prototype.className = className
    supr = superCls.prototype
    window[className] = clazz
    classImp.apply(p, [supr])
}

 

对象类型放在父类原型上时务必小心子类修改其,这时继承于该父类的所有子类的实例都将被修改。而这造出的bug很不容易发现。

 

ES5中加入了一个新API用来实现原型继承:Object.create。可以用它替代上面自实现的create函数,如下

var parent = {
    name: 'jack',
    age: 30,
    isMarried: false
}
var child = Object.create(parent)
console.log(child)

 

 

 

  • 大小: 24.1 KB
  • 大小: 42 KB
分享到:
评论

相关推荐

    探索JavaScript的原型链:原型继承的奥秘

    原型继承的陷阱** - **属性覆盖**:如果一个对象直接修改了原型上的属性,会影响到原型链上的所有对象。 - **原型链深度**:过长的原型链可能导致性能问题,并使代码难以维护。 #### 三、ES6 中的类与继承 尽管...

    浅析JavaScript原型继承的陷阱

    总之,理解JavaScript原型继承的陷阱对于编写可维护和高效的代码至关重要。在设计对象模型时,应谨慎处理引用类型的属性,以防止不必要的共享状态,同时利用原型链来优化方法的继承。通过正确地划分数据属性和方法,...

    JavaScript面向对象继承详解

    总的来说,JavaScript的面向对象继承机制灵活而强大,但同时也有一些复杂性和陷阱。理解和熟练掌握这些概念对于成为JavaScript的高级开发者至关重要。在学习过程中,通过实际编写代码,创建各种继承模式,以及研究...

    JavaScript 继承详解(三)

    在JavaScript中实现继承有多种方法,其中构造函数和原型链的方式是较为传统的一种,但在实际应用中存在一些问题和陷阱。本章节将深入分析这些常见的问题,并提出相应的解决方案。 首先,我们回顾一下使用构造函数和...

    浅谈JavaScript对象与继承_.docx

    总的来说,JavaScript的对象和继承机制是其灵活性和强大性的体现,但同时也因为其独特的设计导致了一些误解和陷阱。理解这些概念对于深入学习和使用JavaScript至关重要。在实际开发中,开发者应根据需求选择合适的...

    javascript权威指南 epub书及源码

    原型和原型链是JavaScript中实现继承的关键机制。通过原型链,一个对象可以继承另一个对象的属性和方法。书中将详细介绍如何利用`__proto__`和`Object.create()`来操作原型,以及如何使用`prototype`属性创建类似于...

    JavaScript经典进阶系列-Effective JavaScript英文原版

    2. **对象与原型**:JavaScript的原型继承机制是其独特之处。了解如何创建和使用原型链,以及如何有效地利用`__proto__`和`Object.create()`,可以更好地实现面向对象编程。 3. **函数与闭包**:闭包是JavaScript中...

    JavaScript the good parts

    JavaScript的继承机制基于原型链,这与传统的类继承有所不同。掌握如何使用`__proto__`、`Object.create()`和`prototype`属性实现继承是进阶学习的关键。 4. **对象** JavaScript的对象是键值对的集合,可以使用...

    Effective JavaScript 编写高质量JavaScript代码的68个有效方法1

    第四章主要讨论原型和对象,这是理解JavaScript继承机制的关键。通过解释原型链和构造函数,作者展示了如何利用这些特性来实现面向对象编程。他还提到了一些最佳实践,如使用Object.create()来创建新对象,以及避免...

    JavaScript 秘密花园.pdf

    JavaScript的原型链机制允许对象通过原型链继承其他对象的属性和方法。每个对象都有一个指向其原型对象的内部链接。当试图访问一个对象的属性时,如果该属性不存在于当前对象,JavaScript引擎会沿着原型链向上查找,...

    JavaScript语言精粹(修订版)

    此外,JavaScript的对象和原型机制是其独特之处,理解原型链、构造函数以及继承方式(如原型继承、组合继承、寄生组合继承、ES6的类继承)对于深入JavaScript至关重要。书中的修订版可能会涵盖最新的ES6及其后续版本...

    Secrets of the JavaScript Ninja, 2nd Edition chapter 7 sample

    《JavaScript忍者秘籍》第二版第7章样本的内容主要围绕JavaScript的对象导向编程和原型继承进行了深入探讨。在现代JavaScript开发中,理解这些概念对于编写高效、可维护的代码至关重要。 首先,文档提到了...

    javaScript秘密花园

    尽管实现类继承模型在JavaScript上相对容易,但要在JavaScript中实现原型继承则复杂得多。 在JavaScript中,对象是数据类型,并且可以作为哈希表使用,保存命名的键与值的对应关系。对象可以通过对象字面量(使用{}...

    JavaScript学习书籍PDF格式

    另外,JavaScript的原型继承和类概念,以及模块系统(CommonJS、ES6模块)也是理解和编写可维护代码的重要知识。 JavaScript还有一套强大的DOM(Document Object Model)操作API,允许开发者通过JavaScript动态地...

    JavaScript语言精粹pdf

    3. **原型与继承**:JavaScript的面向对象特性体现在其独特的原型链机制,通过理解原型和原型链,可以掌握对象的继承与扩展。 4. **DOM操作**:JavaScript与HTML的交互主要通过DOM(文档对象模型),学习如何选择...

    Object-oriented-javascript

    鉴于面向对象编程在JavaScript中的实现与传统语言如Java或C++有所不同,书中可能还会介绍JavaScript特有的OOP特性,如原型继承、对象字面量、工厂模式以及后来的ES6新增的类语法等。 由于内容片段包含了版权声明和...

    JavaScript语言精粹(JavaScript.The.Good.Parts)

    书中讲解了原型继承、构造函数、原型链以及更现代的类和模块系统。此外,还讨论了JSON(JavaScript Object Notation)在数据交换中的应用。 4. **错误处理**:JavaScript中的异常处理是程序健壮性的重要组成部分。...

    JavaScript.The.Good.Parts

    3. **原型和继承**:JavaScript使用原型链实现对象的继承。每个对象都有一个原型,可以通过`__proto__`或`Object.getPrototypeOf`访问。通过原型,对象可以共享属性和方法,实现代码复用。 4. **函数和函数表达式**...

Global site tag (gtag.js) - Google Analytics