Ambiguity in function definition in javascript - javascript

I am new to JS so bear with me.
What is the difference between
function get (attr) {
return function (object) { return object[attr]; }
}
and
function get (attr) {
return object[attr];
}
Why the first function worked but second did not? could not find a logical explanation for this.
Working Example code: https://jsfiddle.net/xf2u0ncL/

In your second code, where does object come from?! That's the entire problem.
The first code is used like this:
// same as getter = function (object) { return object['foo']; }
var getter = get('foo');
var value = getter({ foo: 'bar' });
get accepts a property name and returns a function which accepts an object and returns the value. Your second function doesn't accept any object at any point, so what's it supposed to return?

Looks like you've got a method where your trying to return a property of an object.
Both methods above will work but expect variables in different scopes and will be executed differently.
the first method returns a second method where you pass it an object to get the property from. So
get('foo')({foo: 'bar'}); //returns 'bar'
Whereas the second works like this
var object = {
foo: 'bar'
}
get('foo'); //returns 'bar';
the second excepts object to be a global variable or at least in a higher scope as it is not defined in the function it self.
the first method is passed an object to search for a property from. The first, whilst a little convoluted would be better and more easily tested than the second which expects and relies on global variables.
see fiddle: http://jsfiddle.net/b327nr74/

Related

Code behaving differently when i return 'this' in the function

I have created an object with an object literal and then created another object with Object.create(car).
var car = {
init: function(sound) {
this.sound = sound
return this
},
makeSound: function() {
console.log(this.sound)
}}
var aventador = Object.create(car).init("whatever")
aventador.makeSound()
The thing i want to know is that when i return this in init function, i can use the code like this:
var aventador = Object.create(car).init("Whatever")
aventador.makeSound() and it console logs Whatever
but when i dont return this in the init function, it says undefined
and when i do something like the following:
var aventador = Object.create(car)
aventador.init("Whatever")
aventador.makeSound() it works even without returning this in the init function.
please explain in details whats happening?
The functions are properties of an object.
When you return this and use that return value, you get that object. You can then call another function on that object.
When you don't have a return statement, you get undefined. undefined is not that object and the functions are not properties of undefined.
check this, the above statement having 2 parts an object variable called aventador it is assigned with the statement Object.create(car).init("whatever"). In your initial code this statement returning this as the object context. So aventador will get an object instance and it will call the makeSound method.
In the second method you are actualy creating the parent object using the statement var aventador = Object.create(car). This will automaticaly create an Object of type car and aventador have an instance of car. so aventador can be used to call both init and makeSound method using the object.
The default return value of a function is always undefined. In your case, if init() doesn't return this, then it returns undefined. Obviously when you access something with undefined always throws an error.
Hope that answers your doubt

why am I getting undefined when using `this`? JS [duplicate]

Given an Array Literal inside a JavaScript Object, accessing its own object's properties does not seem to work:
var closure = {
myPic : document.getElementById('pic1'),
picArray: [this.myPic]
}
alert(closure.picArray[0]); // alerts [undefined]
Whereas declaring an Array Item by accessing an other JavaScript Object seem to work
​var closure1 = {
​
​ myPic : document.getElementById('pic1')
​}
​
​var closure2 = {
​
​ picArray: [closure1.myPic]
​}
​
​alert(closure2.picArray[0]); // alerts [object HTMLDivElement]
Example:
http://jsfiddle.net/5pmDG/
The this value will not work like that, it refers to a value determined by the actual execution context, not to your object literal.
If you declare a function member of your object for example, you could get the desired result:
var closure = {
myPic: document.getElementById('pic1'),
getPicArray: function () {
return [this.myPic];
}
};
//...
closure.getPicArray();
Since the this value, inside the getPicArray function, will refer to your closure object.
See this answer to another question, where I explain the behavior of the this keyword.
Edit: In response to your comment, in the example that I've provided, the getPicArray method will generate a new Array object each time it is invoked, and since you are wanting to store the array and make changes to it, I would recommend you something like this, construct your object in two steps:
var closure = {
myPic: document.getElementById('pic1')
};
closure.picArray = [closure.myPic];
Then you can modify the closure.picArray member without problems.
The this property does not point to the closure object. If we were to define the myPic property on the global scope, then you will see picArray initialized with that value. Consider this example:
<script>
window.myPic = "Global myPic";
var closure = {
myPic : document.getElementById('pic1'),
picArray: [this.myPic] // this refers to the global object
};
console.log(closure.picArray); // ["Global myPic"];
</script>
this is one of the hardest concepts in JavaScript. You might like this article on the topic.

Get the right this-context in an overwritten function

I have the following problem:
I'm trying to overwrite a function to apply it then with angular ($scope.$apply()), but my this-context doesn't seem to be the right one.
The original function (in another file) looks like the following:
Anno.prototype.switchTo = function(otherAnno) {
if (otherAnno != null) {
this.hideAnno();
return otherAnno.show();
} else {
console.warn("Can't switchTo a null object. Hiding instead.");
return this.hide();
}
};
And then in another file I "overwrite" it like the following:
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
switchToFunction(otherAnno);
$scope.$apply();
};
So actually I save the original function, then redefine the original function to call the original one and then apply the scope.
Now comes the problem: As you can see, the function uses this.hideAnno() in it, but in my redefined function, the context is another one, that's why chrome is throwing an error saying "this.hideAnno() is not a function". But now I'm not sure how I can get the right context. I tried to understand this, but I find JavaScript is so confusing that I really don't get it.
Can somebody help me understand that JavaScript confusion?
When a function is called as a method in js, the this inside of it refers to the object the method belongs to.
On the other hand, when a function is called on its own, this inside of it refers to the global object or undefined in strict mode.
You are extracting (and then calling) a function defined as a method into a standalone function, that's why this doesn't do what you expect it to.
What you need in this case is to call or apply your switchToFunction, setting the value of this to what you need. In other words you set the this of the old method to be the this of the new method you created:
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno, that) {
switchToFunction.call(this, otherAnno); // sets `this` of the old method to be this of the new method you created
$scope.$apply();
};
To understand the problem, I think first we should understand how this keyword works and how it can be tweaked.
In JavaScript the this object inside of any function will be the object on which the method is invoked.
Consider these following example,
var obj1 = {
foo: function() {
console.log(this);
}
};
function bar() {
console.log(this);
}
Now when the methods are invoked we get output like below,
obj1.foo(); // obj1
bar(); // window
Because foo method is invoked on obj1, so this inside of foo method became obj1. Similarly this inside bar method will be window object.
Now, what if I want to invoke the bar method with obj1 as this inside the function. For this JavaScript provides call, apply and bind methods to change the this of function dynamically. Let us see how we can achieve this using call method.
bar.call(obj1); // obj1
Similarly,
obj1.foo.call(window); // window
call method takes an thisArg object as argument which will be this inside the bar function. And if bar function also expects arguments that also can be passed through call method following thisArg. See MDN for information about call.
So the solution for your problem will be,
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
switchToFunction.call(this, otherAnno);
$scope.$apply();
};
Hope this makes it clear for you to understand the problem.

JS call method, why not just use brackets?

So, I've got some code that looks like this (genericised from a closed-source project).
UserWizard = {
init: function(name) {
this.firstInit.call(name);
this.secondInit.call(name);
},
firstInit: function(name) {
// ...
},
secondInit: function(name) {
// ...
}
}
It's the first time I've ever seen the call method used in JS and it appears to be exactly the same as just calling the function with brackets, e.g.
this.firstInit(name);
So what is call doing here? Does it act any differently?
When calling
UserWizard.init('some name');
The this object of the firstInit and the secondInit functions will be the string 'some name' and the parameter name value will be undefined
UserWizard.firstInit('some name')
Is the same as:
UserWizard.firstInit.call(UserWizard, 'some name');
Hope I was clear
call() is not doing what you think it's doing here. It's actually changing the context of this within both firstInit and secondInit.
Function.prototype.call() is the link to the mozilla docs, quoting from there there:
A different this object can be assigned when calling an existing function. this refers to the current object, the calling object. With call, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object. - by Mozilla Contributors
There's another function Function.prototype.bind() which I'd encourage you to look at. I find generally I use this more often, but it's a similar sort of idea, used to assign this to the function when it may get called later on. This is good for preventing issues like:
var person = {
name: 'First Last',
getName: function (){
return this.name;
}
};
var getName = person.getName;
getName(); // returns undefined as `this` is the global window object

Can you get the object of a method?

I'm just wondering if I can make some of my helper functions(for stuff like benching, logging and caching) a bit neater. Right now I'm doing this
function doSomethingToMethodsObject(object, methodname) {
//do things to object and object[methodname]
}
so I can use it like this
var myObject = function() {
this.myString = "hello";
this.myMethod = function() { return this.myString; }.bind(this);
doSomethingToMethodsObject(this, "myMethod");
}
but it would be better if I could call it like this
doSomethingToMethodsObject(this.myMethod);
and then break down the function reference to this and "myMethod" inside doSomethingToMethodsObject.
So is there a way to figure out what objects a function belongs to?
So is there a way to figure out what objects a function belongs to?
A function does not belong to only a single object. There can be lots of references to that same function on lots of different objects. So, no you can't specifically figure out what object a function belongs to by purely looking at the function.
In fact, why you pass this.myMethod as an argument, there is no connection whatsoever to the this part that is passed. It just gets a reference to the function and passes that.
You can use .bind() to pass a bound reference to the function, but that only lets you call the method in the context of the right object - it doesn't allow you to separate out the object from the method. If you need both object and method separately in your function, then you will need to find some way to make them both separately accessible inside the function - the most obvious way to do that is just pass them both as arguments.
Depending upon the specific context (which you don't really share very much of), sometimes you can use parent scoped variables like var self = this; to maintain a reference to this that can be accessed by child functions, but I'm not sure that applies to what you're doing.
Here are some options:
doSomethingToMethodsObject(this, this.myMethod);
doSomethingToMethodsObject({obj: this, method: this.myMethod});
When you use this.myMethod, JS creates a reference whose base is this and whose referenced name is "myMethod".
However, when you use it as an argument, JS resolves the reference into the property value. Therefore, in doSomethingToMethodsObject, it's too late to get the base.
The only way to obtain the base of this.myMethod is when myMethod is an accessor property with a getter which redirects to the underlying object value. Then you can use this inside the getter, and store it in a property of the underlying value.
For example:
var obj = {
_myMethod: function(arg) { /* Underlying function */
return {thisArg: this, arg: arg};
},
get myMethod() { /* Stores reference parts and redirects */
return Object.assign(this._myMethod, {
refBase: this,
refName: "_myMethod"
});
}
};
function doSomethingToMethodsObject(value) {
return value.call(
value.refBase,
value === value.refBase[value.refName]
);
}
obj.myMethod(123); // {thisArg: obj, arg: 123}
doSomethingToMethodsObject(obj.myMethod); // {thisArg: obj, arg: true}

Categories