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, время: 22:25. |