2013-11-18 1 views
3

Во время игры вокруг с онлайн машинопись компилятором, я заметил, что создатели решили реализовать наследование с помощью следующего метода (который я сделал несколько более читаемым):Цель собственности копирования на наследование типа

var __extends = function(type, base) { 
    for (var prop in base) { // why copy the properties? 
     if (base.hasOwnProperty(prop)) { 
      type[prop] = base[prop]; 
     } 
    } 
    function __() { // <- ? 
     this.constructor = type; 
    } 
    __.prototype = base.prototype. 
    type.prototype = new __(); 
}; 

метод затем используется следующим образом:

var Item = (function() { 
    function Item() { 
    } 
    return Item; 
})(); 

var Sword = (function (base) { 
    __extends (Sword, base); 
    function Sword() { 
     base.call(this); 
    } 
    return Sword; 
})(Item); 

Я с трудом understandind реализации метода __extends.
Какова цель ручного копирования всех свойств из расширяемого типа? Не унаследуете прототип заботиться об этом?

Существует ли штраф за выполнение при поиске свойств в дереве прототипов, а не непосредственно скопированных свойствах?

Вторая часть, я также не могу понять цель. Вместо того, чтобы сделать это:

function __() { 
    this.constructor = type; 
} 
__.prototype = base.prototype. 
type.prototype = new __(); 

Может ли это быть просто реализован как:

type.prototype = base.prototype; 

ответ

3

Большой вопрос. Давайте сломаем это.

var __extends = function(type, base) { 
    // ** Begin static-side inheritance ** 
    for (var prop in base) { 
     if (base.hasOwnProperty(prop)) { 
      type[prop] = base[prop]; 
     } 
    } 
    // ** End static-side inheritance ** 

    // ** Begin Object.create polyfill ** 
    function __() { // <- ? 
     this.constructor = type; 
    } 
    __.prototype = base.prototype. 
    // ** End Object.create polyfill ** 

    // ** Prototype setup ** 
    type.prototype = new __(); 
}; 

Прежде всего это наследование статической стороны. Система типа TypeScript устанавливает, что если какой-либо тип имеет статический метод, производный класс также имеет этот метод (или метод, подпись которого является подтипом метода базового класса). Это полезно для таких вещей, как фабричные модели, например .:

class Car { 
    static create(name: string, topSpeed: number): Car { 
     // ... 
     return new this(/* ... */); 
    } 
} 

class RaceCar extends Car { 
    // RaceCar ignores topSpeed because it goes super fast 
    static create(name: string): RaceCar { 
     // ... 
     return new this(/* ... */); 
    } 
} 

class Truck extends Car { 
} 

function makeTestCar(t: typeof Car) { 
    return t.create('test', 60); 
} 
var car = makeTestCar(Car); // returns an instance of Car 
var raceCar = makeTestCar(RaceCar); // returns an instance of RaceCar 
var truck = makeTestCar(Truck); // OK, even though Truck doesn't explicitly implement 'create' 

Обратите внимание, что в последней строке Truck класса получил свой метод create с помощью своего базового класса Car. Копирование необходимо, так как Truck.__proto__ is неCar.

Далее у нас есть Object.create полипол. Недостаточно написать type.prototype = base.prototype, потому что члены __proto__ (AKA [[proto]]) и prototype - это не одно и то же.Другие ответы на SO дали лучшее изложение прототипного наследования, поэтому я буду откладывать на них.

Наконец, последняя строка устанавливает прототип конструктора, так что созданный объект имеет правильную __proto__

+0

Глядя на ответы на этот вопрос в ретроспективе, и теперь, когда я более опытен с TS, я чувствую, что ваш ответ более полный и информативный, и дает более глубокое понимание. Это был правильный ответ. – Acidic

3

Расширяет копирует прототип и статические элементы (поверхностное копирование). Statics - Parent.things и прототипы - Parent.prototype.things. Как копируется prototype.things, так это то, как работает poly fill для Object.

var __extends = this.__extends || function (d, b) { 
    //Copies Item.things to Sword.things 
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 
    //Copies Item.prototype.things to Sword.prototype.things 
    //this is a polyfill for Object.create 
    function __() { this.constructor = d; } 
    __.prototype = b.prototype; 
    d.prototype = new __(); 
}; 
var Sword = (function (_super) { 
    __extends(Sword, _super); 
    function Sword() { 
     _super.apply(this, arguments); 
    } 
    return Sword; 
})(Iten); 

Рассмотрим следующий Машинопись:

class Item { 
    public static DAMAGE = 0; 
}; 

В JavaScript это будет:

var Item = (function() { 
    function Item() { 
    } 
    Item.DAMAGE = 0; 
    return Item; 
})(); 

Как бы использовать статический ПОВРЕЖДЕНИЯ? См. Следующий пример (simplefied JS);

//Using static to make general getters and setters 
var Item = function(damage){ 
    this._data = []; 
    this.set(Item.DAMAGE,damage) 
}; 
Item.DAMAGE=0; 
Item.prototype.get=function(dataIndex){ 
    return this._data[dataIndex]; 
}; 
Item.prototype.set=function(dataIndex,val){ 
    //maybe execute Item.rules[dataIndex].set(val) for validating value 
    this._data[dataIndex] = val; 
    return val; 
}; 
var i = new Item(22); 
//I could get damage using i.get(0) 
//but the following reads more easily 
i.get(Itesm.DAMAGE); 

Введение о конструкторах функций, прототип, наследование, перемешайте плюсами и это значение здесь: https://stackoverflow.com/a/16063711/1641941

+0

Насколько я могу сказать, что пропавшие вещи не имеют никакого влияния на моем примере, так вот почему я удалил их. – Acidic

+0

@Acidic Правильно, я что-то пропустил. Создал пример того, как использовать static, а пример Rayan показывает хороший для заводских шаблонов. – HMR

Смежные вопросы