Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Безопасный Monkey Patching (https://javascript.ru/forum/misc/51032-bezopasnyjj-monkey-patching.html)

terminator-101 21.10.2014 19:14

Безопасный Monkey Patching
 
Сейчас в JS считается дурным тоном расширение прототипов, особенно нативных объектов. ИМХО, это связано с одной стороны, тем, что в JS приходит много народу из статических языков, которые просто не понимают профита, с другой — вопросами оптимизации. Где то читал, что Во времена расцвета Prototype.js это наоборот считалось Best Practice. Да и в руби, например, вроде от него нос не воротят. Ну ладно, времена меняются.

Я тут подумал, а почему бы не сделать вот так
show=function(x){console.log(x); return x}
Object.prototype.call=function(f){return f(this.valueOf())}

// Примеры использования
"foo".call(show)
"foo bar baz".split(" ").call(show)
;({one: 1, two: 2}).call(show)
;({one: 1, two: 2}).call(function(o){for(var i in o){show(o[i])}})

//  foo
//  [ 'foo', 'bar', 'baz' ]
//  { one: 1, two: 2 }
//  1
//  2

Так мы получаем почти то же самое, правда с ущербным синтаксисом через жопу вызова, типа колбеков, но избавляемся от претензий статик-клоунов по-поводу неожиданных эффектов, т.к. главный объект расширен единственным методом. А уже на основе этого можно делать любые обертки. call можно сделать enumerable=false, если чо.

Octane 21.10.2014 20:19

А смысл твоего метода call, если того же результата можно добиться написав по-человечески:
function show(x) {
    console.log(x);
    return x;
}

show("foo");

show("foo bar baz".split(" "));

show({
    one: 1,
    two: 2
});

(function (o) {
    for (var i in o) {
        show(o[i])
    }
})({
    one: 1,
    two: 2
});

//  foo
//  [ 'foo', 'bar', 'baz' ]
//  { one: 1, two: 2 }
//  1
//  2
?

terminator-101 21.10.2014 20:30

Octane,
Смысл в том, что когда у тебя получается вот такая вот хрень а1(... a2(...a3(....a4(....)))) гораздо легче это писать в объектном стиле a1.a2.a3.a4. Дело даже не в записи как таковой, а в том, что ты запариваешься куда какие параметры передавать. В данном случае, явная передача объекта проще.

kobezzza 22.10.2014 15:20

Не расширяй никогда Object.prototype, а остальные прототипы можно, но аккуратно.

Пример из личного опыта:

Object.prototype.get = function () { ... };


Потом где то в коде была функция:

function foo(params) {
    params = params || {};
    params.get = params.get || '*'; // И тут всё ломается
}

terminator-101 22.10.2014 15:39

Цитата:

Сообщение от kobezzza
И тут всё ломается

А что у тебя сломалось, я не понял?

kobezzza 22.10.2014 18:21

Цитата:

Сообщение от terminator-101 (Сообщение 336942)
А что у тебя сломалось, я не понял?

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

params.get = params.get || '*';


Т.е. вместо значения по умолчанию мы получаем ссылку на значение из прототипа и всё ломается.

danik.js 22.10.2014 19:01

Цитата:

Сообщение от kobezzza
Не расширяй никогда Object.prototype

Да что там, бывает что встроенные свойства малину портят.
Благо, есть Object.create(null), но все равно бесит.

terminator-101 22.10.2014 19:16

kobezzza,
Ну, если ты сам расширял, ты должен был, наверное помнить,об этом. Это называется не "ломается", а "ошибся". И это может произойти не только с расширением Object, но и вообще с чем угодно. Это стандартная хрень
proto={get_: function(){}}
O=function(){}
O.prototype=proto

o1=Object.create(proto)
o2=new O


function foo(params){
   params=params||{}
   params.get_=params.get_||"*"
}


foo(o1)
foo(o2)
alert([o1.get_, o2.get_]) //

То есть, это произошло бы и в случае расширения String, Regexp и пр, равно как и в случае созданного ненативного объекта. Тут дело не в бобине, какбы.

kobezzza 22.10.2014 19:21

terminator-101, в данном случая я "забыл", но такую багу очень легко поймать путём подключения сторонней библиотеки.

Цитата:

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

Цитата:

И это может произойти не только с расширением Object, но и вообще с чем угодно.
Может, но с Object.prototype шанс словить такую багу близится к 100%, если только не городить свои неймспейсы, но это будет бред.


Часовой пояс GMT +3, время: 20:19.