Прототипные практики наследования? - программирование
Подтвердить что ты не робот

Прототипные практики наследования?

Я просто вхожу в JavaScript, и я пытаюсь обернуть голову вокруг прототипального наследования. Похоже, что существует несколько способов достижения такого же эффекта, поэтому я хотел посмотреть, есть ли какие-либо передовые методы или причины делать что-то одностороннее. Вот о чем я говорю:

// Method 1
function Rabbit() {
    this.name = "Hoppy";

    this.hop = function() {
        console.log("I am hopping!");
    }
}

// Method 2
function Rabbit() {}

Rabbit.prototype = {
    name: "Hoppy",

    hop: function() {
        console.log("I am hopping!");
    }
}

// Method 3
function Rabbit() {
    this.name = "Hoppy";
}

Rabbit.prototype.hop = function() {
    console.log("I am hopping!");
}

// Testing code (each method tested with others commented out)
var rabbit = new Rabbit();
console.log("rabbit.name = " + rabbit.name);        
rabbit.hop();

Все они, похоже, имеют одинаковый эффект индивидуально (если только я чего-то не хватает). Так один метод предпочтительнее другого? Как вы это делаете?

4b9b3361

Ответ 1

Когда вы помещаете метод в прототип, каждый экземпляр имеет общую ссылку на метод. Если у вас есть 10 экземпляров, есть одна копия метода.

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

Использование прототипа работает, потому что у javascript есть механизм для связанного выполнения функции с экземпляром, т.е. он устанавливает свойство this для выполнения функции.

Поэтому использование прототипа является очень предпочтительным, поскольку оно использует меньше места (если, конечно, это то, что вы хотите).

В методе 2 вы устанавливаете прототип, устанавливая его равным литералу объекта. Обратите внимание: здесь вы устанавливаете свойство, которое, я думаю, вы не намерены делать, поскольку все экземпляры получат одно и то же свойство.

В методе 3 вы создаете прототип одного задания за раз.

Я предпочитаю метод 3 для всех вещей. т.е. в моем конструкторе я устанавливаю значения свойств

myObj = function(p1){
   this.p1; // every instance will probably have its own value anyway.
}

myObj.prototype.method1 = function(){..} // all instances share the same method, but when invoked  **this** has the right scope.

Ответ 2

Посмотрите на свои примеры по одному. Во-первых:

function Rabbit() {
    this.name = "Hoppy";

    this.hop = function() { //Every instance gets a copy of this method...
        console.log("I am hopping!");
    }
}
var rabbit = new Rabbit();

Вышеприведенный код будет работать, как вы сказали в своем вопросе. Он создаст новый экземпляр класса Rabbit. Каждый раз, когда вы создаете экземпляр, копия метода hop будет храниться в памяти для этого экземпляра.

Второй пример выглядел так:

function Rabbit() {}

Rabbit.prototype = {
    name: "Hoppy",

    hop: function() { //Now every instance shares this method :)
        console.log("I am hopping!");
    }
}
var rabbit = new Rabbit();

На этот раз каждый экземпляр Rabbit поделится копией метода hop. Это намного лучше, поскольку использует меньше памяти. Однако каждый Rabbit будет иметь одно и то же имя (если вы не затенете свойство name в конструкторе). Это связано с тем, что метод наследуется от prototype. В JavaScript, когда вы пытаетесь получить доступ к свойству объекта, это свойство сначала будет искать на самом объекте. Если он там не найден, мы рассмотрим prototype (и т.д. Вверх по цепочке прототипов, пока не достигнем объекта, чье свойство prototype null).

Ваш третий пример - это в значительной степени то, как я это сделал. Методы, разделяемые между экземплярами, должны быть объявлены на prototype. Свойства, такие как name, которые вы можете захотеть установить в конструкторе, могут быть объявлены на основе каждого экземпляра:

function Rabbit(rabbitName) {
    this.name = rabbitName;
}
Rabbit.prototype.hop = function() {
    console.log("Hopping!");
}

Ответ 3

Это важный вопрос, который часто неправильно понимается. Это зависит от того, что вы пытаетесь сделать. Вообще говоря, hvgotcode ответ прямо. Любой объект, который будет создаваться часто, должен присоединить методы и свойства к прототипу.

Но у других есть свои преимущества в очень специфических ситуациях. Прочтите это, включая комментарии: http://net.tutsplus.com/tutorials/javascript-ajax/stop-nesting-functions-but-not-all-of-them/

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

Некоторые разработчики используют еще одну хорошую стратегию, которая пытается уловить некоторые недостатки других. То есть:

var Obj = function() {
    var private_read_only = 'value';

    return {
        method1: function() {},
        method2: function() {}
    };
};

Ответ 4

// option 4
var Rabbit {
    constructor: function () {
        this.name = "Hoppy";
        return this;
    },

    hop: function() {
        console.log("I am hopping!");
    }
};

var rabbit = Object.create(Rabbit).constructor();
console.log("rabbit.name = " + rabbit.name);        
rabbit.hop();

При выполнении прототипического OO с использованием new и функций конструктора полностью необязательно.

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

Однако вполне приемлемым вариантом было бы

function Rabbit() {
    // for some value of extend https://gist.github.com/1441105
    var r = extend({}, Rabbit);
    r.name = "Hoppy";
    return r;
}

Здесь ваши расширяющиеся "экземпляры" со свойствами "prototype". Единственное преимущество, которое имеет реальное прототипное ОО, заключается в том, что он представляет собой живую ссылку, что означает, что изменения прототипа отражают все экземпляры.

Ответ 5

Проведите некоторое тестирование производительности (объявите около 1 миллион переменных кролика). Первым методом будет наибольшее время и память.