理解JS

时间:2015-12-18 20:02:47

标签: javascript inheritance

我已经阅读了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!

2 个答案:

答案 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