Is there a difference between the 2 code snippets?
Since foo is a member function of obj, this would refer to obj itself (method invocation pattern).
1.
var obj = {};
obj.prop = some_property;
obj.foo = function() {
do_something_with(obj.prop);
};
2.
var obj = {};
obj.prop = some_property;
obj.foo = function() {
do_something_with(this.prop);
};
An application I was working on, kept crashing when I used approach 2.
The code was something like :
obj = {};
obj.listener = {
eventprocess : function(param) {
//some code
}
};
obj.init = function() {
this.a = library_func();
this.a.add_listener(this.listener);
};
it worked when I used approach 1.
Any ideas why?
As the resolution of obj and this is deferred until execution of the function, it's result can vary depending on whether this or/and obj has changed between definition and invocation.
For example, given two objects which are identical, except one uses this and the other uses obj in the function foo:
var objA = {};
objA.prop = "test";
objA.foo = function() {
alert(this.prop);
};
var objB = {};
objB.prop = "test";
objB.foo = function() {
alert(objB.prop);
};
... we'll see different behavior here:
var anotherObject = {
objAFoo: objA.foo,
objBFoo: objB.foo
};
anotherObject.objAFoo(); // "undefined";
anotherObject.objBFoo(); // "test";
http://jsfiddle.net/3D6xY/
Note that you can normalize this behavior by setting the value of this using call() or apply(), as pointed out in the comments:
anotherObject.objAFoo.call(objA); // "test";
http://jsfiddle.net/3D6xY/1/
However, note also that cases where this has been bound using bind() or jQuery.proxy() can hurt you here.
Related
Is there any way to retrieve the object, that is bound to a function as thisArg?
Like:
let object = {};
let fn = function () {
return 'hello world';
}
fn = fn.bind(object);
//now i want a way to achieve that this comparison results in true
let result = (object === fn.getBoundThis());
No, there's nothing built into JavaScript that provides that information. fn itself would need to provide it.
This approach can be helpful if you are able to modify fn function definition. Otherwise I don't see any way to get it.
let object = {a:10};
let fn = function () {
getThisVal(this);
return;
}
let theObject;
let getThisVal = function(val){
theObject = val
}
fn = fn.bind(object);
fn();
console.log(theObject);
One more way can be instead of returning this you can call any other function defined by you inside fn and pass this as parameter and access it there.
Like other answers mention, there is no built-in way.
But you can wrap the bind method and intercept the bound object:
// this should be the first javascript
// that you execute on the page
(function() {
let originalBind = Function.prototype.bind;
//wrap bind function
Function.prototype.bind = function(obj) {
let boundFunction = originalBind.call(this, obj);
boundFunction.boundThis = obj;
return boundFunction;
}
console.warn('`Function.prototype.bind` has been patched!');
})();
function foo() {
console.log(this);
}
let object = {
a: 'bind me'
};
let bar = foo.bind(object);
console.log('\'this\' object of bar: ', bar.boundThis);
console.log(`(object === bar.boundThis) =>`, object === bar.boundThis);
Note: Only the objects created after patching will have boundThis property.
I can do something like this:
var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)
Is there a way to mutate first foo instead of creating new function?
I need it to monkey patch some dependency without recreating whole hierarchy of objects.
I need to patch a constructor function in a library, just add an alert on every call. But without juggling with prototypes
No, you can't modify the function foo refers to. You can only make foo refer to a new function that does what you want. One way to do that is to use your toString approach, but it's best to avoid that if at all possible, because the function you get as a result will not be the same as the original; the scope it has access to will be different.
Usually, you do want a proxy/wrapper, e.g.:
// The original foo
var foo = function(arg) {
return "original foo says '" + arg + "'";
};
console.log(foo("bar"));
// Let's wrap it
(function() {
var originalFoo = foo;
foo = function() {
return originalFoo.apply(this, arguments) + " plus updated foo";
};
})();
console.log(foo("bar"));
This doesn't create a hierarchy of objects or similar, it just wraps foo.
If foo is a constructor function (let's call it Foo), you'll also want to copy Foo.prototype:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());
// Let's wrap it
(function() {
var originalFoo = Foo;
Foo = function() {
var rv = originalFoo.apply(this, arguments);
this.arg += " (plus more from augmented foo)";
return rv;
};
Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());
And of course, if you need to wrap a function on Foo.prototype, you can do it just like foo in my first example:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());
// Let's wrap its getArg
(function() {
var originalGetArg = Foo.prototype.getArg;
Foo.prototype.getArg = function() {
return originalGetArg.apply(this, arguments) + " updated";
};
})();
console.log(f.getArg());
Note how it doesn't matter that we wrapped the prototype function after creating the f object.
I have looked at similar questions here on the stack but could not come up with a solution.
My issue is that the following code's this does not point to the object in question, instead it points to the environment (window) in Node.JS.
I'm sure it's something trivial but after about 2 hours of research I have officially given up and it's time to ask for help.
Code:
var slice = Array.prototype.slice;
function Chain(options, links) {
if (!(this instanceof Chain)) return new Chain(options, slice.call(arguments));
return this;
}
Chain.prototype.quicklink = function quicklink(fn) {
console.log(this);
};
var Chain = require('./chains');
var chain = Chain();
var _ = chain.quicklink;
_('extern_var', 'something', '$callback');
Expected:
this to point to Chain object.
Result:
this points to environment or window in Node.JS
Prototyping:
I use JSBin for prototyping. Here is the prototype there. It has essentially the same effect as my Node environment.
http://jsbin.com/OSaHaZAK/1/edit
Call it with apply or call to set the expected this and pass the arguments
_.apply(chain, ['extern_var', 'something', '$callback']);
FIDDLE
You must maintain the context for quicklink:
var _ = chain.quicklink.bind(chain);
The problem you have is classic:
var o = {};
o.f = function () { console.log(this); };
o.f(); //o
var f2 = o.f;
f2(); //window
Demo
read about how this works on MDN
instead of
var chain = Chain();
do this
var chain = new Chain();
new keyword create new instance.
more info from MDN forum. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
Here is another way to solve this riddle (to maintain the context).
var slice = Array.prototype.slice;
function Chain(options, links) {
if (!(this instanceof Chain)) return new Chain(options, slice.call(arguments));
return this;
}
Chain.prototype.quicklink = function quicklink() {
var args = arguments;
console.log(args);
};
var chain = Chain();
function _() {
var args = slice.call(arguments);
chain.quicklink.apply(chain, args);
}
_('extern_var', 'bob', '$callback');
Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar
Is it possible to define a function in the scope of a parent function and bind an argument passed through the parent function as its scope before returning it?
Here is an example:
var myObject = {
foo: "bar"
};
var myFunction = (function() {
return function() {
return this.foo;
};
}).call(myObject);
myFunction.call(myObject); // I'd like to bind myObject as this does ...
myFunction(); // ... but I'd like to do it before invoking it, without .call() or .apply()
Or another complex example, that describes what I'm trying to do:
var createMyCopy = function(original, self) {
var copy;
eval("copy=" + original.toString());
console.log(copy()); // returns undefined
};
(function() {
var self = "Hello world",
myFunction = function() {
return self;
};
console.log(myFunction()); // returns "Hello world"
createMyCopy(myFunction);
})();
I'm trying to create a copy of a function, so that I can make changes to it without changing the original one, but I'd like to have the variables that are defined in the original one in the copy as well...
Do you mean like this?
var myObject = {
foo: "bar"
};
var myFunction = (function() {
var self = this;
return function() {
return self.foo;
};
}).call(myObject);
I think you're getting scope and context mixed up in your question.
I think you mean this:
var myFunction = (function(obj) {
return function() {
return obj.foo;
};
})(myObject);
The immediately invoked function expression is passed myObject and returns a new function in which that parameter is bound as the variable obj.
I'm not sure what you mean, but you can do this:
var myObject = {
foo: "bar"
};
function myFunction() {
return this.foo;
}
console.log(myFunction.apply(myObject)); // bar
The first argument of apply is the context (ie. what this refers to). The second argument of apply is an array of arguments (but I've omitted that here as there are no arguments).