What do empty parentheses () after a function declaration do in javascript? [duplicate] - javascript

This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 8 years ago.
I'm trying to read the Prototype source. I've come to this part.(Unfortunately, this snippet is in the beginnning).
What does this () mean?
Browser: (function(){
var ua = navigator.userAgent;
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
return {
IE: !!window.attachEvent && !isOpera,
Opera: isOpera,
WebKit: ua.indexOf('AppleWebKit/') > -1,
Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
}
})(),
I am referring to the last line before the comma?

The code is defining an anonymous function (the (function (){ ... }) bit) and then calling it (with no arguments). It then assigns the value to the Browser property of the object that is presumably being defined outside of your code snippet.
You could also define the function somewhere:
function myFunction() {
var ua = navigator.userAgent;
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
return {
IE: !!window.attachEvent && !isOpera,
Opera: isOpera,
WebKit: ua.indexOf('AppleWebKit/') > -1,
Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
MobileSafari: /Apple.*Mobile.*Safari/.test(ua)
}
and then call it:
var foo = myFunction();
and then assign the value:
...
Browser: foo,
...
One downside with doing it that way is that you "pollute your namespace" with a function and a variable that you won't use anywhere else. The second issue is that you can't use the value of any locally-scoped variables in your function definition (the anonymous function behaves as a closure).

(function () {}) creates an anonymous function.
Adding the () to the end calls the function that was just created.
In the case of this particular function, the anonymous function returns several properties to the Browser object. So, you end up with boolean values for, e.g., Browser.IE, Browser.Opera, etc.

it calls the anonymous function that was just declared, effectively causing the "block" to be evaluated.

It's a simple function call, no different than foo() except it's invoking an anonymous function literal, the result of the function is assigned to the Browser property.

Related

How to get context of the object that calls a method? 'This' doesn't work. JS [duplicate]

This question already has answers here:
ES6 arrow function and lexical scope inside a function [duplicate]
(2 answers)
Closed 4 years ago.
How can I get the reference to what's being return to the method call? Like how we have the arguments variable to get all arguments being passed to a function. How can I get what's being returned to so I can chain a function?
let myFunc = function(obj, num){
if (typeof obj === 'number' && typeof num === 'undefined') {
num = obj;
obj = this;
}
console.log(obj.name);
console.log(num);
console.log(Object(this));
return obj;
};
let myObj = {
name: 'Devin',
};
myFunc(myObj, 1);
myObj.myFunc = myFunc;
myObj.myFunc(2).myFunc(3);
edit: It's written out this because it's currently used in many places that I will have to refactor down the road but do not have time to right now. So I'm trying to do a few changes that don't affect current code but will work the way I want moving forward. myFunc(myObj, 1) is current but I have done a minor refactor to inline like so... myObj.myFunc(myObj, 2).myFunc(myObj, 3) ... but I thought I could remove myObj as an argument since it's being returned.
edit 2: Changed arrow es6 function to using function keyword to keep this context and added console.log(Object(this)). But still getting undefined from myObj.name and Object(this) only gives the argument
ANSWER: The problem was that I was using an arrow function and that I had typeof num === 'number' instead of equal to 'undefined'. Thank you.
myFunc.bind(myObj) doesn't serve any good purpose because arrows cannot be bound. In order to use dynamic this it should be regular function, e.g. shorthand syntax:
let myObj = {
name: 'Devin',
myFunc(num) {
console.log(num);
return this;
}
};
myObj.myFunc(2).myFunc(3); // basically a noop

Why does 'this' return 'undefined' when referred in an arrow function but doesn't when called on an anonymous function? [duplicate]

This question already has an answer here:
this is undefined inside arrow function
(1 answer)
Closed 6 years ago.
I'm working with node.js v6.7.0 and while declaring an object with a reference to 'this' it returns undefined if it's inside an arrow function but when it's inside a regular anonymous function it returns the object itself (which is what I want)
eg
let obj = {
key: 'val',
getScopeWithArrow: () => {return this;}, //returns undefined
getScopeWithAnonymous: function() {return this;} //returns the object properly
}
Because arrow functions don't have their own this, they close over the this of the calling context. But non-arrow functions, if they're not bound, take this based on how they're called. I assume you're calling these functions like this:
obj.getScopeWithArrow();
obj.getScopeWithAnonymous();
In the first case, again, the arrow function doesn't get its own this so it doesn't matter how you're calling it. In the second case, it does matter, and calling it like that makes this within the call refer to the same object obj refers to.
Separately: In your example, you must be in strict mode, because this can only be undefined in strict mode.
Separately 2: With regard to your method names: this and "scope" have very, very little to do with one another.
Some examples:
function showThis(label, t) {
if (t === window) {
console.log(label, "(global object)");
} else {
console.log(label, t);
}
}
// Loose mode by default in a non-module script element
let obj = {
arrow: () => {
showThis("arrow says ", this);
},
normal: function() {
showThis("normal says ", this);
}
};
obj.arrow(); // global object (window on browsers)
obj.normal(); // obj
function foo() {
// Here, we're in strict mode
"use strict";
let obj = {
arrow: () => {
showThis("arrow says ", this);
},
normal: function() {
showThis("normal says ", this);
}
};
obj.arrow(); // undefined
obj.normal(); // obj
}
foo();
According to developer.mozilla.org (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
No binding of this
Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.
BUT
If the goal is to avoid writing function, you can avoid using the colon and declare your method with the new ECMA6 object function declaration syntax.
let obj = {
key: 'val',
getScopeWithParens() {return this;}, //returns object
getScopeWithAnonymous: function() {return this;} //returns the object properly
}
console.log(obj.getScopeWithAnonymous());
console.log(obj.getScopeWithParens());

Can you compare anonymous functions in javascript? [duplicate]

This question already has answers here:
how do I compare 2 functions in javascript
(6 answers)
Closed 6 years ago.
I need to detect whether two anonymous functions are the same.
In the console, why does the following line return false?
(function() { alert("hello"); }) === (function() { alert("hello"); })
Is there a comparison operator or other method to identify that these are 'functionally' the same?
EDIT:
People are asking for the use of this.
It's for removing a function that has been previously pushed into an array of functions. See http://jsfiddle.net/w6s7J/ for a simplified test.
There is no real way to compare 2 different anonymous functions for 'functionality'.
You can check if they are the same object by using your example code.
var func = function () {
alert('hello');
};
alert(func === func);
The above will work, as you are checking to see that both objects are the same.
The only other method for comparing is to compare them as a string.
var func1 = function () {
alert("hello");
};
var func2 = function () {
alert('hello');
};
alert(func1.toString() === func2.toString());
Oops!, they are functionally the same, the difference is the quotes used, So this returns false.
(function() { alert("hello"); }) === (function() { alert("hello"); })
Returns false because they are different objects in javascript.
(function() { alert("hello"); }).toString() === (function() { alert("hello"); }).toString()
Returns true because they are the same strings.
Also function objects have a name property which return the name of the function (but it does not work in IE):
var a = function b() {}
alert(a.name);//write b

JavaScript call function inside a function by variable name [duplicate]

This question already has answers here:
dynamically call local function in javascript
(5 answers)
Closed 8 years ago.
I'm having a difficulty calling a function inside of another function when its name is in a variable:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
function b() {
alert('got it!');
}
b(); // WORKS AS EXPECTED
x = 'b';
[x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
}
}
inner.a();
}
obj.f();
I tried prefixing [x]() with different scope paths but so far w/o success. Searching existing answers did not turn up anything. It works with this[x]() if b() is placed directly inside object inner. I would like to keep b() as a function inside function a() because of variable scope in function a(), otherwise I would need to pass many parameters to b().
////
Re duplicate question: Quentin provided a more elegant answer in this thread imo.
There is no sensible way of accessing an arbitrary variable using a string matching the name of the variable. (For a very poor way to do so, see eval).
[x](); // DOESN'T WORK
You're trying to call an array as a function
NEITHER this[x]()
The function isn't a property of the inner object.
window[x](), etc.
Since it isn't a global, it isn't a property of the window object either.
If you need to call a function based on the value of a string variable, then organise your functions in an object and access them from that.
function b() {
alert('got it!');
}
var myFunctions = {
b: b
};
x = 'b';
myFunctions[x]();
Try this. Currently you are assigning string to variable x, instead of a function variable.
x = b;
x();
The problem is with your assignment
use x = b instead of x = 'b' to assign the function object as the latter just assigns the string into x.
Once you fix your assignment you can invoke the function as
x();
a.x();
a[x]();
etc.
You should make array for the function and then access using name in your variable as follow:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
// set up the possible functions:
var myFuncs = {
b: function b() {alert('got it!');}
};
//b(); // WORKS AS EXPECTED --> commented this code
x = 'b';
myFuncs[x]();
}
}
inner.a();
}
The function declaration b will be captured in the closure of the anonymous function expression assigned as a.
When var is used in a closure, there is no (available in JavaScript) Object which gets assigned a property similar to what happens with window in the Global Scope.
Writing a function declaration effectively vars the name of the function.
If you really want to access a variable (i.e. b) by String, you will either need to create an Object which holds b similar to what you've done for a, or (and possibly dangerously) rely on an eval to convert "b" to b.
If you can't create the whole Object ahead-of-time, you can use this format
/* in (higher?) scope */
var fnRef = {};
// now when you
function b() {/* define as desired */}
// also keep a ref.
fnRef['b'] = b;
// fnRef['b']() will work **after this line**
let's say your code is like this:
//instead of x = 'b'
x = function(){}
then your solution could be like this:
var obj = {}
obj.f = function() {
var inner = {
a: function() {
function b() {
alert('got it!');
}
b(); // WORKS AS EXPECTED
//you can define it as a variable
var x = function(){};
//and call it like this
x();
//or define it like this
this[x] = function(){};
//and call it like this
this[x]();
//but you are creating an array [x] which is not a function
//and you are trying to call an array????
[x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
}
}
inner.a();
}
obj.f();

Why does this return a reference to the global window object, even though 'this' is within another function

if (typeof obj == 'undefined') {
obj = {};
}
obj.thing = new function () {
if (typeof this.global == 'undefined') {
this.global = (function () {return this;})();
}
}
this.global is assigned to this inside of a function. So, why does this return a reference to the window object?
console.log(this) > DOMWindow
console.log(obj.thing.global) > DOMWindow
console.log(window) > DOMWindow
I would love to understand this better.
In ES 3 and ES 5 there is a this keyword associated with every execution context (ES 3) or Lexical Environment (ES 5). The value is set according to the rules for entering global or function code as described in ECMA-262 §10.4.
In your code you have:
this.global = (function () {return this;})();
Where the result of calling an anonymous function is assigned to this.global. Within that anonymous function, the value of this is set according to the algorithm in §10.4.3.
Since the function is called without setting the value of this, and the code is not in strict mode, the value of this is set to the global object (which, in a browser, is generally the window object) per step 2 of the algorithm.
If the code was in strict mode, then the value of this within the anonymous function would be undefined, which is the value that would be assigned to this.global.
this is a keyword which always returns the current context. Try this:
if (typeof obj == 'undefined') {
obj = {};
}
obj.thing = new function () {
if (typeof this.global == 'undefined') {
var self = this;
this.global = (function () {return self;})();
}
}
The problem is, that within your self-invoking anonymous function, the context is the global object aka window there. So it returns the window reference. Even if the new keyword creates a new object as context for your outer function. That outer context does not matter for the invocation of your self-invoking function.
To avoid that, you can modify the code slightly into:
obj.thing = new function () {
if (typeof this.global == 'undefined') {
this.global = (function (that) {return that;})(this);
}
}
this in javascript is really tricky. It does not mean what you think it means and can indeed have its value substituted in lots of little ways depending on how the function is invoked. Although it can help with optimization and gives you a certain degree of power and javascript-knowledge-points, you might want to avoid using it until you are comfortable with the idea.
It is better to think of 'this' as a special variable that contains extra information the invoker of the function passed in. If you want to lock down the value you can do it with the call/apply methods on functions or the browser Function.bind or _.bind in libraries like underscore.js.
var x = {
name: "George",
hiThere: function() { return "hi "+(this.name || "no value") ; }
}
x.hiThere(); // hi George
var thisWillBeGlobal = hiThere;
thisWillBeGlobal() // hi no value
var manuallyBoundToGeorge = function() {
return x.hiThere();
}
manuallyBoundToGeorge(); //hi George (always)
manuallyBoundToFred = function() {
return x.hiThere.call({name: 'Fred'});
}
manuallyBoundToFred(); //hi Fred (always)
var hiGeorge = Function.bind(x.hiThere, x);
hiGeorge(); //hi George (always) - same as manual bind above
notice that Function.bind is not avilable in older browsers and it is generally preferred to use something like underscroe's _.bind
You would of course still use this when working with libraries like jquery that pass information through it.

Categories

Resources