我试图了解Javascript中的继承。
我知道每个对象都有一个原型,它是一个继承属性的对象。我知道.prototype
属性仅存在于函数上,并且当它被用作构造函数时,它将被设置为从该函数创建的对象的原型。
虽然有些浏览器支持__proto__
属性,但我知道对象的原型是不可访问的。 (但由于它不是该语言的经典部分,我想了解如何在没有它的情况下使用该语言。)
所以如果所有这些都是正确的(?),我想要揭示定义继承链的标准方法。
我能想到的唯一方法是:
我希望它们从另一个对象继承的所有对象,必须通过构造函数创建。他们的基础对象'将被设置为其构造函数的.prototype
。
当我希望他们中的一个成为一个基础对象'其他对象,我将其设置为另一个构造函数的.prototype
。等等。
这看起来很奇怪。有没有办法(正常' JS)设置一个对象的基础'直?或者我是否必须以上述方式使用构造函数,以便创建继承链?
什么是'标准'创建继承的方法?我描述的方法是标准方法吗?
答案 0 :(得分:1)
JavaScript支持继承的主要方式是通过原型继承。具体而言,只要在初始对象上找不到属性查找,JavaScript 委托中的对象就会转移到其他对象。此委托继续,直到JavaScript引擎到达Object.prototype
,其中找到该属性或抛出错误。
创建以特定对象作为原型的对象的当前最佳做法是使用Object.create
- 您可以查看更多信息here。
以下是一个例子:
var methods = {
method1: function () { console.log( 'something' ); },
method2: function () { return 'cool'; }
};
/*
* Now firstObj will delegate to methods whenever a property lookup can't
* be found on firstObj itself
*/
var firstObj = Object.create( methods );
// You can add custom properties on firstObj
firstObj.someOtherProperty = 'custom property';
/*
* You can create a chain of delegations! Property lookup first happens on secondObj.
* If its not found there, it looks up the property in firstObj. If its not found there,
* then it looks up the property in methods. Finally, if not found, it tries
* Object.prototype
*/
var secondObj = Object.create ( firstObj );
答案 1 :(得分:1)
首先,JavaScript中的继承有点难以理解,因为:
new
(这使得人们认为实例继承自构造函数,而不是原型)。这被称为constructor pattern,这是JavaScript混淆的主要原因。出于这个原因Object.create
被引入。它允许对象直接从其他对象继承。但是,与使用Object.create
相比,new
速度较慢。我遇到了同样的问题,我正在寻找替代方案;我确实想出了一个。
请考虑以下代码:
function Person(firstname, lastname, gender) {
this.firstname = firstname;
this.lastname = lastname;
this.gender = gender;
}
Person.prototype.getFullname = function () {
return this.firstname + " " + this.lastname;
};
Man.prototype = new Person;
Man.prototype.constructor = Man;
function Man(firstname, lastname) {
Person.call(this, firstname, lastname, "M");
}
var bobMarley = new Man("Bob", "Marley");
alert(bobMarley.getFullname());

这种编写代码的方式有几个问题:
Man.prototype
设置为Person.prototype
来new Person
继承firstname
。但是,在执行此操作时,我们会在lastname
上初始化gender
,Man.prototype
和Object.create
属性,这是错误的。随着function Person(firstname, lastname, gender) {
this.firstname = firstname;
this.lastname = lastname;
this.gender = gender;
}
Person.prototype.getFullname = function () {
return this.firstname + " " + this.lastname;
};
Man.prototype = Object.create(Person.prototype);
Man.prototype.constructor = Man;
function Man(firstname, lastname) {
Person.call(this, firstname, lastname, "M");
}
var bobMarley = new Man("Bob", "Marley");
alert(bobMarley.getFullname());
的引入,我们现在可以编写如下代码:
Man.prototype = new Person

唯一的变化是我们写Man.prototype = Object.create(Person.prototype)
而不是Object.create
。这解决了传统方法的第二个问题。但是,代码仍然看起来像意大利面条。
然而,var person = {
init: function (firstname, lastname, gender) {
this.firstname = firstname;
this.lastname = lastname;
this.gender = gender;
},
getFullname: function () {
return this.firstname + " " + this.lastname;
}
};
var man = Object.create(person, {
init: {
value: function (firstname, lastname) {
person.init.call(this, firstname, lastname, "M");
}
}
});
var bobMarley = Object.create(man);
bobMarley.init("Bob", "Marley");
alert(bobMarley.getFullname());
非常强大。您也可以使用它来编写面向对象的代码,而根本不创建构造函数。有些人称之为initializer pattern:
Object.create

这解决了传统方法的所有问题。但是,它也引入了一些新问题:
init
创建实例,然后使用new
初始化新对象。这比仅使用var Person = defclass({
constructor: function (firstname, lastname, gender) {
this.firstname = firstname;
this.lastname = lastname;
this.gender = gender;
},
getFullname: function () {
return this.firstname + " " + this.lastname;
}
});
var Man = extend(Person, {
constructor: function (firstname, lastname) {
Person.call(this, firstname, lastname, "M");
}
});
var bobMarley = new Man("Bob", "Marley");
alert(bobMarley.getFullname());
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, properties) {
var prototype = Object.create(constructor.prototype);
var keys = Object.keys(properties);
var length = keys.length;
var index = 0;
while (index < length) {
var key = keys[index++];
prototype[key] = properties[key];
}
return defclass(prototype);
}
慢得多。为了解决这个问题,我在JavaScript中为OOP编写了自己的函数:
defclass
&#13;
我在JavaScript中为OOP定义了两个函数extend
和defclass
。 prototype
函数从原型创建“类”。这是可能的,因为prototypes and classes are isomorphic。
extend函数用于继承。它创建constructor
extend
的实例,并在返回新原型的“类”之前将一些属性复制到其上。
这是我目前在JavaScript中创建原型链的方式。与其他方法相比,它具有以下优点:
Object.create
函数使用constructor
进行继承。因此,新原型不会添加额外的属性。它是一个空白的原型。prototype
上的defclass
属性。它会自动为您完成。extend
函数不同,Object.create
和new
函数是一致的。Object.create
代替init
和{{1}}创建实例。因此,生成的代码要快得多。我现在可能错了,但我不这么认为。希望有所帮助。
答案 2 :(得分:-1)
你可以通过javascript中的两种方式继承 - 经典和原型
古典
function inherit (C, P) {
var F = function () {};
F.prototype = P.prototype;
C.prototype = new F();
}
原型
function inherit (o) {
function F() {}
F.prototype = o;
return new F();
}