self = this в обертке Class
Здравствуйте!
В этом (http://javascript.ru/forum/misc/3215...y-i-cikly.html) топике мне посоватовали использовать обертку Class для организации объектов. Мне она понравилась. Очень удобно. Есть одно НО: Раньше я всегда в начале класса писал var self = this и внутри всех методов использовал self вместо this. Например: function A(o) { var self = this; var init = function() { self.setOptions(o); }; this.setOptions = function(o) { self.options = o; }; init(); } var a = new A({test: "foo"}); var b = new A({test: "bar"}); console.log(a.options); // foo console.log(b.options); // bar Теперь я начал использовать обертку Class, которую мне посоветовали. Возникла проблема, которую я затрудняюсь решить: var A = new Class(function() { var self = this; this.__construct__ = function(o) { self.setOptions(o); }; this.setOptions = function(o) { self.options = o; }; }); var a = new A({test: "foo"}); var b = new A({test: "bar"}); console.log(a.options); // bar (должно быть "foo"!) console.log(b.options); // bar Скорее всего я делаю что-то неправильно. Использовать this внутри методов неудобно, т.к. активно используется jquery и различные callback's, внутри которых this меняет свое значение. Может быть есть решение проблемы? Заранее благодарен |
а чем то self внутри мешать начало ?
|
модифицируйте функцию Class, так чтобы она это делала автоматом. Или я что-то не понял?
|
Цитата:
|
Цитата:
|
а какие пробемы ?
this будет указывать на класс, если ты боишся потерять this внутри метода, тогда сохраняй его в методе в самом начале. test=class({ hello:function(){ var self=this; setTimeout(function(){ //здесь this мы потеряли, на класс он больше не указывает // зато доступен self !!!! self.world("hello"); },1000) ; }, world:function(text){ alert(text+"world") } }) |
надо посмотреть на обертку Class чтобы разобраться
а чем Вам эта обертка понравилась? |
Вот именно прописывать в каждом методе var self = this я совершенно не хочу. А придется это делать очень часто, т.к. постоянно работаю с jquery и другими фреймворками. Получается типа:
this.someAction = function() {}; this.method = function() { this.someAnotherMethod({ onSuccess: function() { this.someAction(); // не будет работать, т.к. this указывает не на объект, в котором лежит внешний метод. self.someAction(); // раньше работало, а при использовании Class - нет. } }); }; |
Обертка вот:
function Class( a, b ) { var description = b || a, superClass = b ? a : null, overname = Class.overname || 'super', Constructor = (description.name) ? eval( "(function " + description.name + "(){ if ( this.__construct__ ) return this.__construct__.apply( this, arguments )})" ) : function () { if ( this.__construct__ ) return this.__construct__.apply( this, arguments ) }, Object = function Object() { }; Object.prototype = superClass ? superClass.prototype : Class.prototype; description.prototype = new Object; Constructor.prototype = new description( Constructor, description.prototype ); var obj = Constructor.prototype; for ( var key in obj ) { if ( obj.hasOwnProperty( key ) && obj[key] instanceof Function ) { var parentProperty = description.prototype[key]; if ( parentProperty ) (function ( originalMethod, parentMethod, key ) { obj[key] = function () { var bk = this[overname]; this[overname] = parentMethod; var returns = originalMethod.apply( this, arguments ); if ( bk ) this[overname] = bk; else delete this[overname]; return returns; } })( obj[key], parentProperty, key ) } } Constructor.create = function ( args ) { function Object() { if ( this.__construct__ ) return this.__construct__.apply( this, args ) } Object.prototype = Constructor.prototype; return new Object }; return Constructor; } |
Цитата:
|
Видите ли мой друг.
![]() всех кто не хочет прописывать self в каждой функции кидают в бездонную яму. Кстатии зачем в каждой ? Прописывайте только там где сочтёте это нужным. Раньше когда вы использывали self у вас было замыкание и переменная хранилась в нём, а сейчас замыкания нет и self хранить негде. максимум что можно, это передавать self в параметре, каждой фнкции. Просто смеритесь, вы обречены :D |
В итоге получается, что JS требует постоянного написания одинакового кода, который явно излишен. Печалька.
Если прописывать прямо в методах, то получаем дополнительный мусор в коде. Кажется, этот вопрос решили в Coffeescript |
Цитата:
|
Нет. Просто хочу, чтобы можно было в коллбеках использовать указатель на объект безо всяких .bind и других доп. конструкций.
Пример: this.onClick = function() { // bla-bla-bla } this.bindEvent = function() { $("some element").on("click", function(e) { this.onClick(); // oh noooo!! тут this = объект jquery // чтобы работало, мне нужно перед аттачем евента сделать в методе var self = this и внутри юзать self.onClick } } А если таких методов у меня в классе много? Я не хочу в каждом таком месте писать одинаковую строчку. |
iMaxmaxmaximus, я тебя понял. Замыкания действительно нет и self хранить негде.
Очень-очень жаль. Не люблю раздувать код одинаковыми конструкциями.. В coffescript это решено на уровне синтаксиса: Код:
onClick: () -> |
Если функция задается через "=>", а не "->", то @ внутри нее будет указывать на тот объект, в котором объявлена эта ф-ция (если правильно выразился)
Получится такое: this.bindEvent = function() { var self = this; $("some element").on("click", function(e) { self.onClick() } } |
bind штука хорошая.
Жаль неработает в ie 8 и более младших. неработает в андроидах<4й версии Походу iphone тоже не будет работать, как я понял bind нет даже в последнем safary mobile я бы пока побрезговал пользоваться. |
ну да, так можно попробывать :)
|
можно немного подругому вызывать попробывать, хотя кривовато конечно.
if (typeof Function.prototype.bind=="undefined"){ Function.prototype.bind=function(self,func){ return function(){ func.apply(self,arguments); } } } и юзать $('#element').on('click', this.clickHandler.bind(this,this.clickHandler)) ; масло маслянное получается, но работать вроде должно |
а как тебе вот такой прикол ? :D
Function.prototype.bind2=function(self){ fun=this; return function(){ fun.apply(self,arguments) } } z=function(){ alert(this.x) }.bind2({x:100}) z(); в ие вроде пашет |
пол 6го утра, мне сейчас всё кажется прикольным.
всё я баиньки. |
|
Цитата:
Ладно, я вас понял. Если написать bind для ишака, то можно вполне сносно работать. Спасибо за ответы |
iMaxmaxmaximus, само-собой в контексте )
Просто когда по незнанию писал все в конструкторе, то мой способ решал вопрос и я перестал задумываться об этом. Потом вот всплыла эта интересная особенность ecma |
> То есть ты не должен создавать ни какие промежуточные анонимные функции внутри метода addListener. так как это быдлокод.
bind как раз и создаёт "промежуточную анонимную функцию". причём делает это _каждый раз_. |
Цитата:
<script> function Method( func ){ return function Method_instance( ){ var args= [ this ].concat( [].slice.call( arguments ) ) return func.apply( null, args ) } } function Trait( scheme ){ var trait= function Class_trait( ){ throw new Error( 'Trait can not be instantiate. Create a Class, please.' ) } trait.scheme= scheme return trait } function Class( scheme ){ var factory= function Class_factory( ){ var obj= new Instance var init= obj.Class_init if( init ) init.apply( obj, arguments ) return obj } var proto= factory.prototype factory.scheme= scheme scheme( proto, factory ) var Instance= function Class_Instance( ){ } Instance.prototype= proto for( var key in proto ){ if( !proto.hasOwnProperty( key ) ) continue var value= proto[ key ] if( typeof value === 'function' ) value= Method( value ) proto[ key ]= value } return factory } // проверяем: var Man= Class( function Man_scheme( man, Man ){ Man.toString= function( ){ return 'Man' } man.name= '' man.Class_init= function( man, name ){ man.name= name } man.toString= function( man ){ return 'Man: ' + man.name } }) var Screamer= Trait( function Screamer_scheme( screamer, Screamer ){ screamer.scream= function( screamer ){ alert( screamer + '!' ) } screamer.screamOn= function( screamer, eventName ){ window.addEventListener ( eventName , function( event ){ screamer.scream() } , false ) } }) var Baby= Class( function Children_scheme( baby, Baby ){ Man.scheme.apply( null, arguments ) Screamer.scheme.apply( null, arguments ) Baby.toString= function( ){ return 'Baby' } baby.toString= function( children ){ return 'Baby: ' + children.name } }) var jim= Baby( 'Jim' ) jim.screamOn( 'load' ) </script> |
Цитата:
вот только если использовать в качестве колбэка функцию для этого не предназначенную - будет по уебански работать, что гораздо хуже. а если заводить для колбэка отдельную функцию, то какая разница описывать её методом объекта или замыканием внутри другого метода? |
... и как только топик стартер столкнулся с этим вопросом, он начал постигать функциональную природу JS
|
> че за херь? обрами нормальными тегами [js]
тебе надо - ты и обрамляй) > разница в красоте кода. какая разница писать очевидным кодом или не очевидным? биндинг функции к контексту это процедура, и она имеет название, она должна быть где-то описана и потмо вызвана. она не должна быть в коде без названия если это конечно не быдлокод, в данном случае мы выносим её в метод бинд. у тебя биндинг головного мозга) вот я привёл пример кода, куда ты тут всунешь свой bind и зачем? |
ну и дурак)
|
да кто бы говорил)
|
будущий копипастер растёт)
|
Часовой пояс GMT +3, время: 10:22. |