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
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.2k
Modern HTML Email Development
othree
3
2.8k
MRT & GIT
othree
1
2.5k
YAJS.vim and Vim Syntax Highlight
othree
1
3.1k
Web Trends to 2015
othree
4
370
Transducer
othree
9
3.2k
HITCON 11 Photographer
othree
4
550
fetch is the new XHR
othree
6
3.6k
Other Decks in Programming
See All in Programming
PHPプロジェクトの結合バランスを可視化する #php_night
kajitack
0
230
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
130
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
110
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
260
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
55
36k
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
3
360
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
660
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
4
1.1k
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
3
470
RSSとCodexを使ってX投稿自動化してみた
ochtum
0
110
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
340
Webの地図
yosuke_furukawa
PRO
1
580
Featured
See All Featured
The browser strikes back
jonoalderson
0
1.6k
Embracing the Ebb and Flow
colly
88
5.2k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
RailsConf 2023
tenderlove
30
1.5k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
410
30 Presentation Tips
portentint
PRO
1
390
A Modern Web Designer's Workflow
chriscoyier
698
190k
Chasing Engaging Ingredients in Design
codingconduct
0
300
From π to Pie charts
rasagy
0
360
GitHub's CSS Performance
jonrohan
1033
470k
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/