我目前正在从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(...);
但我不知道如何使这个系统工作。如果不可能,请告诉我另一个扩展对象的替代方案。
答案 0 :(得分:187)
修改强>:
在使用该代码之前,请查看user2491400的评论,该评论报告了简单分配给prototype
的副作用。
原始回答:
你想从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.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
答案 1 :(得分:80)
我认为Javascript应该尝试在没有" new"的情况下进入营地。它是一种无类别的语言,它不需要构造函数。您只需创建对象,然后扩展或变形它们。当然,有一些陷阱,但这更加强大和简单:
// base `Person` prototype
const Person = {
name : '',
age : 22,
type : 'human',
greet() {
console.log('Hi, my name is ' + this.name + ' and I am a ' + this.type + '.' )
}
}
// create an instance of `Person`:
const 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:
const 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`
const Astromech = Object.create(Robot)
Astromech.variant = 'astromech'
const 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.'
** 10月18日更新。采用ES6语法并使用const
和let
。添加了示例,说明如何使属性不可变。
** 1月17日更新。包括ES6 Object.assign()。
正如您所看到的,分配需要多个语句。使用ES6,您可以使用#assign方法缩短分配。 (要在旧版浏览器上使用polyfill,请参阅MDN on ES6。)
//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"
Robot.powerConsumption_kW = 5
//you can do this
const 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) {
let 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."
你也可以使用Object.create()的第二个参数a.k.a propertiesObject,我发现它有点过于冗长。在#assign上使用它的唯一原因是你需要对值进行更多控制,即可写性/可配置性等等......请注意Robot
严格来说都是由金属制成的。
const Robot = Object.create(Person, {
madeOf: {
value: "metal",
writable: false,
configurable: false,
enumerable: true
},
powerConsumption: {
value: "5kWh",
writable: true,
configurable: true,
enumerable: true
}
})
Robot
的所有原型都不能用其他东西制作。
const polymerRobot = Object.create(Robot)
polymerRobot.madeOf = 'polymer'
console.log(polymerRobot.madeOf) // outputs 'metal'
这种模式有可能会绊倒"经典训练的"程序员。尽管如此,我发现这种模式更具可读性。
答案 2 :(得分:51)
如果您尚未找到方法,请使用JavaScript对象的associative属性将扩展函数添加到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);
答案 3 :(得分:28)
根据@ 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文档。
答案 4 :(得分:18)
另一年后,我可以告诉你还有另一个不错的答案。
如果您不喜欢原型设计的工作方式以扩展对象/类,请参考: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"
答案 5 :(得分:13)
在ES6 中,复制属性值有Object.assign
。如果您不想修改目标对象(传递的第一个参数),请使用{}
作为第一个参数。
var resultObj = Object.assign({},Obj1,Obj2);
有关详情,请参阅链接
如果您需要 Polyfill for ES5 ,该链接也会提供。 :)
答案 6 :(得分:8)
您可能需要考虑使用underscore.js之类的辅助库,其中包含it's own implementation of extend()
。
通过查看源代码,这也是一种很好的学习方式。 annotated source code page非常有用。
答案 7 :(得分:6)
仍在努力寻求简单,最佳方法的人们,可以使用 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 :(得分:6)
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(谷歌浏览器/火狐) - 2015年3月夜间版本中使用。
答案 9 :(得分:3)
在大多数项目中都有一些对象扩展的实现:下划线,jquery,lodash:扩展。
还有纯javascript实现,这是ECMAscript 6的一部分: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
答案 10 :(得分:2)
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
请忽略我2015年的答案,因为自从ES6(Ecmasctipt6)以来,Javascript现在支持extends
个关键字
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
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
答案 11 :(得分:1)
Javascript使用一种称为原型继承的机制。在对象上查找属性时,将使用原型继承。当我们在javascript中扩展属性时,我们将从实际对象继承这些属性。它以以下方式工作:
myObj.foo
或myObj['foo']
)时,JS引擎将首先在对象本身上寻找该属性当我们想从javascript对象扩展时,我们可以简单地在原型链中链接该对象。有很多方法可以实现这一点,我将介绍2种常用方法。
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。明确设置原型属性
使用构造函数创建对象时,我们可以将add属性设置为其原型对象属性。使用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));
答案 12 :(得分:0)
您只需使用以下命令即可:
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
}
答案 13 :(得分:0)
请为DOWNVOTE添加理由
无需使用任何外部库来扩展
在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() + '!';
};
或者简单地说:扩展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
答案 14 :(得分:0)
虽然这项工作并非 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
答案 15 :(得分:-1)
这将扩展您的属性,使用对象参数原型创建一个新的Object而不改变传递的对象。
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();
}
但是如果要在不修改参数的情况下扩展Object,可以将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
}
}
答案 16 :(得分:-2)
原型设计是一种很好的方式,但原型有时非常危险并且可能导致错误。我更喜欢将它封装到一个基础对象中,就像Ember.js对它的Ember.Object.extend和Ember.Object.reopen一样。使用起来更加安全。
我创建了一个关于如何设置类似与Ember.Object使用的内容的要点。