• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
this
 

this

on

  • 667 views

Explain this of JavaScript

Explain this of JavaScript

Statistics

Views

Total Views
667
Views on SlideShare
667
Embed Views
0

Actions

Likes
6
Downloads
8
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    this this Presentation Transcript

    • thisothree@JSDC
    • 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.94cout << Box2.Volume() << endl; // 8.5*6.0*2.0 = 102return 0;}
    • this• Context in JavaScript• Can mean the object also
    • JavaScriptvar 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 Functionvar big = function () {/*...*/};var foo = {small: function () {/*...*/}};big(); // 1. this: window objectfoo.small(); // 2. this: foovar small = foo.small;small();
    • 3 Way to Call Functionvar big = function () {/*...*/};var foo = {small: function () {/*...*/}};big(); // 1. this: window objectfoo.small(); // 2. this: foovar small = foo.small;small(); // 3. this: window object
    • Borrowing Methodvar foo = {small: function () {this;}};var bar = {};foo.small(); // this: foobar.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 undefinedvar foobar2 = new Foobar();// this: new empty object
    • One More Way to CallFunction
    • apply/callvar foo = {};function foobar(v1, v2) {this.bar1 = v1;this.bar2 = v2;}foobar.call(foo, v1, v2); // this: foofoobar.apply(foo, [v1, v2]); // this: foo
    • bindvar foo = {};var otherFoo = {};function setBar(v1, v2) {this.bar1 = v1;this.bar2 = v2;}var fooSetBar = setBar.bind(foo);fooSetBar(1, 2); // this: foootherFoo.foobar = fooSetBar;otherFoo.foobar(3, 4); // this: foo
    • ProtectYour Method• Bind context and function together
    • $.proxy/_.bind• Use apply to implement bind
    • Implement Bindvar 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 DomaElement.addEventListener(click, function () {this; // aElement}, false);// old IEaElement.attachEvent(onclick, function () {this; // window});
    • Callback Functionfunction 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 Stackfunction 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 bindfunction 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
    • Performancehttp://jsperf.com/bind-vs-closure-setup/10
    • Pros• Clearer code
    • Use _.bindfunction 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 $.proxyfunction 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 Needfb = 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
    • Closurevar isIE = true;function foobar() {if (!isIE) {// access isIE is possible because of closurereturn;}// blah...};
    • that/selffunction Foobar(input) {var that = this; // that or selfthis.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 ArrowFoobar = (input) ->@prefix = input@echo = (result) => @prefix + resultfb = new Foobar(res: )$.get(/info, fb.echo)
    • CoffeeScript Fat ArrowFoobar = (input) ->@prefix = input@echo = (result) => @prefix + resultfb = new Foobar(res: )$.get(/info, fb.echo)
    • Compile to JSvar 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 JSvar 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 JSvar 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 Moduledefine(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 thisdefine(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 Withoutthisfunction 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 newvar 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 Modeldefine(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 Chainingvar firstDfd = $.Deferred(),secondDfd = $.Deferred(),thirdDfd = $.Deferred();firstDfd.done(secondDfd.resolve);secondDfd.done(thirdDfd.resolve);firstDfd.resolve(); // All Deferred object resolved here
    • Callbackshttps://github.com/jquery/jquery/blob/master/src/deferred.js// promise[ done | fail | progress ] = list.addpromise[ 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;
    • Callbackshttps://github.com/jquery/jquery/blob/master/src/deferred.js// promise[ done | fail | progress ] = list.addpromise[ 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 Arepromise[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 onmethods definition and not easy toinheritance object• Benefit is you can write more clear, simplecode
    • References
    • https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
    • Questions?http://www.flickr.com/photos/roman/5610736/