Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   self = this в обертке Class (https://javascript.ru/forum/misc/33228-self-%3D-v-obertke-class.html)

bFree 14.11.2012 19:05

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 меняет свое значение.

Может быть есть решение проблемы? Заранее благодарен

melky 14.11.2012 19:21

а чем то self внутри мешать начало ?

OctoberTide 14.11.2012 19:24

модифицируйте функцию Class, так чтобы она это делала автоматом. Или я что-то не понял?

bFree 14.11.2012 19:26

Цитата:

а чем то self внутри мешать начало ?
Не очень понял, что имелось в виду

melky 14.11.2012 19:28

Цитата:

Сообщение от bFree
Не очень понял, что имелось в виду

т.е. в чём вопрос топика? похоже, что не я один не понял, в чём заключается проблема

DjDiablo 14.11.2012 19:39

а какие пробемы ?
this будет указывать на класс, если ты боишся потерять this внутри метода, тогда сохраняй его в методе в самом начале.

test=class({
    hello:function(){
        var self=this;

        setTimeout(function(){      
                //здесь this мы потеряли, на класс он больше не указывает
                // зато доступен self !!!!
                self.world("hello");
        },1000) ;
    },

    world:function(text){
          alert(text+"world")
    }

})

vadim5june 14.11.2012 19:46

надо посмотреть на обертку Class чтобы разобраться
а чем Вам эта обертка понравилась?

bFree 14.11.2012 19:46

Вот именно прописывать в каждом методе var self = this я совершенно не хочу. А придется это делать очень часто, т.к. постоянно работаю с jquery и другими фреймворками. Получается типа:

this.someAction = function() {};

this.method = function() {
    this.someAnotherMethod({
        onSuccess: function() {
            this.someAction(); // не будет работать, т.к. this указывает не на объект, в котором лежит внешний метод.
            self.someAction(); // раньше работало, а при использовании Class - нет.
        }
    });
};

bFree 14.11.2012 19:49

Обертка вот:

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;
}

vadim5june 14.11.2012 19:52

Цитата:

Сообщение от bFree
Обертка вот:

это maximaximus что писал-пусть сам с ней и разбирается

DjDiablo 14.11.2012 19:58

Видите ли мой друг.


всех кто не хочет прописывать self в каждой функции кидают в бездонную яму. Кстатии зачем в каждой ?
Прописывайте только там где сочтёте это нужным.

Раньше когда вы использывали self у вас было замыкание и переменная хранилась в нём, а сейчас замыкания нет и self хранить негде.

максимум что можно, это передавать self в параметре, каждой фнкции.

Просто смеритесь, вы обречены :D

bFree 14.11.2012 20:08

В итоге получается, что JS требует постоянного написания одинакового кода, который явно излишен. Печалька.

Если прописывать прямо в методах, то получаем дополнительный мусор в коде.

Кажется, этот вопрос решили в Coffeescript

melky 14.11.2012 21:02

Цитата:

Сообщение от bFree
А придется это делать очень часто, т.к. постоянно работаю с jquery и другими фреймворками.

в jQuery почти везде можно передать контекст исполнения для обработчика ($.ajax точно, как помню)

bFree 14.11.2012 21:53

Нет. Просто хочу, чтобы можно было в коллбеках использовать указатель на объект безо всяких .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
   }
}

А если таких методов у меня в классе много? Я не хочу в каждом таком месте писать одинаковую строчку.

bFree 14.11.2012 21:58

iMaxmaxmaximus, я тебя понял. Замыкания действительно нет и self хранить негде.

Очень-очень жаль. Не люблю раздувать код одинаковыми конструкциями..
В coffescript это решено на уровне синтаксиса:
Код:

onClick: () ->
  // bla-bla-bla

bindEvent: () ->
  $("some element").on "click" (e) => // => как раз позволяет передать this
    @onClick()

И из этого кофескрипт как раз соберет то, что я не хочу писать руками: var _this = this;

bFree 14.11.2012 22:08

Если функция задается через "=>", а не "->", то @ внутри нее будет указывать на тот объект, в котором объявлена эта ф-ция (если правильно выразился)

Получится такое:
this.bindEvent = function() {
   var self = this;
   $("some element").on("click", function(e) {
       self.onClick()
   }
}

DjDiablo 15.11.2012 01:11

bind штука хорошая.
Жаль неработает в ie 8 и более младших.
неработает в андроидах<4й версии
Походу iphone тоже не будет работать, как я понял bind нет даже в последнем safary mobile

я бы пока побрезговал пользоваться.

DjDiablo 15.11.2012 01:47

ну да, так можно попробывать :)

DjDiablo 15.11.2012 02:05

можно немного подругому вызывать попробывать, хотя кривовато конечно.

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)) ;


масло маслянное получается,
но работать вроде должно

DjDiablo 15.11.2012 02:22

а как тебе вот такой прикол ? :D

Function.prototype.bind2=function(self){
          fun=this;
          return function(){
          	fun.apply(self,arguments)
          }
             
        } 
z=function(){ alert(this.x) }.bind2({x:100})
z();


в ие вроде пашет

DjDiablo 15.11.2012 02:41

пол 6го утра, мне сейчас всё кажется прикольным.
всё я баиньки.

nerv_ 15.11.2012 04:01

https://github.com/kriskowal/es5-shim

bFree 15.11.2012 10:02

Цитата:

То есть ты не должен создавать ни какие промежуточные анонимные функции внутри метода addListener. так как это быдлокод.
Не будь таким категоричным. Иногда это необходимо.
Ладно, я вас понял. Если написать bind для ишака, то можно вполне сносно работать.

Спасибо за ответы

bFree 15.11.2012 10:39

iMaxmaxmaximus, само-собой в контексте )
Просто когда по незнанию писал все в конструкторе, то мой способ решал вопрос и я перестал задумываться об этом. Потом вот всплыла эта интересная особенность ecma

tenshi 17.11.2012 18:46

> То есть ты не должен создавать ни какие промежуточные анонимные функции внутри метода addListener. так как это быдлокод.

bind как раз и создаёт "промежуточную анонимную функцию". причём делает это _каждый раз_.

tenshi 17.11.2012 20:56

Цитата:

Сообщение от bFree (Сообщение 216023)
Нет. Просто хочу, чтобы можно было в коллбеках использовать указатель на объект безо всяких .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>

tenshi 17.11.2012 21:02

Цитата:

Сообщение от iMaxmaxmaximus (Сообщение 216410)
это делает бинд, а не ты! ты не должен создавать РУКАМИ промежуточную функцию потому что это смотрится по уебански.

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

melky 17.11.2012 22:09

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

tenshi 17.11.2012 22:27

> че за херь? обрами нормальными тегами [js]

тебе надо - ты и обрамляй)


> разница в красоте кода. какая разница писать очевидным кодом или не очевидным? биндинг функции к контексту это процедура, и она имеет название, она должна быть где-то описана и потмо вызвана. она не должна быть в коде без названия если это конечно не быдлокод, в данном случае мы выносим её в метод бинд.

у тебя биндинг головного мозга) вот я привёл пример кода, куда ты тут всунешь свой bind и зачем?

tenshi 17.11.2012 22:32

ну и дурак)

tenshi 17.11.2012 22:40

да кто бы говорил)

tenshi 17.11.2012 23:51

будущий копипастер растёт)


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