Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
this
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
othree
May 19, 2013
Programming
3.8k
15
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
this
A introduction about this in JavaScript
othree
May 19, 2013
More Decks by othree
See All by othree
How GitHub Supports Vim License Detection, The Five Years Journey
othree
1
2.3k
WAT JavaScript Date
othree
3
2.3k
Modern HTML Email Development
othree
3
2.8k
MRT & GIT
othree
1
2.5k
YAJS.vim and Vim Syntax Highlight
othree
1
3.2k
Web Trends to 2015
othree
4
370
Transducer
othree
9
3.2k
HITCON 11 Photographer
othree
4
570
fetch is the new XHR
othree
6
3.7k
Other Decks in Programming
See All in Programming
AmebaブログはKMPから卒業します
kmars0605
0
210
Domain-Driven Transformation
hschwentner
2
2.3k
Agents on Rails - Rails at Scale 2026
irinanazarova
0
570
ChromeでローカルLLM
ryu1013
0
150
contenteditable と日本語入力に向き合う
colorful12
0
200
Performance Optimization With LLMs
xleitix
0
160
The Rails Doctrine Decade
koic
2
600
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
330
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
220
Kotlinize Is Not Just Converting to Kotlin
chigichan24
1
160
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
280
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
180
Featured
See All Featured
Technical Leadership for Architectural Decision Making
baasie
3
600
Rails Girls Zürich Keynote
gr2m
96
14k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3.1k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
490
A Tale of Four Properties
chriscoyier
163
24k
WENDY [Excerpt]
tessaabrams
14
40k
Code Reviewing Like a Champion
maltzj
529
40k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3.1k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
43k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
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/