2016-03-09 3 views
0

У меня возникли проблемы с пониманием. Я искал какое-то время о различиях, но я не могу найти ответ, который я ищу.Непонимание создания OOP Javascript

Я пытаюсь изучить Javascript ООП, и каждый учебник, который я читал, кажется, отличается от способа наследования, и его часто объясняют очень сложным образом. Проблема, с которой я сейчас сталкиваюсь, связана с созданием методов для объекта, я использую код из документации разработчика Mozilla.

Вы увидите в большом блоке кода ниже, что я пытался добавить метод jump в Person, как это:

Person.prototype = { 
    jump: function() { 
    console.log("Jumping") 
    } 
} 

Это не работает она в основном разбивает весь класс говорит мне, что student1.walk является не является функцией. Однако, если я изменю объявление метода на

Person.prototype.jump = function() { 
    console.log("Jumping"); 
} 

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

var Person = function(firstName) { 
     this.firstName = firstName; 
    }; 

    Person.prototype.walk = function(){ 
     console.log("I am walking!"); 
    }; 

    Person.prototype = { 
     jump: function() { 
     console.log("Jumping"); 
     } 
    } 

    Person.prototype.sayHello = function(){ 
     console.log("Hello, I'm " + this.firstName); 
    }; 

    function Student(firstName, subject) { 

     Person.call(this, firstName); 

     this.subject = subject; 
    } 

    Student.prototype = Object.create(Person.prototype); // See note below 

    Student.prototype.constructor = Student; 

    Student.prototype.sayHello = function(){ 
     console.log("Hello, I'm " + this.firstName + ". I'm studying " 
        + this.subject + "."); 
    }; 

    Student.prototype.sayGoodBye = function(){ 
     console.log("Goodbye!"); 
    }; 

    var student1 = new Student("Janet", "Applied Physics"); 
    student1.sayHello(); 
    student1.walk(); 
    student1.sayGoodBye(); 
    student1.jump(); 
+1

'Person.prototype = {...}' переопределяет прототип. Вы можете сделать 'Object.assign (Person.prototype, {...})' – elclanrs

+0

Вместо того, чтобы новый объект вводить в 'prototype', вы должны назначить новый метод в вашем случае' jump' –

ответ

3

Просто сравните два заявления:

Person.prototype = { 
    jump: function() { 
    console.log("Jumping"); 
    } 
}; 

Здесь вы устанавливаете прототип нового литерала объекта. В следующем заявлении:

Person.prototype.jump = function() { 
    console.log("Jumping"); 
}; 

Вы устанавливаете свойство перехода прототипа функции.

Если вы хотите, чтобы добавить все функции сразу, объявить прототип однажды:

Person.prototype = { 
    jump: function() { 
    console.log("Jumping") 
    }, 
    walk: function(){ 
    console.log("I am walking!"); 
    }, 
    sayHello: function(){ 
    console.log("Hello, I'm " + this.firstName); 
    } 
}; 

Разница между ними просто вопрос, когда метод добавляется к прототипу. Обычно я предпочитаю добавлять все свои функции к прототипу сразу, так что я знаю, где в коде я сделал метод sayHello. Иногда я использую второй метод, если мне нужно переопределить метод в свете новой информации. Но это очень редко.

+0

В вашем примере это. firstName' не определено. Убедитесь, что вы включили локальные переменные! –

+0

Мех, поэтому он записывает '' Привет, я не определился ''... Это не так уж далеко;) –

7

Вопрос заключается в том, что вы перекрывая всю цепочку прототипов, вызвав Person.prototype = {}. Это заставляет другие методы исчезать, потому что они были выведены из цепи, сбросив его.

Это, как и любой другой переменной

let x = 5; //5 
x = 6; // 6 

Это простой оператор присваивания повторного назначения вашей цепочки прототипов.

2

Никогда не заменяйте конструктор prototype на другой объект, если вы не знаете, что делаете.

Она имеет следующие проблемы:

  • экземпляры, созданные до изменения больше не будут рассматриваться случаи по instanceof, и они не будут наследовать свойства от нового объекта.
  • Экземпляры, созданные после изменения, не наследуют свойства от старого объекта.
  • Старый объект может иметь некоторые данные, которые вы явно не задали, например. a constructor или внутренний [[Prototype]]. Это будет потеряно, если вы не скопируете его на новый объект.

Если вы просто хотите добавить несколько свойств к prototype, не повторяя его каждый раз, используйте Object.assign:

Object.assign(Person.prototype, { 
    jump: function() { 
    console.log("Jumping"); 
    }, 
    sayHello = function(){ 
    console.log("Hello, I'm " + this.firstName); 
    } 
}); 
+0

Просто хочу уточнить. 'prototype' и [' instanceof'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) не имеет ничего подобного. 'instanceof' работает с' constructor' не с 'prototype' –

+0

@ [' instanceof'] (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.6) использует [\ [\ [HasInstance \] \]] (http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.3), который проверяет, наследует ли объект от «прототипа» конструктора , 'constructor' вообще не задействован. – Oriol

+0

yeap my typo, я имел в виду 'prototype.constructor'. благодаря –

1

ООП в JavaScript некрасиво смотреть. Я бы использовал библиотеку классов, такую ​​как ds.oop. Это похоже на prototype.js и другие. делает многократное наследование очень легким и минималистичным. (только 2 или 3 kb) Также поддерживает некоторые другие опрятные функции, такие как интерфейсы и инъекции зависимостей

/*** multiple inheritance example ***********************************/ 

var Runner = ds.class({ 
    run: function() { console.log('I am running...'); } 
}); 

var Walker = ds.class({ 
    walk: function() { console.log('I am walking...'); } 
}); 

var Person = ds.class({ 
    inherits: [Runner, Walker], 
    eat: function() { console.log('I am eating...'); } 
}); 

var person = new Person(); 

person.run(); 
person.walk(); 
person.eat();