【问题标题】:Extending an Object in Javascript在 Javascript 中扩展对象
【发布时间】:2012-05-12 21:40:31
【问题描述】:

我目前正在从Java 转换为Javascript,我有点难以弄清楚如何按照我想要的方式扩展对象。

我在互联网上看到有几个人使用了一种名为 extend on object 的方法。代码将如下所示:

var Person = {
   name : 'Blank',
   age  : 22
}

var Robot = Person.extend({
   name : 'Robo',
   age  : 4
)}

var robot = new Robot();
alert(robot.name); //Should return 'Robo'

有谁知道如何进行这项工作? 我听说你需要写

Object.prototype.extend = function(...);

但我不知道如何使这个系统工作。如果不可能,请告诉我另一个扩展对象的替代方法。

【问题讨论】:

  • 返回真;但这就是我问的原因:)
  • 我建议在 MDN 上阅读这个漂亮的教程:- developer.mozilla.org/en/…
  • 如果您在阅读了那些不错的文档后仍然对 extend 函数感到好奇,我在这里设置了一个示例:jsfiddle.net/k9LRd
  • 我还建议不要将其严格地视为“从 Java 转换为 JavaScript”,而应将其视为“学习一种与 Java 具有相似语法的新语言 Javascript”

标签: javascript function object prototype extends


【解决方案1】:

您想从 Person 的原型对象“继承”:

var Person = function (name) {
    this.name = name;
    this.type = 'human';
};

Person.prototype.info = function () {
    console.log("Name:", this.name, "Type:", this.type);
};

var Robot = function (name) {
    Person.apply(this, arguments);
    this.type = 'robot';
};

Robot.prototype = Person.prototype;  // Set prototype to Person's
Robot.prototype.constructor = Robot; // Set constructor back to Robot

person = new Person("Bob");
robot = new Robot("Boutros");

person.info();
// Name: Bob Type: human

robot.info();
// Name: Boutros Type: robot

【讨论】:

  • 我有一个问题:当您执行new Robot() 时,如何调用Person() 构造函数?在我看来,您应该调用该基类构造函数,而不是在 Robot() 构造函数中执行 this.name = name;...
  • @AlexisWilke:是的,你应该打电话给Person.apply(this, arguments);。最好使用Robot.prototype = Object.create(Person.prototype); 而不是new Person();
  • 正如菲利克斯所说,'Robot.prototype = Person.prototype;'如果有人希望“机器人”类型拥有自己的原型实例,那么这是一个坏主意。添加新的机器人特定功能也会将其添加到人员。
  • 这个例子是完全错误的。通过这样做,您可以更改 Person 的原型。这不是继承,您可能会在 Person 类中造成巨大的混乱。请参阅建议使用 Object.create() 的答案。这才是做事的正确方式。
  • @osahyoun 这个答案在谷歌搜索中排名很高。我真的建议您按照此处其他 cmets 的建议修复代码并更正原型链。
【解决方案2】:

没有“new”关键字的世界。

使用 Object.create() 并使用更简单的“散文式”语法。

*此示例针对 ES6 类和 TypeScript 进行了更新。

首先,Javascript 是 prototypal language,不是基于类的。它的真实性质以下面的原型形式表达,您可能会发现它非常简单,像散文,但功能强大。

TLDR;

Javascript

const Person = { 
    name: 'Anonymous', // person has a name
    greet: function() { console.log(`Hi, I am ${this.name}.`) } 
} 
    
const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'
jack.greet()                         // outputs "Hi, I am Jack."

打字稿

在 TypeScript 中,您需要设置接口,这些接口将在您创建 Person 原型的后代时进行扩展。突变politeGreet 显示了在后代jack 上附加新方法的示例。

interface Person {
    name: string
    greet(): void
}

const Person =  {
    name:  'Anonymous',  
    greet() {
        console.log(`Hi, I am ${this.name}.`)
    }
}

interface jack extends Person {
    politeGreet: (title: 'Sir' | 'Mdm') => void
}

const jack: jack = Object.create(Person)
jack.name = 'Jack'
jack.politeGreet = function(title) {
    console.log(`Dear ${title}! I am ${this.name}.`)
}
jack.greet()  // "Hi, I am Jack."
jack.politeGreet('Sir') // "Dear Sir, I am Jack."

这消除了有时令人费解的构造函数模式。 新对象继承自旧对象,但能够拥有自己的属性。如果我们尝试从新对象 (#greet()) 中获取新对象 jack 缺少的成员,则旧对象 Person 将提供该成员。

Douglas Crockford's words: "Objects inherit from objects. What could be more object-oriented than that?"

您不需要构造函数,也不需要 new 实例化。您只需创建对象,然后扩展或变形它们。

此模式还提供immutability (partial or full)getters/setters

干净整洁。它的简单性不会影响功能。继续阅读。

创建 Person prototype 的后代/副本(技术上比 class 更正确)。

*注意:以下示例是在 JS 中。要使用 Typescript 编写,只需按照上面的示例设置输入接口即可。

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'
Skywalker.firstName = ''
Skywalker.type = 'human'
Skywalker.greet = function() { console.log(`Hi, my name is ${this.firstName} ${this.lastName} and I am a ${this.type}.`

const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true

如果您觉得丢弃构造函数而不是直接赋值不太安全,一种常见的方法是附加 #create 方法:

Skywalker.create = function(firstName, gender, birthYear) {

    let skywalker = Object.create(Skywalker)

    Object.assign(skywalker, {
        firstName,
        birthYear,
        gender,
        lastName: 'Skywalker',
        type: 'human'
    })

    return skywalker
}

const anakin = Skywalker.create('Anakin', 'male', '442 BBY')

Person 原型分支到Robot

当你从Person原型分支Robot后代时,你不会影响Skywalkeranakin

// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'

附加Robot独有的方法

Robot.machineGreet = function() { 
    /*some function to convert strings to binary */ 
}

// Mutating the `Robot` object doesn't affect `Person` prototype and its descendants
anakin.machineGreet() // error

Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false

在 TypeScript 中,您还需要扩展 Person 接口:

interface Robot extends Person {
    machineGreet(): void
}
const Robot: Robot = Object.create(Person)
Robot.machineGreet = function() { console.log(101010) }

而且你可以拥有 Mixins——因为……Darth Vader 是人类还是机器人?

const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.
Object.assign(darthVader, Robot)

Darth Vader 获取Robot 的方法:

darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...

还有其他奇怪的事情:

console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.

优雅地反映了“现实生活”的主观性:

“他现在比人更像机器,扭曲而邪恶。” - 欧比旺克诺比

“我知道你很优秀。” - 卢克天行者

与 ES6 之前的“经典”等效项进行比较:

function Person (firstName, lastName, birthYear, type) {
    this.firstName = firstName 
    this.lastName = lastName
    this.birthYear = birthYear
    this.type = type
}

// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }

function Skywalker(firstName, birthYear) {
    Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}

// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker

const anakin = new Skywalker('Anakin', '442 BBY')

// #isPrototypeOf won't work
Person.isPrototypeOf(anakin) // returns false
Skywalker.isPrototypeOf(anakin) // returns false

ES6 类

与使用对象相比更笨拙,但代码可读性还可以:

class Person {
    constructor(firstName, lastName, birthYear, type) {
        this.firstName = firstName 
        this.lastName = lastName
        this.birthYear = birthYear
        this.type = type
    }
    name() { return this.firstName + ' ' + this.lastName }
    greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}

class Skywalker extends Person {
    constructor(firstName, birthYear) {
        super(firstName, 'Skywalker', birthYear, 'human')
    }
}

const anakin = new Skywalker('Anakin', '442 BBY')

// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true

进一步阅读

可写性、可配置性和免费的 Getter 和 Setter!

对于免费的 getter 和 setter,或额外的配置,您可以使用 Object.create() 的第二个参数,也就是 propertiesObject。它也可以在#Object.defineProperty#Object.defineProperties 中使用。

为了说明其用途,假设我们希望所有Robot 都严格由金属制成(通过writable: false),并标准化powerConsumption 值(通过getter 和setter)。


// Add interface for Typescript, omit for Javascript
interface Robot extends Person {
    madeOf: 'metal'
    powerConsumption: string
}

// add `: Robot` for TypeScript, omit for Javascript.
const Robot: Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,  // defaults to false. this assignment is redundant, and for verbosity only.
        configurable: false, // defaults to false. this assignment is redundant, and for verbosity only.
        enumerable: true  // defaults to false
    },
    // getters and setters
    powerConsumption: {
        get() { return this._powerConsumption },
        set(value) { 
            if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k') 
            this._powerConsumption = value
            throw new Error('Power consumption format not recognised.')
        }  
    }
})

// add `: Robot` for TypeScript, omit for Javascript.
const newRobot: Robot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

并且Robot 的所有原型都不能是madeOf 别的东西:

const polymerRobot = Object.create(Robot)
polymerRobot.madeOf = 'polymer'
console.log(polymerRobot.madeOf) // outputs 'metal'

【讨论】:

  • - Object.create 在许多(旧)浏览器中不存在,尤其是 Internet Explorer 8 及更低版本。 - Object.create() 仍然调用你通过它的函数的构造函数。 - 对于每个属性声明,您必须一遍又一遍地配置相同的设置(如示例代码中所示)。使用 Object.create 代替 new 关键字并没有真正的好处。
  • “受过经典训练的”程序员,你这是什么意思?
  • 我来自经典的 OOP 思维方式,这个答案对我帮助很大。关于代码的两个问题:1)今天的 ES2015 Object.assign(Robot, {a:1} 是您的 extend() 方法的好替代品吗? 2) 如何覆盖greet() 方法,使其返回相同的文本,但附加“a greet override”?
  • 1) #Object.assign 看起来确实是个不错的选择。但浏览器支持较低的atm。 2) 您将使用对象的__proto__ 属性来访问其原型的问候功能。然后你调用原型 greet 函数并传入被调用者的范围。在这种情况下,该函数是一个控制台日志,因此不可能“附加”。但是通过这个例子,我认为你明白了。 skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
  • 嗯,这是应该与 ECMAScript 语言规范维护者进行的讨论。我大体上同意,但我必须使用我所拥有的。
【解决方案3】:

如果您还没有想出办法,请使用 JavaScript 对象的关联属性将扩展函数添加到 Object.prototype,如下所示。

Object.prototype.extend = function(obj) {
   for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
         this[i] = obj[i];
      }
   }
};

然后您就可以使用该功能,如下所示。

var o = { member: "some member" };
var x = { extension: "some extension" };

o.extend(x);

【讨论】:

  • 请注意,在“父”类中使用对象/数组时,这将创建指向“子”类中原始对象的指针。详细说明:如果您的父类中有一个对象或数组,则在扩展该基类的子类中对其进行修改,实际上将针对在同一基类上扩展的所有子类进行修改。
  • Harold,感谢您强调这一事实。对于使用该函数的人来说,加入一个检查对象/数组并复制它们的条件是很重要的。
【解决方案4】:

在 ES6 中,你可以使用扩展操作符

var mergedObj = { ...Obj1, ...Obj2 };

请注意,Object.assign() 会触发 setter,而传播语法则不会。

更多信息见链接,MDN -Spread Syntax


旧答案:

在 ES6 中,Object.assign 用于复制属性值。如果您不想修改目标对象(传递的第一个参数),请使用{} 作为第一个参数。

var mergedObj = Object.assign({}, Obj1, Obj2);

更多详情见链接,MDN - Object.assign()

如果您需要 用于 ES5 的 Polyfill,该链接也提供了它。 :)

【讨论】:

    【解决方案5】:

    不同的方法:Object.create

    根据@osahyoun 的回答,我发现以下是从 Person 的原型对象“继承”的更好、更有效的方法:

    function Person(name){
        this.name = name;
        this.type = 'human';
    }
    
    Person.prototype.info = function(){
        console.log("Name:", this.name, "Type:", this.type);
    }
    
    function Robot(name){
        Person.call(this, name)
        this.type = 'robot';
    }
    
    // Set Robot's prototype to Person's prototype by
    // creating a new object that inherits from Person.prototype,
    // and assigning it to Robot.prototype
    Robot.prototype = Object.create(Person.prototype);
    
    // Set constructor back to Robot
    Robot.prototype.constructor = Robot;
    

    创建新实例:

    var person = new Person("Bob");
    var robot = new Robot("Boutros");
    
    person.info(); // Name: Bob Type: human
    robot.info();  // Name: Boutros Type: robot
    

    现在,使用Object.create

    Person.prototype.constructor !== Robot
    

    还要查看MDN 文档。

    【讨论】:

    • 只想说@GaretClaborn它工作正常,但你没有将name参数传递给父构造函数,像这样:jsfiddle.net/3brm0a7a/3(区别在第8行)跨度>
    • @xPheRe 啊,我明白了,谢谢。我编辑了答案以反映这种变化
    • @xPheRe,我想当我添加这个解决方案时,我更专注于证明一个观点。谢谢。
    • 不错的答案 +1,您可以查看 ECMAScript 6。关键字类和扩展可用:developer.mozilla.org/en-US/docs/Web/JavaScript/…
    【解决方案6】:

    又过了一年,我可以告诉你还有另一个不错的答案。

    如果您不喜欢原型设计以扩展对象/类的方式,请查看:https://github.com/haroldiedema/joii

    可能性的快速示例代码(以及更多):

    var Person = Class({
    
        username: 'John',
        role: 'Employee',
    
        __construct: function(name, role) {
            this.username = name;
            this.role = role;
        },
    
        getNameAndRole: function() {
            return this.username + ' - ' + this.role;
        }
    
    });
    
    var Manager = Class({ extends: Person }, {
    
      __construct: function(name)
      {
          this.super('__construct', name, 'Manager');
      }
    
    });
    
    var m = new Manager('John');
    console.log(m.getNameAndRole()); // Prints: "John - Manager"
    

    【讨论】:

    • 好吧,我还有 2 个月的时间,直到 2 年结束 :P 不管怎样,JOII 3.0 即将发布 :)
    • 3 年后制作。
    • 有趣的概念,但语法看起来真的很难看。你最好等待 ES6 类变得稳定
    • 我完全同意@sleepycal。但不幸的是,在所有主要/常见浏览器都实现这一点之前,至少还需要 5 年时间。所以在那之前,这将不得不做......
    【解决方案7】:

    还在为最简单最好的方法而苦苦挣扎的人,可以使用Spread Syntax来扩展对象。

    var person1 = {
          name: "Blank",
          age: 22
        };
    
    var person2 = {
          name: "Robo",
          age: 4,
          height: '6 feet'
        };
    // spread syntax
    let newObj = { ...person1, ...person2 };
    console.log(newObj.height);

    注意:请记住,最右边的属性将具有优先权。在本例中,person2 位于右侧,因此 newObj 将在其中包含名称 Robo

    【讨论】:

      【解决方案8】:

      您可能需要考虑使用像 underscore.js 这样的辅助库,它有 it's own implementation of extend()

      通过查看它的源代码,这也是一种学习的好方法。 annotated source code page 非常有用。

      【讨论】:

      【解决方案9】:

      Mozilla '宣布'从 ECMAScript 6.0 扩展的对象:

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends

      注意:这是一项实验性技术,是 ECMAScript 6(Harmony)提案的一部分。

      class Square extends Polygon {
        constructor(length) {
          // Here, it calls the parent class' constructor with lengths
          // provided for the Polygon's width and height
          super(length, length);
          // Note: In derived classes, super() must be called before you
          // can use 'this'. Leaving this out will cause a reference error.
          this.name = 'Square';
        }
      
        get area() {
          return this.height * this.width;
        }
      
        set area(value) {
          this.area = value;     } 
      }
      

      Gecko (Google Chrome / Firefox) - 03/2015 nightly builds 中提供了这项技术。

      【讨论】:

        【解决方案10】:

        在大多数项目中都有一些对象扩展的实现:下划线、jquery、lodash:extend

        还有纯 javascript 实现,它是 ECMAscript 6 的一部分:Object.assignhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

        【讨论】:

        • “纯 javascript 实现”不是指仅用 JavaScript 实现的东西,而不是环境提供的可以本地实现的功能吗?
        • @binki,我的意思是原生 javascript 实现 - ECMAScript 2015 (ES6) 标准的一部分
        【解决方案11】:
        Function.prototype.extends=function(ParentClass) {
            this.prototype = new ParentClass();
            this.prototype.constructor = this;
        }
        

        然后:

        function Person() {
            this.name = "anonym"
            this.skills = ["abc"];
        }
        Person.prototype.profile = function() {
            return this.skills.length // 1
        };
        
        function Student() {} //well extends fom Person Class
        Student.extends(Person)
        
        var s1 = new Student();
        s1.skills.push("")
        s1.profile() // 2
        

        2017 年 1 月更新:

        请忽略我对 2015 年的回答,因为 Javascript 现在支持 extends 关键字,因为 ES6 (Ecmasctipt6)

        - ES6:

        class Person {
           constructor() {
             this.name = "anonym"
             this.skills = ["abc"];
           }
        
           profile() {
            return this.skills.length // 1
           }
        
        }
        
        Person.MAX_SKILLS = 10;
        class Student extends Person {
        
        
        } //well extends from Person Class
        
        //-----------------
        var s1 = new Student();
        s1.skills.push("")
        s1.profile() // 2
        

        - ES7 :

        class Person {
            static MAX_SKILLS = 10;
            name = "anonym"
            skills = ["abc"];
        
            profile() {
              return this.skills.length // 1
            }
        
        }
        class Student extends Person {
        
        
        } //well extends from Person Class
        
        //-----------------
        var s1 = new Student();
        s1.skills.push("")
        s1.profile() // 2
        

        【讨论】:

        • 通过在覆盖构造函数之前调用new ParentClass(),您已经执行了父构造函数。如果你问我,我认为那不是正确的行为......
        【解决方案12】:

        总结:

        Javascript 使用一种称为原型继承 的机制。在查找对象的属性时使用原型继承。当我们在 javascript 中扩展属性时,我们是从实际对象继承这些属性。它的工作方式如下:

        1. 当请求对象属性时(例如myObj.foomyObj['foo']),JS 引擎将首先在对象本身上查找该属性
        2. 当在对象本身上找不到此属性时,它会爬上原型链查看原型对象。如果这里也没有找到这个属性,它将继续爬上原型链,直到找到该属性。如果未找到该属性,则会引发引用错误。

        当我们想在 javascript 中扩展一个对象时,我们可以简单地在原型链中链接这个对象。有很多方法可以实现,我将介绍两种常用的方法。

        示例:

        1. Object.create()

        Object.create() 是一个将对象作为参数并创建新对象的函数。作为参数传递的对象将是新创建对象的原型。例如:

        // prototype of the dog
        const dogPrototype = {
          woof: function () { console.log('woof'); }
        }
        
        // create 2 dog objects, pass prototype as an argument
        const fluffy = Object.create(dogPrototype);
        const notFluffy = Object.create(dogPrototype);
        
        // both newly created object inherit the woof 
        // function from the dogPrototype
        fluffy.woof();
        notFluffy.woof();

        2。显式设置原型属性

        在使用构造函数创建对象时,我们可以为其原型对象属性设置添加属性。使用new 关键字创建的对象形成构造函数,其原型设置为构造函数的原型。例如:

        // Constructor function object
        function Dog (name) {
           name = this.name;
        }
        
        // Functions are just objects
        // All functions have a prototype property
        // When a function is used as a constructor (with the new keyword)
        // The newly created object will have the consturctor function's
        // prototype as its prototype property
        Dog.prototype.woof = function () {
          console.log('woof');
        }
        
        // create a new dog instance
        const fluffy = new Dog('fluffyGoodBoyyyyy');
        // fluffy inherits the woof method
        fluffy.woof();
        
        // can check the prototype in the following manner
        console.log(Object.getPrototypeOf(fluffy));

        【讨论】:

          【解决方案13】:

          简单易读的解决方案是使用扩展运算符

          ...
          

          例如:

          const obj1 = {a: "a"} const obj2 = {b: "b"} const result = {...obj1, ..obj2,} console.log("result", result) // must be {a: "a", b: "b"}
          

          【讨论】:

            【解决方案14】:

            您可以简单地使用:

            Object.prototype.extend = function(object) {
              // loop through object 
              for (var i in object) {
                // check if the extended object has that property
                if (object.hasOwnProperty(i)) {
                  // mow check if the child is also and object so we go through it recursively
                  if (typeof this[i] == "object" && this.hasOwnProperty(i) && this[i] != null) {
                    this[i].extend(object[i]);
                  } else {
                    this[i] = object[i];
                  }
                }
              }
              return this;
            };
            

            更新:我检查了this[i] != null,因为null 是一个对象

            然后像这样使用它:

            var options = {
                  foo: 'bar',
                  baz: 'dar'
                }
            
                var defaults = {
                  foo: false,
                  baz: 'car',
                  nat: 0
                }
            
            defaults.extend(options);
            

            这口井的结果是:

            // defaults will now be
            {
              foo: 'bar',
              baz: 'dar',
              nat: 0
            }
            

            【讨论】:

              【解决方案15】:

              请添加拒绝投票的原因

              • 无需使用任何外部库进行扩展

              • 在 JavaScript 中,一切都是对象(除了这三个 原始数据类型,甚至它们都自动包装 需要时提供对象)。此外,所有对象都是可变的。

              JavaScript 中的类人

              function Person(name, age) {
                  this.name = name;
                  this.age = age;
              }
              Person.prototype = {
                  getName: function() {
                      return this.name;
                  },
                  getAge: function() {
                      return this.age;
                  }
              }
              
              /* Instantiate the class. */
              var alice = new Person('Alice', 93);
              var bill = new Person('Bill', 30);
              

              修改特定实例/对象

              alice.displayGreeting = function() 
              {
                  alert(this.getGreeting());
              }
              

              修改类

              Person.prototype.getGreeting = function() 
              {
                  return 'Hi ' + this.getName() + '!';
              };
              

              或者简单地说:extend JSON 和 OBJECT 都是一样的

              var k = {
                  name : 'jack',
                  age : 30
              }
              
              k.gender = 'male'; /*object or json k got extended with new property gender*/
              

              感谢罗斯·哈姆斯,达斯汀·迪亚兹

              【讨论】:

                【解决方案16】:

                虽然这项工作并非 100% 正确

                // Parent
                var Parent = function (name) {
                  this.name = name;
                  this.test = function () {
                    console.log("parent test");
                  }
                  this.testOverride = function () {
                    console.log("parent testOverride");
                  }
                }
                // define a function extend
                Parent.prototype.extend = function () {
                  // parent properties to override or add
                  var override = arguments[0];
                  return function () {
                    Parent.apply(this, arguments);
                    // add and override properties
                    Object.keys(override).forEach(el =>{
                      this[el] = override[el];
                    })
                   }
                }
                // create a Child from the Parent and override
                // the function "testOverride" and keep "test" unchanged
                var Child = Parent.prototype.extend({
                  y: 10,
                  testOverride: function () { 
                    console.log("child testOverride"); 
                  }
                });
                // Create an object of type Parent
                var p = new Parent("Parent");
                // Create an object of type Child
                var c = new Child("Child");
                console.log(p.name);
                // Parent
                console.log(c.name);
                // Child
                p.test();
                //parent test
                p.testOverride();
                //parent testOverride
                c.test();
                //parent test
                c.testOverride();
                //child testOverride
                

                【讨论】:

                  【解决方案17】:

                  这将使您的属性扩展创建一个新的对象,其中包含对象参数原型,而不会更改传递的对象。

                  function extend(object) {
                      if (object === null)
                          throw TypeError;
                      if (typeof object !== "object" && typeof object !== "function")
                          throw TypeError;
                      if (Object.create)
                          return Object.create(object);
                      function f() {}
                      ;
                      f.prototype = p;
                      return new f();
                  }
                  

                  但是如果你想扩展你的对象而不修改它的参数,你可以将 extendProperty 添加到你的对象中。

                  var Person{
                  //some code
                  extend: extendProperty
                  }
                  
                  //Enforce type checking an Error report as you wish
                      function extendProperty(object) {
                          if ((object !== null && (typeof object === "object" || typeof object === "function"))){
                              for (var prop in object) {
                                  if (object.hasOwnProperty(prop))
                                      this[prop] = object[prop];
                              }
                          }else{
                              throw TypeError; //Not an object
                          }
                      }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-11-21
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-09-21
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-06-02
                    相关资源
                    最近更新 更多