Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
this
Search
othree
May 19, 2013
Programming
15
3.5k
this
A introduction about this in JavaScript
othree
May 19, 2013
Tweet
Share
More Decks by othree
See All by othree
How GitHub Supports Vim License Detection, The Five Years Journey
othree
1
1.9k
WAT JavaScript Date
othree
3
1.9k
Modern HTML Email Development
othree
3
2.6k
MRT & GIT
othree
1
2k
YAJS.vim and Vim Syntax Highlight
othree
1
2.6k
Web Trends to 2015
othree
4
310
Transducer
othree
9
2.8k
HITCON 11 Photographer
othree
4
460
fetch is the new XHR
othree
6
3.5k
Other Decks in Programming
See All in Programming
テストコード書いてみませんか?
onopon
2
110
情報漏洩させないための設計
kubotak
2
180
創造的活動から切り拓く新たなキャリア 好きから始めてみる夜勤オペレーターからSREへの転身
yjszk
1
130
Fibonacci Function Gallery - Part 1
philipschwarz
PRO
0
220
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
menu基盤チームによるGoogle Cloudの活用事例~Application Integration, Cloud Tasks編~
yoshifumi_ishikura
0
110
数十万行のプロジェクトを Scala 2から3に完全移行した
xuwei_k
0
270
Scalaから始めるOpenFeature入門 / Scalaわいわい勉強会 #4
arthur1
1
330
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
550
開発者とQAの越境で自動テストが増える開発プロセスを実現する
92thunder
1
190
モバイルアプリにおける自動テストの導入戦略
ostk0069
0
110
From Translations to Multi Dimension Entities
alexanderschranz
2
130
Featured
See All Featured
Navigating Team Friction
lara
183
15k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
28
900
Fashionably flexible responsive web design (full day workshop)
malarkey
405
66k
Optimizing for Happiness
mojombo
376
70k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.4k
Code Reviewing Like a Champion
maltzj
520
39k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Making the Leap to Tech Lead
cromwellryan
133
9k
Transcript
this othree@JSDC
None
this • ‘the object’ it belongs in OOP
C++ class Box { public: Box(double l=2.0, double b=2.0, double
h=2.0) { this->length = l; this->breadth = b; this->height = h; } double Volume() { return length * breadth * height; } int compare(Box box) { return this->Volume() > box.Volume(); } private: double length; double breadth; double height; };
Continued.. int main(void) { Box Box1(3.3, 1.2, 1.5); Box Box2(8.5,
6.0, 2.0); cout << Box1.Volume() << endl; // 3.3*1.2*1.5 = 5.94 cout << Box2.Volume() << endl; // 8.5*6.0*2.0 = 102 return 0; }
this • Context in JavaScript • Can mean the object
also
JavaScript var Box = function Box (l, b, h) {
this.length = l; this.breadth = b; this.height = h; }; Box.prototype.Volume = function () { return this.length * this.breadth * this.height; }; Box.prototype.compare = function (box) { return this.Volume() > box.Volume(); };
this in Function • Context • Depends on how you
call the function
3 Way to Call Function var big = function ()
{/*...*/}; var foo = { small: function () {/*...*/} }; big(); // 1. this: window object foo.small(); // 2. this: foo var small = foo.small; small();
3 Way to Call Function var big = function ()
{/*...*/}; var foo = { small: function () {/*...*/} }; big(); // 1. this: window object foo.small(); // 2. this: foo var small = foo.small; small(); // 3. this: window object
Borrowing Method var foo = { small: function () {
this; } }; var bar = {}; foo.small(); // this: foo bar.borrowedSmall = foo.small; bar.borrowedSmall(); // this: bar
this in Global Scope • Root object
Root Object • `window` in browsers • Root object in
other environment
to Support Both (function () { root = this; //blah....
}());
Strict Mode • No more global context
Don’t Forget `new` function Foobar() { "use strict"; this.a =
'foo'; this.b = 'bar'; } var foobar1 = Foobar(); // Cannot set property 'a' of undefined var foobar2 = new Foobar(); // this: new empty object
One More Way to Call Function
apply/call var foo = {}; function foobar(v1, v2) { this.bar1
= v1; this.bar2 = v2; } foobar.call(foo, v1, v2); // this: foo foobar.apply(foo, [v1, v2]); // this: foo
bind var foo = {}; var otherFoo = {}; function
setBar(v1, v2) { this.bar1 = v1; this.bar2 = v2; } var fooSetBar = setBar.bind(foo); fooSetBar(1, 2); // this: foo otherFoo.foobar = fooSetBar; otherFoo.foobar(3, 4); // this: foo
Protect Your Method • Bind context and function together
$.proxy/_.bind • Use apply to implement bind
Implement Bind var bind = function (func, context) { return
function () { func.apply(context, arguments); }; };
Solve Event Handler • Use apply to assign context •
JavaScript Libraries did it for you
this in Event Handler // W3C Dom aElement.addEventListener('click', function ()
{ this; // aElement }, false); // old IE aElement.attachEvent('onclick', function () { this; // window });
Callback Function function Foobar (input) { this.prefix = input; }
Foobar.prototype.echo = function (result) { return this.prefix + result; }; fb = new Foobar(); $.get('/info', function (result) { fb.echo(result); });
Reduce One Stack function Foobar (input) { this.prefix = input;
} Foobar.prototype.echo = function (result) { return this.prefix + result; }; fb = new Foobar(); $.get('/info', fb.echo); // this.prefix is 'undefined'
Use bind function Foobar (input) { this.prefix = input; this.echo
= this.echo.bind(this); // Protect method } Foobar.prototype.echo = function (result) { return this.prefix + result; }; fb = new Foobar(); $.get('/info', fb.echo);
Cons • Performance is bad • Old browser don’t support
Performance http://jsperf.com/bind-vs-closure-setup/10
Pros • Clearer code
Use _.bind function Foobar (input) { this.prefix = input; this.echo
= _.bind(this.echo, this); // function, context } function Foobar (input) { this.prefix = input; _.bindAll(this); // context } http://underscorejs.org/#bind
Use $.proxy function Foobar (input) { this.prefix = input; this.echo
= $.proxy(this.echo, this); // function, context } function Foobar (input) { this.prefix = input; this.echo = $.proxy(this, 'echo'); // context, method name } http://api.jquery.com/jQuery.proxy/
Bind by Need fb = new Foobar(); $.get('/info', $.proxy(fb, 'echo'));
$.get('/info', $.proxy(fb.echo, fb)); $.get('/info', $.bind(fb.echo, fb));
http://www.flickr.com/photos/othree/8544069132/
Avoid Using this
Closure var isIE = true; function foobar() { if (!isIE)
{ // access isIE is possible because of closure return; } // blah... };
that/self function Foobar(input) { var that = this; // that
or self this.prefix = input; this.echo = function (result) { return that.prefix + result; // that is accessible because of closure }; } fb = new Foobar('res: '); $.get('/info', fb.echo);
CoffeeScript Fat Arrow Foobar = (input) -> @prefix = input
@echo = (result) => @prefix + result fb = new Foobar('res: ') $.get('/info', fb.echo)
CoffeeScript Fat Arrow Foobar = (input) -> @prefix = input
@echo = (result) => @prefix + result fb = new Foobar('res: ') $.get('/info', fb.echo)
Compile to JS var Foobar, fb; Foobar = function(input) {
var _this = this; this.prefix = input; return this.echo = function(result) { return _this.prefix + result; }; }; fb = new Foobar('res: '); $.get('/info', fb.echo);
Compile to JS var Foobar, fb; Foobar = function(input) {
var _this = this; this.prefix = input; return this.echo = function(result) { return _this.prefix + result; }; }; fb = new Foobar('res: '); $.get('/info', fb.echo);
Compile to JS var Foobar, fb; Foobar = function(input) {
var _this = this; this.prefix = input; return this.echo = function(result) { return _this.prefix + result; }; }; fb = new Foobar('res: '); $.get('/info', fb.echo);
LiveScript use ~>
Pros • No more this issue, context free • Reduce
one call stack • No call/apply, no impact on performance • Encapsulation
Cons • Can’t use this tip on normal constructor
How about AMD • Define modules can return constructor, function,
array, primitive data • Define a singleton module on most cases • Always have data on module
AMD Singleton Module define('foobar', function () { return { init:
function (prefix) { this.prefix = prefix; } echo: function (input) { return this.prefix + input; } }; });
Cons • Function can be borrowed • Not doing on
right `this` you expect
Avoid Use this define('foobar', function () { var self =
{}; return { init: function (prefix) { self.prefix = prefix; } echo: function (input) { return self.prefix + input; } }; });
Constructors? • Use bind to protect methods if necessary
Constructor Without this function Person(birth, gender) { var person =
{ birth: (birth || '1970/01/01'), gender: (gender || 'M') }; return { getBirth: function () { return person.birth; }, getGender: function () { return person.gender; } }; }
to new or not to new var p1 = Person('2013/01/02');
p1.getBirth(); // "2013/01/02" var p2 = new Person('2000/01/02', 'F'); p2.getBirth(); // "2000/01/02" p1.getBirth(); // "2013/01/02"
Cons • No prototype inheritance • More memory usage for
methods
Backbone Model define(function (require) { return Backbone.Model.extend( initialize: function (attrs)
{ return _.bindAll(this); }, toITEM: function () { return this.toJSON(); }, toConfig: function () { return { name: this.get('name'), package_name: this.get('package_name') }; } ); });
Who Use this Tip • jQuery.Deferred • jQuery.Callbacks
Deferred Chaining var firstDfd = $.Deferred(), secondDfd = $.Deferred(), thirdDfd
= $.Deferred(); firstDfd.done(secondDfd.resolve); secondDfd.done(thirdDfd.resolve); firstDfd.resolve(); // All Deferred object resolved here
Callbacks https://github.com/jquery/jquery/blob/master/src/deferred.js // promise[ done | fail | progress ]
= list.add promise[ tuple[1] ] = list.add; // skip... // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ] (this === deferred ? promise : this, arguments); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith;
Callbacks https://github.com/jquery/jquery/blob/master/src/deferred.js // promise[ done | fail | progress ]
= list.add promise[ tuple[1] ] = list.add; // skip... // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ] (this === deferred ? promise : this, arguments); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith;
Actually Are promise['done'] = resolveCallbacks.add; promise['fail'] = rejectCallbacks.add; promise['progress'] =
notifyCallbacks.add; // skip... deferred["resolveWith"] = resolveCallbacks.fireWith; deferred["rejectWith"] = rejectCallbacks.fireWith; deferred["notifyWith"] = notifyCallbacks.fireWith;
Summary • Understand `this` • Understand how not to use
`this` • Use `this` carefully if necessary
Trade-Off • ‘Not use this’ requires more memory on methods
definition and not easy to inheritance object • Benefit is you can write more clear, simple code
References
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
Questions? http://www.flickr.com/photos/roman/5610736/