2012-05-10 2 views
5

Я ищу, чтобы иметь возможность расширить прототип функции в javascript (то есть добавить функцию ко всем функциям). Цель состоит в том, чтобы преобразовать его в формат для обмена между другим языком (а именно рубином, который может общаться только через строки [в этой конкретной настройке]). У меня уже есть система, так что я могу обойти другие тип путем определения to_js метода на объектах рубина и метода на яваскрипт объектах to_ruby, как иРасширение функции prototype

Number.prototype.to_ruby = function() { return this.toString(); } 

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

_empty = function() {}; 
_empty.__proto__.to_ruby = function() { 
    return 'JSFunction.new(' + this.toString().to_ruby() + ')'; 
}; 

Но это не работает в IE (что является требованием системы).

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

Все остальное неудача я мог бы просто написать функцию частного случая сделку с ним (т.е. isFunction(instance) ? fn_to_ruby(instance) : instance.to_ruby(), но я предпочел бы сохранить эту модель, если это возможно.

+0

Hah! Я просто смотрю в одно и то же. SketchUp Ruby <-> Мост JavaScript. : D – thomthom

ответ

2

__proto__ не является стандартным. Попробуйте этот подход:

(function(){}).constructor.prototype.to_ruby = function(){ 
    return 'JSFunction.new(' + this.toString().to_ruby() + ')'; 
}; 
+0

Ах! Добавление '.constructor' дает мне функциональность, которую я искал - спасибо! – DanielB

+2

Вы должны получить персонаж. '(function() {}). constructor.prototype' - это просто' Function.prototype'. И вызов 'someObj.to_ruby()' будет идентичен '' "+ someObj' – RobG

+0

@RobG, вы правы - и, конечно, теперь, когда я вижу это, это имеет смысл. спасибо :) – DanielB

-1

__proto__ не является частью какого-либо стандарта JavaScript это просто pesudo-стандарт, некоторые производители браузеров решили реализовать. IE является тот, который не реализовали.

Если вы хотите изменить любой типа в системе типов JavaScript, то вы будете иметь для изменения прототипа Object:

Object.prototype.foo = function() { console.log('foo'); }; 
(1).foo(); 
'asd'.foo(); 
(true).foo(); 
({ bar: 'baz' }).foo(); 
3

Как сказал выключатель, вы можете добавить метод ко всем объектам, добавив его в Object.prototype, но это на самом деле не кошерно, как это может повлиять на плохо написанный for..in петель.

Вы можете добавить его только к функциям через Function.prototype:

Function.prototype.to_ruby = function() { 
    return this.toString(); 
} 

Однако существует общее правило, которое вы не должны изменять встроенные объекты, в основном, потому что вы никогда не знаете, когда он вернется, чтобы преследовать вы (например, новая версия ECMAScript реализует свойство с тем же именем). Может быть, вам лучше написать один toRuby функции:

function toRuby(obj) { 
    return obj.toString(); 
} 

, но вы также можете использовать оператор + для конкатенации со строкой для вызова toString метода неявно:

'' + obj; // returns obj.toString() 

который будет возвращать точно такой же результат, как и выше. Твой выбор.

+0

Я понимаю ваш аргумент, но у меня есть несколько разных типов объектов, которые все нужно возвращать немного по-другому. Таким образом, это будет работать для базовых типов, таких как числа и строки (при условии, что их не нужно экранировать), но для массивов, хэш-подобных объектов и пользовательских типов мне пришлось бы писать специальный случай для каждого и продолжать редактировать что, поскольку я требую более или менее объектов. – DanielB

+0

В этом случае вы можете написать одну функцию 'toRuby()' и сообщить ей, как преобразовать переданный объект, например. 'toRuby (someFn, 'fn')', 'toRuby (someObj, 'obj')' или аналогичный. – RobG

+0

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

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