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.8k
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.4k
Other Decks in Programming
See All in Programming
Enabling DevOps and Team Topologies Through Architecture: Architecting for Fast Flow
cer
PRO
0
340
CSC509 Lecture 11
javiergs
PRO
0
180
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
100
Better Code Design in PHP
afilina
PRO
0
130
AI時代におけるSRE、 あるいはエンジニアの生存戦略
pyama86
6
1.2k
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
NSOutlineView何もわからん:( 前編 / I Don't Understand About NSOutlineView :( Pt. 1
usagimaru
0
340
Amazon Qを使ってIaCを触ろう!
maruto
0
410
イベント駆動で成長して委員会
happymana
1
330
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
PHP でアセンブリ言語のように書く技術
memory1994
PRO
1
170
Featured
See All Featured
Bash Introduction
62gerente
608
210k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.5k
A Philosophy of Restraint
colly
203
16k
RailsConf 2023
tenderlove
29
900
How GitHub (no longer) Works
holman
310
140k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
GraphQLとの向き合い方2022年版
quramy
43
13k
What's new in Ruby 2.0
geeforr
343
31k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
47
2.1k
The Invisible Side of Design
smashingmag
298
50k
A Tale of Four Properties
chriscoyier
156
23k
Why Our Code Smells
bkeepers
PRO
334
57k
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/