我已经阅读了Google第一页上的每篇文章和示例,我仍然很难完全理解如何在JavaScript中正确实现Prototypal Inheritance。我面临的最大挑战是我看到了许多不同的方法来实现继承。
首先,如果这是C#,我将从我想要实现的目标开始:
C#
class Base {
public string UI { get; set; } // Using a string just for simplicity
}
class Book : Base {
public Book(string title) {
this.title = title;
}
private string title { get; set; } // Title of book
}
然后我可以实例化一本书,并能够在每个实例上访问UI
:
var myBook = new Book("East of Eden");
myBook.UI = "some string"; // This work.. all Book instances have THEIR OWN UI string
的JavaScript
现在假设我在JS中有一个基础对象,我希望所有其他对象都继承自:
function Base() {
this.UI = {}
}
然后我希望另一个对象类型继承这个模型:
function Book(title){
this.title = title;
}
Book.prototype = new Base();
// Sometimes I have seen this line instead... nothing seems to work at all when I use this though, so I don't understand whats happening here
//Book.prototype = Object.create(Base.prototype);
Book.prototype.constructor = Book;
Book.prototype.getTitle = function(){
return this.title;
}
var myBook = new Book("East of Eden");
var anotherBook = new Book("Grapes of Wrath");
console.log(myBook.getTitle()); // East of Eden
myBook.UI.isRead = true;
console.log(myBook.UI);
console.log(anotherBook.getTitle()); // Grapes of Wrath
anotherBook.UI.isHardcopy = true;
myBook.UI.isRead = false;
console.log(anotherBook.UI); // This UI object has isRead on it as well!!! NOOOO
所以这并没有真正起作用,因为两个实例共享相同的UI对象,但我想要的是让他们拥有UI对象的OWN实例。
我看到的另一种方法是根本不使用'new'关键字,只使用Object.create()
来获取新对象。但是,我不确定如何使用Base
之类的子类实现我的Book
类,然后创建Book
的多个实例,每个实例都有自己的UI属性。
有人可以举个例子来说明如何继承基类并使用自己的UI对象创建该子类的实例吗?感谢
修改
实现我想做的事情的“简单”方式也是如此:
var Base = {
UI: {}
}
function Book(title){
_.extend(this, Base);
this.title = title;
}
var myBook = new Book("East of Eden");
myBook.UI.prop = 5; // This works now but doesn't utilize true inheritance at all!
答案 0 :(得分:2)
原型是链接的而不是复制的。这意味着当你这样做时:
function Base(){
this.UI = {}
}
Book.prototype = new Base();
Book.prototype.constructor = Book;
Book
构造函数的原型将是Base
的新实例。您Book
的所有实例都将具有相同的原型,即Base
的相同实例。由于它是保存UI
属性的对象,因此所有Book
实例都将回退到同一对象属性。
认为您的Prototype将是:
var proto = {
UI : { }
}
您的所有Book
个实例都可以访问此对象:
var a = new Book('East of Eden');
var b = new Book('Grapes of Wrath');
a.UI.prop = 'prop'; //proto.UI.prop === 'prop'
b.UI.prop === 'prop'; //because it's also proto.UI.prop
如果您实际在Book
个实例上定义了一个属性,请说明它的构造函数:
function Book(title){
this.title = title;
this.UI = { };
}
您会发现它们是不同的对象:
a.UI !== b.UI //true
a.UI.prop = 'prop';
b.UI.prop !== b.UI; //true
调用构造函数是最简单的方法来初始化子元素的属性:
function Book(title){
Base.call(this);
this.title = title;
}
关于new Base()
和Object.create(Base.prototype)
之间的差异。
new Base()
将初始化对象并调用构造函数,而Object.create(Base.prototype)
将基本相同,除非它不会调用构造函数。这意味着,原型不会在构造函数(UI
)上设置属性。
答案 1 :(得分:1)
我面临的最大挑战是我看到许多不同的方法来实现继承。
确实只有一种正确的方法。
使用Object.create
建立继承:
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
configurable: true,
}
});
然后将子构造函数中的父构造函数应用于子实例:
function Child() {
Parent.call(this);
}
如果您使用ES2015的新class
语法,这基本上就是在幕后发生的事情。
有关Object.create
的详细信息以及在这种情况下您希望使用它的原因,请参阅Benefits of using `Object.create` for inheritance。