Can a method find out the "this" of its parent object? - javascript

Let's say I've come up with a particular sort function that I want to put in the prototype of some Array based object (I'll use Array itself here). I can do
Array.prototype.specialSort = function...
but what I'd really like to do is
Array.prototype.sort.special = function...
the problem, of course, is that when it's called, the latter won't know about the Array object, it will only know about the sort, so it can't sort. Is there any magical incantation to pass a "this" down the tree?
Secondary question (since the answer to the primary question is likely "no"): What would you do to implement the notion of "sub-methods" with maximum elegance?

This should be fairly close to what you want:
Array.prototype.sort = function () {
return {
self: this;
, special: function () {
return sortLogic (self);
}
};
};
var xs = [1, 2, 3];
xs.sort ().special ();
Another option would be to use Function.prototype.call or Function.prototype.apply, especially if you want arr.sort () to sort the list as normal.
Array.prototype.sort.special.call (arr, arg1, arg2, etc);
Using the second method over the first allows one to use the call and apply methods easily on the sort.special method. Could be useful when doing something like the following:
function () {
Array.prototype.sort.special.call (arguments);
}
If you want both worlds, something like this could work:
Array.prototype.sort = (function () {
var special = function () {
if (this [0] > this [1]) {
var tmp = this [0];
this [0] = this [1];
this [1] = tmp;
}
return this;
};
var sort = function () {
var context = this;
return {
special: function () {
return special.apply (context, arguments)
}
};
};
sort.special = special;
return sort;
}) ();
/*** Example Below ***/
function foo () {
Array.prototype.sort.special.call (arguments);
var xs = [5, 2, 3];
xs.sort ().special ();
alert (arguments);
alert (xs);
}
foo (9, 6);

Thanks for the guidance to both Pointy and trinithis. I think I am clear on the subject now. The sticking point is that, although sort() is a method of the Array, if it's not invoked, it's just a member (or property), so it has no "this". I was wanting the "this" it would have had if it had been invoked. And since I was invoking something at the end of the chain, I was kind of hoping there was some magic that would keep it all method-y. But no.
What I would probably do is have a separate "sorts" method to act as the grouper for my special methods, and leave the existing sort alone.

Related

Modifying "this" variables

I was playing around with modifying Array Prototype, but I'm stumped at this part. Would be great if you could help me.
Alright, suppose I want to add a function "Parent" to Array.prototype
Array.prototype.Parent = function() {
console.log(this);
}
Next, I want to add a Child function to the Parent function. I would do it like this:
Array.prototype.Parent.Child = function() {
console.log(this);
}
Now, I want both this in Parent and Child to refer to the array itself. So:
[1,2,3].Parent(); // Would output [1,2,3];
[1,2,3].Parent.Child(); // Want it to print [1,2,3];
Basically, I want this variable in child to refer to the array instead of the Parent Function. Any insight?
You can make Parent a getter that returns a unique function for each array, providing context:
Object.defineProperty(Array.prototype, 'parent', {
configurable: true,
get: function () {
var that = this;
function parent() {
console.log(that);
}
parent.child = function () {
console.log(that);
};
return parent;
},
});
The problem here is how the this variable is identified if you have a series of object lookups then a function call. Like this.
foo.bar.baz.qux();
The qux method has a this value equal to foo.bar.baz.
So in essence functions in javascript have a hidden argument this that is the object they are called on.
There is no way to modify this behavior in javascript.
You can reassign this using Function.bind.
var myArray = [1,2,3];
myArray.Parent.Child.bind( myArray )();
In my example, myArray.Parent.Child is the Function you defined in your example - then we use bind to create a copy of the function with this set to myArray, then we use the () operator to invoke it.
This can be reduced to a single line with a self-executing lambda (ES6):
( x => x.Parent.Child.bind( x )() )( myArray );
...which is equivalent to this in ES5:
( function( x ){ return x.Parent.Child.bind( x )() } )( myArray );

Javascript dynamically created functions in an object

I'm just studying javascript and I faced an issue related to scoping.
Here's the code
function User (properties) {
for (var i in properties) {
(function () {
this ['get' + i] = function () {
return properties [i];
};
}) ();
}
}
var me = new User ({
Id : 54,
Name : 'ohyou'
});
console.log (me.getName ());
console.log (me.getId ());
How I want it to work: it should create two functions getName and getId that belong to the me object.
How it works: it creates two functions just as I want, but they belong to the window
What I tried:
I tried removing the function on the line 3. It does what I want, but now it returns the name "ohyou" two times, instead of returning the id and the name
I tried using the functions from the window scope, the problem as in the previous case persists - it returns the name twice.
The question: what am I doing wrong and how do I make it work as I want?
P.S. Making this post using phone, sorry for possible typos or formatting issues. Also, please forgive me my english skills.
Try to understand why the following code works:
function User(properties) {
for (var i in properties) {
with ({ i: i, self: this, props: properties }) {
self["get" + i] = function () {
return props[i];
};
}
}
}
var me = new User({
Id: 54,
Name: "ohyou"
});
alert(me.getName());
alert(me.getId());
This is an example of one of the legitimate uses of the with statement.
I find the with statement to be more succinct than using an immediately invoked function expression (IIFE) as others are suggesting.
Edit: The with keyword is not bad if you use it correctly. There are some legitimate uses of with:
http://webreflection.blogspot.in/2009/12/with-worlds-most-misunderstood.html
The reason your code doesn't work is because every function has it's own value of this. Hence when you immediately invoke the function expression within the for loop, the value of this inside the function is no longer your new object. It is window. To solve that problem you could do something like:
(function (i, self, props) {
self["get" + i] = function () {
return props[i];
};
}(i, this, properties))
However using the with statement is clean and faster. It's faster because you're not calling a function.
function User (properties) {
var that = this;
for (var i in properties) {
(function (i) {
that ['get' + i] = function () {
return properties [i];
};
}) (i);
}
}
var me = new User ({
Id : 54,
Name : 'ohyou'
});
You can avoid all these closures and other things if you use Object.keys and then forEach, which already introduces a new scope. Then you'd have to pass the this value, which is the second parameter:
function User(properties) {
Object.keys(properties).forEach(function(k) {
this['get'+ k] = function() {
return properties[k]
}
},this)
}
One thing you must remember, any function that does not belong to any object, will always belong to window object.
For example if we modify your object and add a new method,
me.doSomeWork = function(){
this.myLuckyNumber = 10;
var that = this;
function doubleMyLuckyNumber(){
console.log(this); //window
that.myLuckyNumber = that.myLuckyNumber * 2;
}
doubleMyLuckyNumber();
};
me.doSomeWork();
console.log(me.myLuckyNumber) //outputs 20
So always save the reference to a var to use it in inner methods. You can use any of the way that others suggested but I prefer James emanon's approach.

Can you create functions with custom prototypes in JavaScript?

First of all, I don't want to add methods to Function.prototype. Doing that would make them available for all functions and that's not what I'm looking for.
In JavaScript you can create objects with custom prototypes like this:
function CustomObj() {}
CustomObj.prototype = {};
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomObj = new CustomObj(); //=> returns an object: {}
myCusomObj.sayFoo(); //=> 'foo'
You can also create array-like objects with custom prototypes like this:
function CustomArr() {}
CustomArr.prototype = [];
CustomObj.prototype.sayFoo = function () { return 'foo' };
var myCustomArr = new CustomArr(); //=> returns an ordered object: []
myCustomArr.sayFoo(); //=> 'foo'
What I'd like to do is use some kind of constructor to create a function with its own custom prototype in the same way. However, the following does not work:
function CustomFn() {}
CustomFn.prototype = function () {};
CustomFn.prototype.sayFoo = function () { return 'foo' };
var myCustomFn = new CustomFn(); //=> PROBLEM! returns an object: {}
myCustomFn.sayFoo(); //=> 'foo'
// ^^ Here, the prototype was applied but the output was not a function.
myCustomFn(); //=> TypeError: object is not a function
So is there any way to accomplish what I'm trying to do?
UPDATE
Maybe there's another way I could be asking this question that would make it a little clearer.
There's a problem with the idea of a closure:
function makeFn() {
var output = function () { /* do some stuff */ };
output.foo = function () { /* do some stuff */ };
return output;
}
var specialFn = makeFn();
Essentially, this technique gives me what I want. However, the problem is that every time I call makeFn, output.foo has to be created as a totally independent function that takes up its own memory. Gross. So I could move that method out of the closure:
var protoMethods = {
"foo" : function () { /* do some stuff */ }
};
function makeFn() {
var output = function () { /* do some stuff */ };
for (var i in protoMethods) {
Object.prototype.hasOwnProperty.call(protoMethods, i) &&
(output[i] = protoMethods[i]);
}
return output;
}
var specialFn = makeFn();
But now I have to manually do an iteration every time I call makeFn which would be less efficient than if I could just assign protoMethods to be the prototype of output. So, with this new update, any ideas?
It is a tricky thing indeed, more complicated than it should be if the language was designed well...
Basically, you just can't do it cleanly in current versions. Objects other than functions can not be callable.
In future Javascript versions, you can do it with a "proxy" object that can define a "call" handler. But it is still way too complicated and contrived in my opinion.
Another way to go about it is to make your object a real function, not a custom object. Then try to set its __proto__, which is non-standard yet but works in most modern browsers, except Opera and IE 8 or less. Also maybe set its constructor property for faking instanceof checks... such hacks are quite tricky though and results will vary a lot with environments.
The following example works fine on my Firefox:
http://jsfiddle.net/Q3422/2/
function MyFun() {
if (!this || this==window) {
return new MyFun();
}
var f = function() {
return "thanks for calling!";
}
f.__proto__ = MyFun.prototype;
f.constructor = MyFun;
return f;
}
MyFun.prototype = {
foo: function() {
return "foo:" + this();
},
__proto__: Function.prototype
};
var f = new MyFun();
alert("proto method:"+f.foo()); // try our prototype methods
alert("function method:"+f.call()); // try standard function methods
alert("function call:"+f()); // try use as a function
alert('typeof:' + typeof f); // "function", not "object". No way around it in current js versions
alert('is MyFun:' + (f instanceof MyFun)); // true
alert('is Function:' + (f instanceof Function)); // true
Just wanted to add that you should not be worried about "copying" functions to each instance of your objects. The function itself is an object, so is never really copied, nor is it recompiled or anything. It does not waste memory, except for the function object reference itself and any closure variables.
Iterating over the prototype to copy it should not concern you as well, I guess you will not have a gazillion methods.
So your own last solution is probably the best if you need to support environments where proto is not settable, and you are not worried that your prototype might get extended after some objects already got created and they may not pick up the changes.
You're at the heart of what inheritance in JavaScript is all about. Yes, since prototypes are objects, you'll want to set the prototype of CustomFn to an object instead of a function.
But that object can come from another function:
function ParentFn() {}
function CustomFn() {}
CustomFn.prototype = Object.create(ParentFn.prototype);
CustomFn.prototype.sayFoo = fun ...
If you don't have ES5 or a polyfill:
CustomFn.prototype = (function() {
function F(){}
F.prototype = ParentFn.prototype;
return new F();
}());
Some may tell you just to do the following but the above way is better:
CustomFn.prototype = new ParentFn();
I tried that too, when working on V library. I wanted to override the Function constructor to enforce a restricted syntax of constructor functions, that I'm calling "class functions" (and I'm confident to do so).
Answer is no, using the new operator you can only create new "object"s, but not new "function object"s.
However you can use a constructor function both as a constructor and as a function!
var CustomFn = function () {
if (this instanceof CustomFn) {
// here we are 'new CustomFn()'
}
else {
// here we are 'CustomFn()' or 'CustomFn.call()'
}
};
Or as I believe is the better concept, to do the function in first place and then let the constructor go:
var CustomFn = function () {
if (!(this instanceof CustomFn)) { // functioning
// here we are 'CustomFn()' or 'CustomFn.call()'
return new CustomFn(); // or return undefined or throw
}
// constructing
// here we are 'new CustomFn()'
// BaseCustomFn.call(this);
};

alternative for the var self = this pattern

I am looking for var self = this alternative plan.
var Animal = function(name){
this.name = name;
this.arr = [1,2,3,4];
this.inc = function(num){
return num + 1;
};
this.fireArr = function(){
var self = this;
this.arr.forEach(function(item){
console.log(self.inc(item));
});
};
};
var dog = new Animal("dog");
console.log(dog.fireArr());
My fiddle is here.
http://jsfiddle.net/haradashinya/TtYpc/
Do you have any idea?
Thanks in advance.
You can set the second argument to forEach, which is the this value.
this.arr.forEach(function(item){
console.log(this.inc(item));
}, this);
You can use .bind() to make sure the function is called with the right this value:
function fireArr() {
this.arr.forEach(function(item){
console.log(this.inc(item));
}.bind(this));
}
But imho the self (that, _this) variable is easier to understand, because it directly states that not the normal this value is used, although one would expect it (e.g. in an event handler, or jQuery's each()). Especially on long functions, where you don't see the bind() in the end, this is of importance. Also, some ancient browsers do not support bind() and you would need to shim it.
So, for any in-place function expressions I recommend the use of a dereferencing variable.
But it can be of great use when you have a method defined somewhere, normally using this to point to the current object as it is common in that context, and then the method should be used somewhere else. Instead of a var self-wrapper, you can and should use bind for simplicity and clarity. Your example offers quite a good demo (assuming the inc method used the this keyword):
this.arr.forEach( this.inc.bind(this) );
(although forEach() allows us to pass a custom this argument - event attachers for example don't)
In your example, the inc function doesn't use the this value, so it doesn't need to be a method. You can define it as a local function:
var Animal = function ( name ) {
this.name = name;
this.arr = [ 1, 2, 3, 4 ];
var inc = function ( num ) {
return num + 1;
};
this.fireArr = function () {
this.arr.forEach(function ( item ) {
console.log( inc( item ) );
});
};
};

What is context in _.each(list, iterator, [context])?

I am new to underscore.js. What is the purpose of [context] in _.each()? How should it be used?
The context parameter just sets the value of this in the iterator function.
var someOtherArray = ["name","patrick","d","w"];
_.each([1, 2, 3], function(num) {
// In here, "this" refers to the same Array as "someOtherArray"
alert( this[num] ); // num is the value from the array being iterated
// so this[num] gets the item at the "num" index of
// someOtherArray.
}, someOtherArray);
Working Example: http://jsfiddle.net/a6Rx4/
It uses the number from each member of the Array being iterated to get the item at that index of someOtherArray, which is represented by this since we passed it as the context parameter.
If you do not set the context, then this will refer to the window object.
Extras:
To answer the What's the advantage of that? Why not just refer to someOtherArray[num] rather than this[num]? upvoted question found in the comments below, let's move the anonymous iteratee callback into a function for easy re-use:
const someOtherArray = ["name","patrick","d","w"];
const yetAnotherArray = ["what","goes","here","?"];
function alertStr(num){
alert( this[num] );
}
_.each([1, 2, 3], alertStr, someOtherArray);
_.each([1, 2, 3], alertStr, yetAnotherArray);
You can see how the this reference allows us to re-use the iteratee function across multiple _.each calls with different context values. This would not work if we had the someOtherArray hardcoded inside the iteratee.
context is where this refers to in your iterator function. For example:
var person = {};
person.friends = {
name1: true,
name2: false,
name3: true,
name4: true
};
_.each(['name4', 'name2'], function(name){
// this refers to the friends property of the person object
alert(this[name]);
}, person.friends);
The context lets you provide arguments at call-time, allowing easy customization of generic pre-built helper functions.
some examples:
// stock footage:
function addTo(x){ "use strict"; return x + this; }
function pluck(x){ "use strict"; return x[this]; }
function lt(x){ "use strict"; return x < this; }
// production:
var r = [1,2,3,4,5,6,7,8,9];
var words = "a man a plan a canal panama".split(" ");
// filtering numbers:
_.filter(r, lt, 5); // elements less than 5
_.filter(r, lt, 3); // elements less than 3
// add 100 to the elements:
_.map(r, addTo, 100);
// encode eggy peggy:
_.map(words, addTo, "egg").join(" ");
// get length of words:
_.map(words, pluck, "length");
// find words starting with "e" or sooner:
_.filter(words, lt, "e");
// find all words with 3 or more chars:
_.filter(words, pluck, 2);
Even from the limited examples, you can see how powerful an "extra argument" can be for creating re-usable code. Instead of making a different callback function for each situation, you can usually adapt a low-level helper. The goal is to have your custom logic bundling a verb and two nouns, with minimal boilerplate.
Admittedly, arrow functions have eliminated a lot of the "code golf" advantages of generic pure functions, but the semantic and consistency advantages remain.
I always add "use strict" to helpers to provide native [].map() compatibility when passing primitives. Otherwise, they are coerced into objects, which usually still works, but it's faster and safer to be type-specific.
Simple use of _.each
_.each(['Hello', 'World!'], function(word){
console.log(word);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Here's simple example that could use _.each:
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
x.addItem('banana');
x.addItem('apple');
x.addItem('kiwi');
x.show();
Output:
items: [ 'banana', 'apple', 'kiwi' ]
Instead of calling addItem multiple times you could use underscore this way:
_.each(['banana', 'apple', 'kiwi'], function(item) { x.addItem(item); });
which is identical to calling addItem three times sequentially with these items. Basically it iterates your array and for each item calls your anonymous callback function that calls x.addItem(item). The anonymous callback function is similar to addItem member function (e.g. it takes an item) and is kind of pointless. So, instead of going through anonymous function it's better that _.each avoids this indirection and calls addItem directly:
_.each(['banana', 'apple', 'kiwi'], x.addItem);
but this won't work, as inside basket's addItem member function this won't refer to your x basket that you created. That's why you have an option to pass your basket x to be used as [context]:
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
Full example that uses _.each and context:
function basket() {
this.items = [];
this.addItem = function(item) {
this.items.push(item);
};
this.show = function() {
console.log('items: ', this.items);
}
}
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], x.addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In short, if callback function that you pass to _.each in any way uses this then you need to specify what this should be referring to inside your callback function. It may seem like x is redundant in my example, but x.addItem is just a function and could be totally unrelated to x or basket or any other object, for example:
function basket() {
this.items = [];
this.show = function() {
console.log('items: ', this.items);
}
}
function addItem(item) {
this.items.push(item);
};
var x = new basket();
_.each(['banana', 'apple', 'kiwi'], addItem, x);
x.show();
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In other words, you bind some value to this inside your callback, or you may as well use bind directly like this:
_.each(['banana', 'apple', 'kiwi'], addItem.bind(x));
how this feature can be useful with some different underscore methods?
In general, if some underscorejs method takes a callback function and if you want that callback be called on some member function of some object (e.g. a function that uses this) then you may bind that function to some object or pass that object as the [context] parameter and that's the primary intention. And at the top of underscorejs documentation, that's exactly what they state: The iteratee is bound to the context object, if one is passed
As explained in other answers, context is the this context to be used inside callback passed to each.
I'll explain this with the help of source code of relevant methods from underscore source code
The definition of _.each or _.forEach is as follows:
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context);
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
Second statement is important to note here
iteratee = optimizeCb(iteratee, context);
Here, context is passed to another method optimizeCb and the returned function from it is then assigned to iteratee which is called later.
var optimizeCb = function(func, context, argCount) {
if (context === void 0) return func;
switch (argCount == null ? 3 : argCount) {
case 1:
return function(value) {
return func.call(context, value);
};
case 2:
return function(value, other) {
return func.call(context, value, other);
};
case 3:
return function(value, index, collection) {
return func.call(context, value, index, collection);
};
case 4:
return function(accumulator, value, index, collection) {
return func.call(context, accumulator, value, index, collection);
};
}
return function() {
return func.apply(context, arguments);
};
};
As can be seen from the above method definition of optimizeCb, if context is not passed then func is returned as it is. If context is passed, callback function is called as
func.call(context, other_parameters);
^^^^^^^
func is called with call() which is used to invoke a method by setting this context of it. So, when this is used inside func, it'll refer to context.
// Without `context`
_.each([1], function() {
console.log(this instanceof Window);
});
// With `context` as `arr`
var arr = [1, 2, 3];
_.each([1], function() {
console.log(this);
}, arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You can consider context as the last optional parameter to forEach in JavaScript.

Categories