首先,抱歉我的英语不好 - 我不是母语人士。
现在,关于问题:
我正在学习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。
答案 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 );