2013-11-18 3 views
0

Я объявил прототип функции A.a, но хотел бы предоставить некоторый синтаксический сахар другими функциями, например. A.sayHi и A.sayBye. Проблема связана с контекстом, потому что я хочу, чтобы он указывал на экземпляр, но не имел к нему доступа, когда я объявляю прототип.Как создать функцию прототипа, которая связывает другую функцию прототипа как синтаксический сахар (и сохранить контекст экземпляра)?

function A() { 
    this.txt = 'so'; 
}; 

A.prototype.a = function (txt) { 
    alert(txt + ' ' + this.txt); 
} 

A.prototype.sayHi = A.prototype.a.bind(A, 'hi'); 

A.prototype.sayBye = A.protoype.a.bind(A.prototype, 'bye'); 

Когда я new A().sayHi().sayBye(); я получаю уведомление с «приветом неопределенного» и «до свидания неопределенного». Конечно, я могу сделать

A.prototype.sayHi = function() { 
    this.a('hi'); 
}; 

но это некрасиво :)

Есть ли способ, что я храню контекст экземпляра (так что this.txt равно «так») без написания функции?

+1

Вы не будете в состоянии сделать это.Проблема в том, что ваш код 'bind' запускается до создания любого экземпляра, поэтому вы никогда не сможете передать правильное значение this. – Matt

ответ

2

Bind - это не то, что вы хотите.

Bind предназначен для создания функции, которая оборачивает в this указатель (который должен существовать, когда Bind называется), чтобы избежать необходимости писать много временных функций, таких как

var that = this; 
callMeBack(function() { that.callback(); }); 

(т.е. выше становится)

callMeBack(this.callback.Bind(this)); 

Он может быть использован для частичного применения/ограниченного выделки, но в вашем случае, если вы не имеете this в точке, которую вы пытаетесь вызвать Bind. Вы определенно не хотите, чтобы либо конструктор, либо его объект-прототип были this, вы хотите, чтобы это был фактический объект, но этого не существует при запуске этого кода.

Ваш последний пример в точности правильный.


Отступление: Я не думаю, что это некрасиво - это понятно, и явное, и очень идиоматических Javascript. Возможно, это многословность. Если вы считаете, что это некрасиво, тогда вы, возможно, еще не используете Javascript. Привыкнуть к функциям в качестве первого класса данных и т.д .:

var A = function() { ... }; 

вместо

function A { ... } 

бывших является то, что означает Javascript последнего. Попадая в привычку думать о функциях как о другом типе данных, вы сможете «получить» Javascript и увидеть его неотъемлемую красоту. И будет иметь побочный эффект, что вы не будете оскорблены «уродливым» при показе при программировании для node.js :)

+0

Это было мое мышление в точности, привязка не работает, потому что она работает только с экземплярами. Я хотел заархивировать A.a, создав A.sayHi, но я думаю, что это невозможно без доступа к контексту (т. Е. Путем создания функции, которая его обертывает). – godspeedelbow

+0

@godspeedelbow Ну, потому что вы можете создавать и возвращать функции по своему желанию, если вы хотите использовать функцию, создающую прототипы, и применяет правильный указатель во время выполнения, когда она доступна, вы можете это написать. Шрайас дает пример этого. Существует очень мало смысла только для одного или двух применений, однако вы можете использовать «уродливый» подход. Но это прекрасно иллюстрирует, насколько мощными локальными функциями и лексической типизацией являются. – Ian

+0

Ответ Shreyas на самом деле не гарантирует, что 'this' имеет правильное значение, это более сложный ответ, чем тот, который дал Гранди. Вы можете гарантировать только значение 'this' при передаче функции как замыкание/использование bind или объявление функции в теле конструктора (me = this; this.sayHi = function() {me.a (" Hi ")}) , – HMR

0

Это работает для вас?

function runtimeContextBinder(func){ 
    var args = Array.prototype.slice.call(arguments, 1); 
return function(){ 
    func.apply(this,args); 
} 
} 

function A() { 
    this.txt = 'so'; 
}; 

A.prototype.a = function (txt) { 
    alert(txt + ' ' + this.txt); 
} 

A.prototype.sayHi = runtimeContextBinder(A.prototype.a,'hi'); 

A.prototype.sayBye = runtimeContextBinder(A.prototype.a, 'bye'); 

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

+0

Вы генерируете ловушку «уродливую» локальную функцию из другой функции :) Приятно мета. – Ian

+1

Да, это сработало бы, но, как сказал Ян, вы создаете закрытие в 'runtimeContextBinder', которое фактически делает то же самое, что и запись функции, но только один раз. Спасибо в любом случае! – godspeedelbow

+0

@Ian Так что же такое 'Function.prototype.bind' делать внутри? – C5H8NNaO4

1

вы можете попробовать небольшое изменение a функции

function A() { 
    this.txt = 'so'; 
}; 

A.prototype.a = function (txt) { 
    return function(){ 
     alert(txt + ' ' + this.txt); 
     return this; 
    } 
} 

A.prototype.sayHi = A.prototype.a("Hi") 

A.prototype.sayBye = A.protoype.a('bye'); 
+0

Прохладный ответ! Настолько эффективно, что мы немного отключили 'A.a', чтобы мы могли это сделать. Недостатком является то, что' A.'' ведет себя по-другому, так что вы почти хотели бы только доступную как частную функцию. – godspeedelbow

+0

Ницца. Вам понадобится еще одна функция, если вы хотите иметь общую версию, если только вы не хотите писать foo.a («Hola»)(); – Ian

+0

Это действительно не связывает функции с экземпляром: 'var a = new A(); var b = {}; b.sayHi = a.sayHi; b.sayHi(); 'this.txt теперь не определено. – HMR

Смежные вопросы