2013-07-28 4 views
4

Я изучаю javascript.Почему мы добавляем функции к прототипу javascripts?

Почему функции определены за пределами объекта?

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName; 
} 

Man.prototype.getName = function() {  
    return this.firstName + this.lastName; 
}; 

Выглядит немного странно для меня. Он работает, если я добавляю функцию внутри класса (удаление .protoype и т. Д.), Но мне говорят, чтобы определить функцию outisde объекта.

Почему?

+0

Это просто, как работает Javascript. Это не классический язык OO. Почему большое дело? – MaxArt

+0

Почему бы вам не динамически создавать каждый метод только при инициализации экземпляра класса? – Blender

+0

@Blender: поскольку точка прототипического наследования не делает этого :-) – Bergi

ответ

8

Выглядит немного странно для меня.

Вот как работает настройка прототипов, назначенных функциями конструктора. И вы не единственный, кто считает это неудобным, см. Ниже. :-) (Update:. И смотри ниже для того, как ES6 делает это намного проще)

Это работает, если добавить функцию внутри класса (удаление .protoype и т.д.), но я являюсь сказал, чтобы определить функцию outisde объекта.

Если вы сделаете это:

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName; 
    this.getName = function() {  
     return this.firstName + this.lastName; 
    }; 
} 

... то каждый Man объекта получает свою собственную копии функции. Они не разделяют, вы получаете новый функциональный объект для каждого объекта Man. (Умный движок может повторно использовать базовую функцию код, но там будет - это два функциональных объекта.) Целью прототипов является создание функций, которые могут совместно использоваться объектами, построенными конструктором.

Другое замечательное в прототипах заключается в том, что соединение объекта с прототипом продолжается, что означает, что вы можете добавлять функции к уже существующим объектам, добавляя их к прототипу. Пример:

как мы добавили introduction к прототипу после joe был создан
function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName; 
} 

Man.prototype.getName = function() {  
    return this.firstName + " " + this.lastName; 
}; 

var joe = new Man("Joe", "Bloggs"); 
console.log(joe.getName()); // "Joe Bloggs" 

Man.prototype.introduction = function() { 
    return "Hi there, I'm " + this.getName(); 
}; 

console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs" 

Примечание. Это не имеет значения, поиск динамичен. Когда вы делаете joe.introduction, двигатель ищет объект introduction на joe и, если он не находит его, он смотрит на прототип. Таким образом, добавление в прототип позже (косвенно) улучшает существующие объекты.


Вы не единственный, кто считает синтаксис неудобным. Вы часто видите, что люди создают «extend» методы, подобные тем, которые используются в jQuery, подчёркивании, прототипе и т. Д. Метод extend просто присваивает свойства исходного объекта целевому объекту.Простая форма этого является:

function extend(target, source) { 
    var name; 
    for (name in source) { 
     target[name] = source[name]; 
    } 
} 

... хотя, как правило, вы видите что-то с более широкими возможностями (несколько объектов-источников, возвращение назначения и т.д.).

И тогда вы можете использовать его как это:

function Man(firstName, lastName) { 

    this.firstName = firstName; 
    this.lastName = lastName; 
} 
extend(Man.prototype, { 
    getName: function() {  
     return this.firstName + this.lastName; 
    }, 
    introduction: function() { 
     return "Hi there, I'm " + this.getName(); 
    } 
}); 

Это использует синтаксис инициализатора объекта (иногда называемый «литерал объекта»), передает его в extend и extend помещает свойства на Man.prototype.

Вы также видите такие вещи, как my Lineage script, которые упрощают этот синтаксис и обрабатывают несколько других вещей (например, вызов функции-прототипа функции-источника).


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

class Man { 
    constructor(firstName, lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

    getName() {  
     return this.firstName + " " + this.lastName; 
    } 

    introduction() { 
     return "Hi there, I'm " + this.getName(); 
    } 
} 

var joe = new Man("Joe", "Bloggs"); 
console.log(joe.getName()); // "Joe Bloggs" 

console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs" 
+1

Другой способ добавления прототипа, который стоит упомянуть, - использовать прототип какой-либо «протяженности» (например, для jquery или underscore.js). Просто мысль :) - она ​​выглядит намного чище, по крайней мере, и намного меньше печатает. – Stephen

+0

Вау, это на самом деле удивительная особенность. благодаря! – user2627149

+0

@ user2627149: Добро пожаловать! Рад, что помогло. –

1

Вы можете определить функции внутри объекта, но это не всегда возможно (встроенные объекты, сторонние библиотеки и т. Д.).

Предположительно, книга/учебник/учитель хочет, чтобы вы использовали прототип, потому что они хотят, чтобы вы научились расширять объекты с помощью этого метода.

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