Может кто-нибудь объяснить наследование Javascript прототипа - PullRequest
7 голосов
/ 09 ноября 2009

Интересно, может ли кто-нибудь быть настолько любезным, чтобы объяснить function.prototype thingie (thingie !! ??) в OO javascript.

Я пришел из среды программирования на стороне сервера, и, может быть, я не понимаю всей концепции прототипов,

Учитывая следующие фрагменты кода:

var animate=function(){};
animate.angular=function(){/*does something here*/};
animate.circular=function(){/*does something here*/};

И

var animate=function(){};
animate.prototype.angular=function(){/*does something here*/};
animate.prototype.circular=function(){/*does something here*/};

Насколько я могу судить, обе последние функции можно вызывать с помощью animate.angular(/*args*/) и animate.circular(/*args*/), поэтому я предполагаю, что мой вопрос заключается в том, каковы преимущества определения функций вторым способом? и чем или чем они отличаются?

Надеюсь, я понял ...

РЕДАКТИРОВАТЬ: Спасибо вам всем за поучительные ответы, здесь очень трудно судить о том, что ответ "Правильный", поэтому я отмечу тот, который, как мне кажется, был внесен наиболее ... 1020 *

Вы, конечно, дали мне больше пищи для размышлений ...

Ответы [ 6 ]

6 голосов
/ 10 ноября 2009

Я думаю, что вы хотели установить что-то равное new animate () где-то в вашем примере. Без использования new Я немного поясню, что происходит:

var animate = function(){ console.log(0, 'animate'); };
animate.angular = function(){ console.log(1, 'animate.angular'); };
animate.circular = function(){ console.log(2, 'animate.circular'); };

animate.prototype.angular = function(){ console.log(3, 'animate.prototype.angular'); };
animate.prototype.circular = function(){ console.log(4, 'animate.prototype.circular'); };

Только первые две функции, # 1 и # 2, могут вызываться из переменной animate.

animate.angular();
animate.circular();

Если вы создаете new animate () , вы можете вызвать следующие два, # 3 и # 4 (но не # 1 или # 2).

var ani2 = new animate();

ani2.angular();
ani2.circular();

Кроме того, animate () - это функция, а ani2 - нет.

console.log(5, typeof animate);
console.log(6, typeof ani2);
console.log(7, animate());

Хотя ani2 уже создан, вы можете добавить в него новых членов через animate.prototype.

animate.prototype.bark = function(){ console.log(8, 'bark'); };
ani2.bark();

Однако переменная animate не наследует форму своего прототипа.

console.log(9, typeof ani2.bark);
console.log(10, typeof animate.bark);

Обратите внимание, что ani2 не наследует членов, примененных непосредственно к переменной animate. Он наследуется только от animate.prototype.

animate.paperclip = function(){ console.log(11, "paperclip"); };

animate.paperclip();
console.log(12, typeof ani2.paperclip);
console.log(13, typeof animate.paperclip);

Вы также можете использовать ключевое слово this внутри функции конструктора, например animate, для добавления членов экземпляра в new children.

var Anime = function(a,b){ this.a=a; this.b=b; this.c=console; };
var anime1 = new Anime(14, 'anime1');
var anime2 = new Anime(15, 'anime2');
anime1.c.log(anime1.a, anime1.b);
anime2.c.log(anime2.a, anime2.b);

Anime.prototype.a = 16;
Anime.prototype.z = 'z';

var anime3 = new Anime(17, 'anime3');
anime3.c.log(18, anime3.a, anime3.b, anime3.z, " ", anime2.a, anime2.b, anime2.z, " ", anime1.a, anime1.b, anime1.z);
anime2.z='N';
anime3.c.log(19, anime3.a, anime3.b, anime3.z, " ", anime2.a, anime2.b, anime2.z, " ", anime1.a, anime1.b, anime1.z);

Память была автоматически выделена для отдельного экземпляра anime2.z только потому, что он был изменен, anime1 и anime3 по-прежнему «делят» экономную немодифицированную z.

Члены a, b и c не являются "коммунальными" одинаково. Они были сразу выделены с помощью this в конструкторе, new Anime () , (не унаследовано от Anime.prototype). Кроме того, член a в прототипе всегда будет «индивидуализирован» конструктором.

Никогда не забывайте ключевое слово new , иначе оно не будет работать так, как должно. Например, this указывает на глобальный объект в конструкторе, который вызывается без new .

console.log(20, typeof window.a, typeof window.b, typeof window.c);
var opps = Anime(21, 'zapp');
console.log(22, typeof window.a, typeof window.b, typeof window.c);
console.log(23, typeof opps);

Вот вывод. И секунду за то, что Том предлагает видео Дугласа Крокфорда!


/*
1 animate.angular
2 animate.circular
0 animate
3 animate.prototype.angular
4 animate.prototype.circular
5 function
6 object
0 animate
7 undefined
8 bark
9 function
10 undefined
11 paperclip
12 undefined
13 function
14 anime1
15 anime2
18 17 anime3 z 15 anime2 z 14 anime1 z
19 17 anime3 z 15 anime2 N 14 anime1 z
20 undefined undefined undefined
22 number string object
23 undefined
*/
3 голосов
/ 10 ноября 2009

Несмотря на то, что иногда это так, в JavaScript нет классов, но он работает с прототипами. Вы определяете прототип, затем вы можете создавать копии прототипа.

Начиная с:

var animate=function(){};
animate.angular=function(){/*does something here*/};

Вы можете:

var a = new animate();
animate.angular();       // OK
a.circular();            // error: a.circular is not a function

Однако, если вы начнете с:

function animate(i){};
animate.prototype.angular = function() {};

теперь вы можете

var a = new animate();
a.angular();

конечно, это более интересно, если у вас есть переменные экземпляра.

function animate(i) {
    this.x = i;
}
animate.prototype.angular = function() {
    this.x *= 2;
}

var a = new animate(5);
a.angular();
console.log(a.x);    // 10
2 голосов
/ 10 ноября 2009

ООП на основе прототипов дает вам свободу Classy OOP не дает.

Если вы действительно хотите узнать об этом, как говорили многие, прочитайте объяснения Крокфорда, вы не получите лучшего ресурса, чем этот.

Если вы хотите быстрые выгоды:

var Building = function() {
    this.openDoor = function() {};
};

var House = function() {
    this.closeDoor = function() {};
};
House.prototype = new Building();

var a = new House();
a.openDoor();
a.closeDoor();

Определение объектов (которые будут представлять, какие классы есть в других языках), как это, СЛИШКОМ ОЧЕНЬ противно, поэтому я включу небольшой совет в свой ответ:

Лучший способ построить вашу систему - использовать глобальное пространство имен, выбранное вами, например:

if (typeof MYAPP === 'undefined' || !MYAPP) {
    var MYAPP = {};
}

function New(className, classBody) {
    // This adds your "classes" to this MYAPP namespace so they can be instantiated
    // You need some magic here, so have fun with this function
}

New('Building', function() {
    this.openDoor = function() {};
});

New('House', function() {
    this.prototype = new MYAPP.Building();
    this.closeDoor = function() {};
});

// Now you can do the same as before but your application is cleaner :)
var a = new MYAPP.House();
a.openDoor();
a.closeDoor();

Приветствие.

2 голосов
/ 10 ноября 2009

Если вы можете сэкономить 3 часа времени, я бы посоветовал вам посмотреть видео "Язык программирования JavaScript" от YUI Theatre. Спикер / учитель - Дуглас Крокфорд, и он даст вам твердую основу JS, на которой вы можете строить.

Привет

Tom

2 голосов
/ 10 ноября 2009

Javascript - это странный язык ... очень мощный, но не настолько сильно структурированный по сравнению с другими языками ...

Прототип - это то, как JavaScript позволяет вам экономить память, если вы собираетесь создавать несколько экземпляров класса ... Поэтому, если вы используете JS ООП, вы должны определить свои функции как часть прототипа. Также есть способы симуляции наследования с использованием прототипа.

Я настоятельно рекомендую книгу "Javascript, The Good Parts" для большого количества прекрасных объяснений по этому поводу.

1 голос
/ 10 ноября 2009

Другие уже упоминали Дуглас Крокфорд , проверьте Prototypal Inheritance на его сайте для получения дополнительной информации. Для контраста см. Классическое наследование .

Как и Гандерсон, я также рекомендую (тонкий) книгу Крокфорда JavaScript: Хорошие детали .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...