This that self javascript

Difference between this and self in JavaScript

Everyone is aware of this in javascript, but there are also instances of self encountered in the wild, such as here So, what is the difference between this and self in JavaScript?

@dystroy: There is one: window.self ( === window ). Though the OP probably means a trivial variable name…

@dystroy: Actually I didn’t think he could really mean it, but indeed in global scope (and a browser environment) this === self is true 🙂

Subjective aside: aliasing this to self is not a great practice nowadays when it’s common to have code with many (well, more than one is bad enough) levels of callback nesting, as a consequence of asynchronous programming. Use a more descriptive name instead. Objectively speaking the name this itself carries no information and is only a nonbad choice of name because the lexical context of a class definition qualifies it.

5 Answers 5

Unless set elsewhere, the value of self is window because JavaScript lets you access any property x of window as simply x , instead of window.x . Therefore, self is really window.self , which is different to this .

If you’re using a function that is executed in the global scope and is not in strict mode, this defaults to window , and therefore

function foo() < console.log( window.self === window, // is self window? window.self === this, // is self this? this === window // is this window? ); >foo(); // true true true 

If you’re using a function in a different context, this will refer to that context, but self will still be window .

// invoke foo with context <> foo.call(<>); // true false false 

For completeness, self is useful in context of WebWorker when window is not accessible (developer.mozilla.org/en-US/docs/Web/Guide/Performance/…). Using self instead of window lets you access the global object in a portable way.

Читайте также:  Css select with 2 classes

A slight addition to this as people may encounter this in the context of service workers, in which case it means something slightly different.

You might see this in a service worker module:

self.addEventListener('install', function(e) < console.log('[ServiceWorker] Install'); >); 

Here self refers to the WorkerGlobalScope, and this is the standard method for setting event listeners.

By using self, you can refer to the global scope in a way that will work not only in a window context (self will resolve to window.self) but also in a worker context (self will then resolve to WorkerGlobalScope.self).

Although I am late here but I came across one example which too can be helpful to understand this further:

var myObject = < foo: "bar", func: function() < var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); (function() < console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo mt24">
)" data-controller="se-share-sheet" data-se-share-sheet-title="Share a link to this answer" data-se-share-sheet-subtitle="" data-se-share-sheet-post-type="answer" data-se-share-sheet-social="facebook twitter devto" data-se-share-sheet-location="2" data-se-share-sheet-license-url="https%3a%2f%2fcreativecommons.org%2flicenses%2fby-sa%2f3.0%2f" data-se-share-sheet-license-name="CC BY-SA 3.0" data-s-popover-placement="bottom-start">Share
)" title="">Improve this answer
)">edited Apr 18, 2017 at 12:04
answered Jul 24, 2016 at 6:14
1
  • 1
    this is always defined in its context. What is undefined is this.foo. That's a huge difference and to achieve the behavior you mentioned existed before ECMA 5, arrow functions can be used or as you specified assigning self to be this outside of the inner function and using self inside instead of this, the cleaner way being the arrow function.
    – Dejazmach
    Apr 17, 2020 at 20:45
Add a comment|
3

The reference to ECMA 5 needs clarifying.

I assume it means ECMA-262 Edition 5. It should be noted that ECMA-262 (a.k.a. ECMAScript or, less accurately, Javascript) is a general scripting language which has been implemented in Internet Browsers. From the Edition 5.1 standard:

The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:

  1. If the function code is strict code, set the ThisBinding to thisArg.
  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
  3. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
  4. Else set the ThisBinding to thisArg
  5. . (not about "this")

The term "global object" refers to whatever object is at the top of the scope chain. For browsers this would be the "window" object but this is an implementation choice (Windows Script Host has an invisible global object but no strict mode so unqualified references access its properties and there is no global "self"). Also, "strict mode" must be explicitly enabled otherwise it is not active (section 14.1 of the standard). As such, an undefined "this" would still resolve to the global object (window) in "ECMA 5" with strict mode not active.

So the answer to the question is:

"this" always refers to the object invoking the function. If the function was not invoked by an object (i.e. not a method call) then "this" (as passed to the function) is "undefined". However, if NOT using strict mode then an undefined "this" is set to the global object (rule 2 above).

"self" has no special syntactic meaning, it is just an identifier. Browsers tend to define window.self (just a property of the global window object) = window. This results in unqualified references to "self" being the same as "window" UNLESS "self" has been redefined within an enclosing scope (such as by "var self = this;" above. Good luck redefining "this".)

So the full explanation of the example above is:

outer func: this.foo = bar // "this" refers to the invoking object "myObject" outer func: self.foo = bar // "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject" inner func: this.foo = undefined // "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined. inner func: self.foo = bar // self resolves to the variable in the enclosing scope which is still "myObject"

An interesting variation of the example creates a closure by returning a reference to the inner function.

var myObject = < foo: "bar", func: function() < var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); return function() < console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo = " + self.foo); >; > >; var yourObject = < foo: "blat", func: myObject.func() // function call not function object >; console.log("----"); yourObject.func(); 
outer func: this.foo = bar outer func: self.foo = bar ---- inner func: this.foo = blat inner func: self.foo = bar 

Note how the inner function is not called until invoked by yourObject. So this.foo is now yourObject.foo but self still resolves to the variable in the enclosing scope which, at the time the inner function object was returned, was (and in the resulting closure still is) myObject. So, within the inner function, "this" refers to the object calling the inner function while "self" refers to the object which called the outer function to create the reference to the inner function.

To summarize the summary of the summary, "this" is defined by the language standard, "self" is defined by whoever defines it (runtime implementer or end programmer).

Источник

Правильный захват контекста в Javascript

Довольно часто во многих статьях я вижу, как люди захватывают контекст this для использования в анонимной функции и удивляюсь — то, что уже стало стандартом — просто ужасная практика, которая противоречит всем канонам программирования. Вам знакома такая запись?
var self = this ;
Может вам тоже стоит переосмыслить этот аспект?

Итак, пример:

$( 'input' ). bind ( 'keydown' , function () var $this = $( this );
$this . css ( background : $this . val ()
>);
>);

Ненависть

Я считаю, что в названиях переменных self и $this (а также that, _this, t) кроется зло. Зло кроется по двум причинам.
Первая — названия совершенно не несут смысловой нагрузки. Таким же чудом мы могли бы использовать, скажем var killmeplz = this ;
Вторая — иногда контексты могут множиться и пересекаться и тогда настаёт путаница. Например, когда функции у нас вложены одна в другую:

var self = this ;
asyncFunc (function () var self2 = this ; // wtf .
setTimeout (function () self . callMethod ( self2 );
>, 200 );
>);

Решение первое — правильно именуем переменные

Всегда надо давать вменяемые имена переменным. Это правило относится не к контексту в JS, а к программированию в целом, но во время захвата контекста все об этом забывают. Например:

$( 'input' ). bind ( 'keydown' , function () var $colorInput = $( this );
$colorInput . css ( background : $colorInput . val ()
>);
>);

Это решит проблему со вложенными функциями.

$block = $( this );
$( 'button' ). each (function () var $button = $( this );
$. each ( users , function () var user = this ;
$block . append ( user . init ( $button ));
>);
>);

Но чаще всего такое разнообразие контекстов не требуется. Потому давайте посмотрим на другой способ:

Принудительное задание контекста функции

Эту идею я почерпнул из фреймворка MooTools и считаю её замечательной. Немножко расширим прототип Function

Function. prototype . bind = function ( scope ) var fn = this ;
return function () return fn . apply ( scope , arguments );
>;
>;

Теперь мы можем не терять контекст в течении всей работы. Если нам нужен только внешний контекст — мы прямо это указываем и код становится значительно прозрачнее:

Другие возможности работы с .bind

Часто бывает, что для того, чтобы работать с методом объекта приходится городить очень некрасивую конструкцию. Например (пример на MooTools):

var Analizer = new Class( initialize : function ( name ) this . dataRouter = new DataRouter [ name ]();
>,
start : function () var analizer = this ;
this . dataRouter . get (function ( data ) analizer . parse ( data );
>);
>,
parse : function ( data ) // parsing data, using this.privateMethods
>
>);

мы не можем передать в метод get просто ссылку на метод parse:

потому что тогда потеряется контекст метода. метод bind поможет нам в этом и мы видим, насколько яснее стал этот код:

var Analizer = new Class( initialize : function ( name ) this . dataRouter = new DataRouter [ name ]();
>,
start : function () this . dataRouter . get (
this . parse . bind ( this )
);
>,
parse : function ( data ) // parsing data, using this.privateMethods
>
>);

Небольшой кусок кода из карточной игры Bridge на LibCanvas, демонстрирующий использование bind.
Суть ассинхронности в том, что ИИ не должен совершать никаких действий, пока летит карта.
Например, он берет карту из колоды, но может её туда положить только после того, как карта долетит, иначе будет неприятный для игрока эффект.

Bridge . AI = new Class( // ..
putCardSmart : function ( card ) this . putCard ( card ,
// Этот метод вызовется только когда карта долетит, но он сохранит контекст.
this . finishSmart . bind ( this )
);
>,
getCardSmart : function () this . getCard (function ( card ) this . canPutCard ( card ) ?
this . putCardSmart ( card ) :
this . finishSmart ();
>. bind ( this )); // Мы захватываем контекст.
>,
finishSmart : function () this . canFinishMove () ?
this . finishMove () :
this . movement ();
>
// ..
>);

Источник

Javascript scope and self=this, _this=this, that=this

Why is _this. not working but this. is working. I thought the whole point of _this=this was to provide a mechanism for when object functions are called, you have a "guaranteed" reference back to the instantiated object as it is now within the closure of the object function to mimic traditional class behavior. I've read so many pieces about scope and for some reason I'm just not seeing it. What am I missing?

var PersonClass = function PersonClass(_name, _age) < _this=this; this.name=_name; this.age=_age; console.log("created "+this.name+":"+this.age); function changeAge(num) < console.log("changing age for:" + _this.name); _this.age=num; >PersonClass.prototype.changeAge=changeAge; PersonClass.prototype.getAge=function() < console.log(_this.name+":"+_this.age); return _this.age; >; PersonClass.prototype.getAge2=function() < console.log(this.name+":"+this.age); return this.age; >; >; // comments indicate what value is displayed in console var john=new PersonClass("john",1); // john:1 var sue=new PersonClass("sue",2); // sue:2 john.getAge(); // sue:2 john.getAge2(); // john:1 john.changeAge(10); // sue sue.getAge(); // sue:10 sue.getAge2(); // sue:10 john.getAge(); // sue:10 john.getAge2(); // john:1 

Probably because you've not var d it. You're also doing something very unusual with the prototyping there. The way you've written it, these should be instance methods not inherited methods

Paul - that's not it. var _this=this doesn't change anything Alnitak - how would you do it? SLaks - What do you mean by "capture".

stop using prototype, simplest answer. Prototype is a very old way of doing this, and it is very unnecessary, clunky, and not easily manageable. Check my answer. Works like a charm.

Источник

Оцените статью