if (a != null){ ... }
if (typeof a != 'undefined' && a != null){ ... }
if (a != null){ ... }
if (typeof a != 'undefined' && a != null){ ... }
if (!Function.prototype.softBind) { Function.prototype.softBind = function(obj) { var fn = this, curried = [].slice.call( arguments, 1 ), bound = function bound() { return fn.apply( (!this || (typeof window !== "undefined" && this === window) || (typeof global !== "undefined" && this === global) ) ? obj : this, curried.concat.apply( curried, arguments ) ); }; bound.prototype = Object.create( fn.prototype ); return bound; }; } function foo() { console.log("name: " + this.name); } var obj = { name: "obj" }, obj2 = { name: "obj2" }, obj3 = { name: "obj3" }; var fooOBJ = foo.softBind( obj ); fooOBJ(); // name: obj obj2.foo = foo.softBind(obj); obj2.foo(); // name: obj2 <---- look!!! fooOBJ.call( obj3 ); // name: obj3 <---- look! setTimeout( obj2.foo, 10 ); // name: obj <---- falls back to soft-binding
if (!Function.prototype.softBind) { Function.prototype.softBind = function(obj) { var fn = this; console.log("Outer this = "+ fn); var curried = [].slice.call( arguments, 1 ); console.log("Outer curry = "+curried); var bound = function bound() { console.log("Inner this = " + this); console.log("Inner curry = "+curried.concat.apply( curried, arguments )); return fn.apply( (!this || (typeof window !== "undefined" && this === window) || (typeof global !== "undefined" && this === global) ) ? obj : this, curried.concat.apply( curried, arguments ) ); }; bound.prototype = Object.create( fn.prototype ); console.log("return bound"); return bound; }; } function foo(a1, a2) { console.log(a1 + ' ' +a2 + " name: " + this.name); } var obj = { name: "obj" }, obj2 = { name: "obj2" }, obj3 = { name: "obj3" }; var fooOBJ = foo.softBind( obj, 'A1'); fooOBJ('A2'); // name: obj //obj2.foo = foo.softBind(obj, 'A1'); //obj2.foo('A2'); // name: obj2 <---- look!!! //fooOBJ.call( obj3 ); // name: obj3 <---- look!
Outer this = function foo(a1, a2) { console.log(a1 + ' ' +a2 + " name: " + this.name); } Outer curry = A return bound Inner this = [object Object] Inner curry = A,A2 A A2 name: obj2
[].slice.call(arguments, 1)is semantically equal to
arguments.slice(1)except the latter is syntactically incorrect because the variable arguments is not a real array. It's an 'array-like' object.
bound.prototype = Object.create( fn.prototype );copies all the properties of foo to bound, essentially ensuring that after softbind the function foo doesn't lose any properties.
function foo(a) { this.a = a; } var bar = new foo( 2 ); var bar2 = foo( 2 ); console.log( bar); // foo {a: 2} console.log( bar.a); // 2 console.log( bar2); // undefined console.log( bar2.a); // TypeError
function foo(a) { this.a = a; return this; } var bar = new foo( 2 ); var bar2 = foo( 2 ); console.log( bar); // foo {a: 2} console.log( bar.a); // 2 console.log( bar2); // Window {top: Window, location: Location, document: document, window: Window, external: Object…} console.log( bar2.a); // 2
function foo(a) { this.a = a; return 3; } var bar = new foo( 2 ); var bar2 = foo( 2 ); console.log( bar); // foo {a: 2} console.log( bar.a); // 2 console.log( bar2); // 3 console.log( bar2.a); // undefined
class foo{ var a; public foo(a){ this.a = a; } } var bar = new foo(2);
function foo(num) { console.log( "foo: " + num ); // keep track of how many times `foo` is called // Note: `this` IS actually `foo` now, based on // how `foo` is called (see below) this.count++; } foo.count = 0; var i; for (i=0; i<10; i++) { if (i > 5) { // using `call(..)`, we ensure the `this` // points at the function object (`foo`) itself foo.call( foo, i ); } } // foo: 6 // foo: 7 // foo: 8 // foo: 9 // how many times was `foo` called? console.log( foo.count ); // 4
foo.call( null, i );
foo.call( foo, i ) = foo.bind(foo)(i) foo.call( null, i) = foo(i)
var obj = { id: "awesome", cool: function coolFn() { console.log( this.id ); } }; var id = "not awesome"; obj.cool(); // awesome setTimeout( obj.cool, 100 ); // not awesome
console.log( obj.id );
cool2: function coolFn2() { console.log( this.id ); }.bind(obj)It doesn't work because obj cannot be referenced within itself, well, unless it is referenced within a function. Therefore the 2nd attempt.
cool3: function coolFn3() { (function(){ console.log(this.id); }.bind(obj))(); }
var MyModules = (function Manager() { var modules = {}; function define(name, deps, impl) { for (var i=0; i<deps.length; i++) { deps[i] = modules[deps[i]]; } modules[name] = impl.apply(impl, deps); console.log("module "+modules[name]); } function get(name) { return modules[name]; } return { define: define, get: get }; })(); MyModules.define( "bar", [], function(){ function hello(who) { return "Let me introduce: " + who; } return { hello: hello }; } ); MyModules.define( "foo", ["bar"], function(bar){ var hungry = "hippo"; function awesome() { console.log( bar.hello( hungry ).toUpperCase() ); } return { awesome: awesome }; } ); var bar = MyModules.get( "bar" ); var foo = MyModules.get( "foo" ); console.log(bar.hello( "hippo" )); // Let me introduce: hippo foo.awesome(); // LET ME INTRODUCE: HIPPO
modules[name] = impl.apply(impl, deps);
fun.apply(thisArg, [argsArray])
thisArg
this
provided for the call to fun
. Note that this
may not be the actual value seen by the method: if the method is a function in non-strict mode code, null
and undefined
will be replaced with the global object, and primitive values will be boxed.modules[name] = impl(deps);
modules[name] = impl(deps[0]);
for (var i=1; i<=5; i++) { setTimeout( function timer(){ console.log( i ); }, i*1000 ); }
for (var i=1; i<=5; i++) { (function(){ var j = i; setTimeout( function timer(){ console.log(j); }, i*1000 ); })(); }
for (var i=1; i<=5; i++) { (function(j){ setTimeout( function timer(){ console.log(j); }, i*1000 ); })(i); }
for (let i=1; i<=5; i++) { setTimeout( function timer(){ console.log(i); }, i*1000 ); }