2013-12-17 4 views
1

Я знаю немного C#, и теперь я начал работать с JavaScript, и у меня возникли проблемы с пониманием основ.Необходимое фундаментальное разъяснение Javascript

Вот мой пример кода:

function BaseFunc(x, y) { 
    this.X = x; 
    this.Y = y; 
} 

function DerivedFunc(x, y, z) { 
    this.Z = z; 
    BaseFunc.call(this, x, y); 
} 

DerivedFunc.prototype = new BaseFunc; 


function Test() { 
    var d = DerivedFunc(1, 2, 3); 
    var b = new BaseFunc(4, 5); 
    d.sayHello(); 
    b.sayHello(); 
} 

DerivedFunc.prototype.sayHello = function() { 
    alert("Result is: " + (this.X + this.Y + this.Z)); 
} 

В приведенном выше коде я пытаюсь сделать наследование.

Все выглядит хорошо, пока я не достиг линии BaseFunc.call(this, x, y); Эта линия должна вызывать базовую функцию, но в этом контексте используется this. Это только для удовлетворения подписи метода call, как это работает?

Второй вопрос: в javascript мы можем добавить что-нибудь динамически, В моем случае я добавляю свойство sayHello() и назначаю его анонимной функцией. как DerivedFunc.prototype.sayHello, я добавляю свойство/метод к BaseFunc или DerivedFunc, так как он добавлен к прототипу, он должен быть добавлен в BaseFunc, насколько я понимаю. Но когда я выполняю вышеуказанный код, я получаю ошибку, которая не определена. sayHello.

Может кто-то прояснить меня о том, что происходит не так, спасибо?

+0

'вар D = DerivedFunc (1, 2, 3);' Это одна из причин [Дуглас Крокфорд] (HTTP: // Javascript .crockford.com /) против использования «класса» в JavaScript в его [книге] (http://www.amazon.com/exec/obidos/ASIN/0596517742/wrrrldwideweb): это синтаксис правильный, ошибка не возникла, но вы не можете получить то, что хотите. Вы можете на самом деле означать «var d = новый DerivedFunc (1, 2, 3)». – Passerby

+0

@Passerby: Есть миллион ошибок программирования, которые синтаксически правильны и не вызывают ошибок, но которые не делают то, что планировал программист. Я не знаю, почему люди так одержимы этим, это не хуже других. –

+0

Возможно, вам будет полезно прочитать статью [MDN об объектно-ориентированном JavaScript] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript). –

ответ

1

Все выглядит хорошо, пока не достиг линии BaseFunc.call (это, x, y); эта линия должна вызывать базовую функцию, но в чем ее смысл использовать в этом контексте.

Это там так, что внутри вызова BaseFunc, this имеет такое же значение, которое он имеет в вызове DerivedFunc, так что линии this.X = x; и такие в BaseFunc назначают на правильный экземпляр. (Вызов функции настройки определенного значения для this является то, что .call и .apply методы функций делает.)

Но когда я выполняю приведенный выше код я получаю ошибку, что SayHello не определена.

Если это d.sayHello, где вы испытываете тревогу, это потому, что вы пропустили оператора new на линии d = DerivedFunc(1, 2, 3);. Начиная с DerivedFunc, когда вызывается только как функция, а не через new, не имеет никакого возвращаемого значения, d будет undefined.


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

DerivedFunc.prototype = new BaseFunc; 

Вы пытаетесь использовать функцию, предназначенную для создания экземпляров, и который принимает аргументы для того, чтобы создать экземпляр прототипа, который DerivedFunc присвоит к вещам. Что же тогда должно делать BaseFunc о тех аргументах, которые отсутствуют? Затем вы снова вызываете его (от DerivedFunc) для инициализации экземпляра. BaseFunc делает двойной долг.

Вот как исправить это, сначала многословно версия:

function x() { } 
x.prototype = BaseFunc.prototype; 
DerivedFunc.prototype = new x; 
DerivedFunc.prototype.constructor = DerivedFunc; 

Или, если вы можете рассчитывать на ES5-х Object.create:

DerivedFunc.prototype = Object.create(BaseFunc.prototype); 
DerivedFunc.prototype.constructor = DerivedFunc; 

Теперь мы не призываем BaseFunc, чтобы создать прототип, но мы все еще получаем его объект prototype в качестве базового прототипа объекта DerivedFuncprototype. У нас больше нет проблемы с тем, что делать с аргументами BaseFunc, а BaseFunc вызывается только так, как он предназначен для вызова: инициализировать отдельные экземпляры, а не прототипы.

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

Если вы заинтересованы в JavaScript иерархии наследования, вы можете захотеть взглянуть на мой короткий Lineage сценарий   — не обязательно использовать, но чтобы понять, как эти вещи работают. page showing how to do things without the script и сравнение их со сценарием могут быть особенно полезными.

+0

Crowder: Спасибо, сэр за ур ответ Я положил новый, и он работает на Derived, но почему я не могу call sayHello на BaseFunc, так как я добавил его, сказав Derived.prototype.sayHello? – ShrShr

+0

@ShrShr: потому что вы не добавили его в 'BaseFunc.prototype', который является объектом, назначенным в качестве прототипа экземпляров, созданных с помощью' new BaseFunc'. Вместо этого вы назначили его «DerivedFunc.prototype», поэтому он доступен только для экземпляров, созданных с использованием * этого * в качестве своего прототипа (созданного в этом случае с помощью «нового DerivedFunc»). В то время как 'DerivedFunc.prototype' использует в качестве своего прототипа' BaseFunc.prototype', это отдельные объекты, добавление свойств в 'DerivedFunc.prototype' не влияет на' BaseFunc.prototype'. –

0

Привет, пожалуйста, просмотрите следующее. Я надеюсь, что это даст вам некоторое представление о вызове и наследования()

<script type="text/javascript"> 

    //inheritence 
    function parent() { 
     this.add = function (a, b) { 
      return a + b; 
     } 
     this.subtract = function (a, b) { 
      return a - b; 
     } 
    } 

    function child() { 
     this.display = function() { 
      alert(this.add(11, 23)); 
     } 
    } 

    child.prototype = new parent();   //child extends parent.... inheritence 
    child.prototype.constructor = child; //resetting constructor property 

    var obj = new child(); 
    obj.display(); 

    /* 
    .call() and .apply() 
    They allow our objects to borrow methods from other objects and invoke them as their own 
    */ 
    var person = { 
     name: 'Kundan', 
     display: function(name) { 
      alert(this.name + ' welcomes ' + name); 
     } 
    }; 

    person.display('Dipa'); //Kundan welcomes Dipa 

    var person1 = { name: 'Java Master' }; 
    person.display.call(person1, 'Sachin'); //Java Master welcomes Sachin 
    //here person1 object is passed in the call function 
    //if we are using call inside a function and want to pass the same function object then this is passed in call function 
    /* 
    We can pass more parameters as follows 

    person.display.call(person1, 'a', 'b', 'c'); 

    The method apply() works the same way as call() but with the difference that all parameters you want to pass to the method of the other object are passed as an array. 
    */ 
     person.display.apply(person1, ['a', 'b', 'c']); 



</script> 
Смежные вопросы