在Javascript中扩展对象

我目前正在从Java转换到Javascript,对于如何按照我希望的方式来扩展对象,我有点困难。

我看到互联网上有几个人使用了一种叫做“在对象上扩展”的方法。 代码将如下所示:

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(...); 

但我不知道如何使这个系统工作。 如果这是不可能的,请给我看另一个扩展对象的select。

编辑
在使用代码之前,请检查user2491400中有关简单分配给prototype副作用的评论。

原始答案:

你想从Person的原型对象“inheritance”:

 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.name = name; 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 

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

用Object.create()更简单的语法。

我在信奉Javascript的阵营中应该尝试没有“新”的生活。 这是一种无阶级的语言,它不需要构造函数。 您只需创build对象,然后对其进行扩展或变形即可。 当然,这是有缺陷的,但是这是非常强大和简单的:

 // base `Person` prototype var Person = { name : '', age : 22, type : 'human', greet: function() { console.log('Hi, my name is ' + this.name + ' and I am a ' + this.type + '.' ); } }; // create an instance of `Person`: var skywalker = Object.create(Person); skywalker.name = 'Anakin Skywalker'; skywalker.greet(); // 'Hi, my name is Anakin Skywalker and I am a human.' 

扩展基础原型

 // create a `Robot` prototype by extending the `Person` prototype: var Robot = Object.create(Person); Robot.type = 'robot'; Robot.variant = ''; // add properties for Robot prototype // Robots speak in binaries, so we need a different greet function: Robot.greet = function() { //some function to convert strings to binary } 

再深一层

 // create a new instance `Robot` var Astromech = Object.create(Robot); Astromech.variant = 'astromech'; var r2d2 = Object.create(Astromech); r2d2.name = 'R2D2'; r2d2.greet(); // '0000111010101011100111....' // morphing the `Robot` object doesn't affect `Person` prototypes skywalker.greet(); // 'Hi, my name is Anakin Skywalker and I am a human.' 

进一步阅读

**更新1月22日17.包括ES6 Object.assign()。

正如你所看到的,任务需要多个语句。 使用ES6,您可以使用#assign方法来缩短分配。 (要在较旧的浏览器上使用polyfill ,请参阅ES6上的MDN 。)

 //instead of this var Robot = Object.create(Person); Robot.name = "Robot"; Robot.madeOf = "metal"; Robot.powerConsumption_kW = 5; //you can do this var Robot = Object.create(Person); Object.assign(Robot, { name = "Robot", madeOf: "metal", powerConsumption_kWh: 5, fullCharge_kWh = 10, currentCharge_kWh = 5 }); //attach some methods unique to Robot prototype. Robot.charge = function(kWh) { var self = this; this.currentCharge_kWh = Math.min(self.fullCharge_kWh, self.currentCharge_kWh + kWh); var percentageCharged = this.currentCharge_kWh / this.fullCharge_kWh * 100; console.log(this.name + (percentageCharged === 100) ? ' is fully charged.' : ' is ' + percentageCharged +'% charged.'); }; Robot.charge(5); // outputs "Robot is fully charged." //you can also use Object.create()'s second argument aka propertiesObject, //which I find to be a little too lengthy. The only reason to use it over #assign is if you need more control over the values ie writability/configurability etc... var Robot = Object.create(Person, { madeOf: { value: "metal", writable: true, configurable: true, enumerable: true }, powerConsumption: { value: "5kWh", writable: true, configurable: true, enumerable: true } }); 

这种模式有一些陷阱,可能会出现“古典训练”的程序员。 尽pipe如此,我发现这种模式更具可读性。

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

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

然后你可以使用这个function,如下所示。

 var o = { member: "some member" }; var x = { extension: "some extension" }; o.extend(x); 

不同的方法: Object.create

根据@osahyoun的回答,我发现以下是从Person的原型对象'inheritance'的更好和有效的方法:

 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 Robot.prototype = Object.create(Person.prototype); // Set constructor back to Robot Robot.prototype.constructor = Robot; person = new Person("Bob"); robot = new Robot("Boutros"); person.info(); // Name: Bob Type: human robot.info(); // Name: Boutros Type: robot 

现在,通过使用Object.create , Person.prototype.constructor !== Robot

检查MDN文档。

再过一年,我可以告诉你还有一个很好的答案。

如果你不喜欢原型的工作方式来扩展对象/类,请点击这里: 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" 

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

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

有关更多详情,请参阅链接

MDN – Object.assign()

如果你需要的是一个用于ES5Polyfill ,链接也提供它。 🙂

您可能需要考虑使用像underscore.js这样的助手库,它有自己的extend()

通过查看源代码,这也是学习的好方法。 注释的源代码页是非常有用的。

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

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

注意:这是一个实验技术,是ECMAScript 6(和谐)提案的一部分。

 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(谷歌浏览器/火狐浏览器) – 2015年3月每晚构build这项技术。

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

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

 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 

更新01/2017:

请忽略我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 

你可以简单地通过使用:

 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 } 
  • 不需要使用任何外部库来扩展

  • 在JavaScript中,一切都是一个对象(三种基本数据types除外,即使它们在需要时也会自动包装在对象中)。 而且,所有对象都是可变的。

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() + '!'; }; 

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

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

感谢ross harmes,dustin diaz

原型是一个不错的方法,但原型有时是相当危险的,可能会导致错误。 我更喜欢把它封装到一个基础对象中,就像Ember.js对Ember.Object.extend和Ember.Object.reopen所做的那样。 这是更安全的使用。

我创build了一个如何设置类似于 Ember.Object使用的东西的要点。

这里的链接: https : //gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd