2015-11-13 4 views
1

Я хотел бы переопределить прототип, но при этом использовать оригинальную функцию прототипа. Цель состоит в том, чтобы добавить отладочный код тестового стенда в существующее определение прототипа производства.прототип javascript redefine с использованием существующего прототипа

// production definition 
function tester(n) { this.name = n ; } 
tester.prototype.getName = function() { return this.name; } 

// debug override 
if (typeof tester.prototype.getName === 'function') { 
    var f = tester.prototype.getName; 
    tester.prototype.getName = function() { 
    return f() + " (plus some more)"; 
    }; 
} 

// test 
var tt = new tester('testing'); 
console.log(tt.getName()); // logs ' (plus some more)' but I want 'testing (plus some more)' 

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

Большое спасибо заранее! - Джон :)

+0

Я бы посмотрел на функциональный инструмент, который предлагает возможность _compose_, я думаю, что у lodash есть один. Таким образом, вы можете смешивать и сопоставлять расширенные возможности без ручного кодирования каждого перехвата. – dandavis

ответ

1

Вы должны вызвать f с правильным this значением и правильными аргументами:

f.apply(this, arguments); 

Узнайте больше о this и apply.


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

Но я думаю, вы делаете это только для очень специфических методов.

0

В вашем переопределении вам необходимо установить правильный контекст (this) для функции f, используя Function.prototype.apply(). В вашем коде контекст функции f установлен в глобальную область действия, даже если он вызывается в переопределенном свойстве getName tt. Вместо этого он должен быть контекстом переопределенной функции getName.

// production definition 
function tester(n) { this.name = n ; } 
tester.prototype.getName = function() { return this.name; } 

// debug override 
if (typeof tester.prototype.getName === 'function') { 
    var f = tester.prototype.getName; 
    // Here, 'this' is the global scope (window). 
    console.log('Global scope:'); 
    console.log(this); 
    console.log('f called with context of global scope:'); 
    console.log(f()); // prints 'name' prop of global scope 
    tester.prototype.getName = function() { 
    console.log("Instance:"); 
    console.log(this); 
    // Here, 'this' is tt when tt.getName() is evaluated. 
    // If we call f() here, the context for f 
    // will still be the global scope, instead of tt. 
    // So, we use apply to set the context of f to 
    // an instance of tester. 
    return f.apply(this) + " (plus some more)"; 
    }; 
} 

// test 
var tt = new tester('testing'); 
console.log(tt.getName()); // logs testing (plus some more)' 

http://jsfiddle.net/a27xzqc9/3/

+0

Итак, какое решение вы предлагаете и как оно отличается от моего? –

+0

Это то же самое решение, я считаю. –

+0

Почему вы отправили его тогда? –

0

Расширение Феликса и ответ Патрика с инкапсуляцией, чтобы избежать использования глобальной переменной «F», так как я буду повторно использовать такую ​​структуру в несколько раз.

;(function(){ 
    if (typeof tester.prototype.getName === 'function') { 
    var f = tester.prototype.getName; 
    tester.prototype.getName = function() { 
     return f.apply(this) + " (plus some more)"; 
    }; 
    } 
})(); 
Смежные вопросы