Talk is cheap; show me the code.
// equals to this.test = "inside window"
var test = "inside window";
function f () {
console.log(this.test)
};
var obj = {
test: "inside object",
fn: f
};
obj.fn(); // "inside object" --> fine
(obj).fn(); // "inside object" --> fine
(1, obj).fn(); // "inside object" --> fine
(obj.fn)(); // "inside object" --> fine
(0 || obj.fn)(); // "inside window" --> why?
// reference equality check
console.log(
f === obj.fn &&
(obj.fn) === f &&
f === (1, obj.fn)
); // all equal :/
I had read ydkjs book and Im familiar with call-site and dynamic this
binding, but I don't understand why the last function call has window
as its this
context; in this controlled experiment that only thing
that is changed ()
and comma operator
and as you can see in the last statement comma operator
is doing something weird. I suspect it does an assignment when it returns the value (since if we do an assignment the same result happens) but I'm not sure.
The effect is also seen on &&
, ||
operators: (0 || obj.fn)()
In JavaScript, the functions wrapped with parenthesis are called “Immediately Invoked Function Expressions" or "Self Executing Functions. The purpose of wrapping is to namespace and control the visibility of member functions. It wraps code inside a function scope and decrease clashing with other libraries.
The parentheses encapsulating the function declaration tell the JavaScript engine to execute the code immediately after it's parsed.
Parenthesis are used in an arrow function to return an object. Parenthesis are used to group multiline of codes on JavaScript return statement so to prevent semicolon inserted automatically in the wrong place.
It means that the first function ( $filter ) returns another function and then that returned function is called immediately. For Example: function add(x){ return function(y){ return x + y; }; } var addTwo = add(2); addTwo(4) === 6; // true add(3)(4) === 7; // true. Follow this answer to receive notifications.
Given:
foo.bar()
Inside bar
, this
will be foo
.
(There are exceptions, such as when bar
is defined with an arrow function, but they don't apply in this case).
Given:
const bar = foo.bar;
bar();
Now the function has been called without the context of foo
so this
is now the default object (which is window
in a browser).
The expression: (1, foo.bar)
evaluates as the right-hand side. This is the function.
Just as if you had copied it to a variable, this disconnects the function from the object before you call it, so you get the same effect.
There's no assignment because you haven't involved a variable, but you are calling the result of an expression and not the object method directly.
To support @Quentin's answer, the comma operator indeed returns the last operand as a function without context (hence window) rather than the one from the object's blueprint.
Only on calling apply/call over the function with the object, it can gain the context back.
(1, a.fn).call(a); // "inside object"
(1, a.fn).apply(a); // "inside object"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With