在JavaScript中重新定义方法

时间:2016-01-26 15:03:53

标签: javascript oop design-patterns

首先,抱歉我的英语不好 - 我不是母语人士。

现在,关于问题:

我正在学习JavaScript设计模式,在尝试实现一个更复杂的装饰模式示例时,我意识到我无法修改构造函数中定义的方法,但我可以修改用原型定义的方法。

有人可以向我解释为什么会这样,或者我错过了一些非常重要的事情。

这是模式的代码:

// Basic constructor with one parameter and test method
var ExampleOne = function (param1) {
  this.param1 = param1;
  this.test = function () {
    console.log('Test One');
  }
}
// Adding logParam1 method using prototype
ExampleOne.prototype.logParam1 = function () {
  console.log(this.param1);
}
// Adding testTwo method using prototype
ExampleOne.prototype.testTwo = function () {
  console.log('Prototype Test');
}
// Creating instance of ExampleOne
var example = new ExampleOne('Parameter One');
// Simple decoration
example.decorate = function() {
  console.log('Decoration One');
}
// More complicated decoration
var ExampleTwo = function(param1, param2) {
  ExampleOne.call(this, param1);
  this.param2 = param2;
}
// Creating separate prototype from original one
ExampleTwo.prototype = Object.create(ExampleOne.prototype);
// Trying to change test (defined in constructor)
ExampleTwo.prototype.test = function () {
  console.log('Test Two');
}
// Trying to change logParam1 (defined using prototype)
ExampleTwo.prototype.logParam1 = function () {
  console.log(this.param1 + ' ' + this.param2);
}
// Creating instance
var examplee = new ExampleTwo('Test Two', 'Decoration Two');

// Testing
example.test(); // Expecting: Test One, Returns: Test One
example.testTwo(); // Expecting: Prototype Test, Returns: Prototype Test
example.logParam1(); // Expecting: Parameter One, Returns: Parameter One
example.decorate(); // Expecting: Decoration One, Returns: Decoration One

examplee.test(); // Expecting: Test Two, Return: Test One << WHY?
examplee.testTwo(); // Expecting: Prototype Test, Returns: Prototype Test
examplee.logParam1(); // Expecting: Test Two Decoration Two, Returns: Test Two Decoration Two
// examplee.decorate(); // Expecting: error, Returns: error

日Thnx。

2 个答案:

答案 0 :(得分:3)

function ExampleTwo正在调用ExampleOne.call(this, param1);ExampleTwo作为上下文传递。因此,ExampleOne方法this.test现在指向您的ExampleTwo

因此,使用“new”调用ExampleTwo的每个变量都将拥有一个名为test()的属性函数。这个将在ExampleTwo原型的test()函数之前调用。 Javascript首先查找自己的属性,如果找不到,他会遵循原型链(在这种情况下是ExampleTwo.prototype对象)。

答案 1 :(得分:1)

在处理原型链之前,属性访问器将始终访问对象自己的属性。在你的情况下,对象有一个测试属性输出'测试1',他们的原型有一个输出'测试2'的测试属性,但是obj.test无法直接访问该原型函数,因为测试1来了首先在链中。

您仍然可以访问“测试2”:Object.getPrototypeOf( example ).test();


您仍然可以覆盖原始测试,但它需要基于每个对象而不是原型:

example.test = function () { console.log('Test Two'); }

或者如果你创建了一个子类,你可以在构造函数中覆盖它:

function ExampleFour ( param ) {
    ExampleOne.call( this, param );

     var superTest = this.test;
     this.test = function () {
          console.log( 'In overridden test, about to call Test 1' );
          superTest.call( this );
     };

}

ExampleFour.prototype = Object.create( ExampleOne.prototype );
相关问题