0

How in world is the following is outputting "undefined" instead of a "number"?

<script>

var foo = {
  bar: function(){ return this.baz; },
  baz: 1
}

console.log(typeof (f = foo.bar)());

</script>

Note: The code is exactly right and not a typo. I mean (f = foo.bar)() only here which is a valid code.

Deadpool
  • 6,416
  • 5
  • 32
  • 64
  • Your code is valid, and the result is as expected: you execute `f`, and `this` is not bound when you do, hence `this` is the window object. In strict mode this would have triggered an error as `this` would have been undefined in that case. See duplicate reference. – trincot Feb 26 '19 at 08:04
  • 3
    `(f = foo.bar)` is an expression which results in the value `function () { return this.baz }`, which you're calling like `(function () { return this.baz })()` for all intents and purposes. There's no context to the call, hence no [explicit] `this`. – deceze Feb 26 '19 at 08:04
  • 1
    Please avoid asking the same question repeatedly – adiga Feb 26 '19 at 08:05
  • Ya, thats good. But, pls answer while making such assignment -- in memory will f get a new memory location with function written? or will it get a reference to `foo.bar` so that if we make changes later in function, same will reflect in f? – Deadpool Feb 26 '19 at 08:07
  • 1
    No, you're assigning the *value* of `foo.bar`, which is `function () ...`. If you assign something else to `foo.bar` later, that won't reflect on `f`. – deceze Feb 26 '19 at 08:08
  • @Deadpool, functions are objects and expressions can return objects, in this case a function. It is a reference. You call it without a `this` bound to it. – trincot Feb 26 '19 at 08:09
  • @deceze : thanks, meaning it will get its own copy of function with **new memory location** (unbound and unlink in anyway to the original `foo object` or `foo.bar` function)? – Deadpool Feb 26 '19 at 08:10
  • `typeof (f = foo.bar).bind(foo)()` should return number – adiga Feb 26 '19 at 08:11
  • 3
    functions are not inherently bound to a `this`. It is the way you *call* them that determines the binding of `this`. It has nothing to do with memory. If you call a function that you get from an expression, then there is no specific `this` binding (the default applies). If you call it with dot notation (`a.b()`) then `a` will be `this`. It is the *calling* that determines it. All this info can be found in the duplicate reference though. – trincot Feb 26 '19 at 08:12
  • 1
    The function object is still the same. But `f` won't change if you assign something else to `foo.bar = 42`. If you *modify the function object itself*, that will reflect on both. E.g. `foo.bar.baz = 42; console.log(f.baz)`. – deceze Feb 26 '19 at 08:12
  • 2
    Also note that `f` is an implicitly declared global variable as side effect of an expression here, which will also raise errors in strict mode. You should not be writing such code normally. – deceze Feb 26 '19 at 08:14

1 Answers1

3

Because at the execution time, the context is "window", so there is no variable "baz" declared on window object.

n1kkou
  • 2,848
  • 2
  • 16
  • 27
  • But, why the execution context would go to window of instead by obj foo? can you explain? – Deadpool Feb 26 '19 at 08:02
  • 1
    And a little bit of more explanation: at execution time, you assign f to be equal to the method "bar" of function foo. Then, it's like you would write: f.bar = function(){return this.baz; }. But in this context, "this.baz" is referencing window.baz, which is not declared (because the baz property, only existing on the local scope of the variable foo). If you would inherited all the methods and properties from a "class-like" object, then you could easily inherit that property, so it would be availble on the f variable aswel. – n1kkou Feb 26 '19 at 08:05
  • 1
    @n1kkou It's decidedly *not* like `f.bar = ...` at all. – deceze Feb 26 '19 at 08:06
  • What is the case where you want to do this check? So I can understand your context and not give you a misleading explication. – n1kkou Feb 26 '19 at 08:07
  • Probably you have this expectation, because you assign only the method to the f variable. Instead, if you just assign f = foo, then you try to log (typeof (f.bar)()), then you will get a result of type number. – n1kkou Feb 26 '19 at 08:13
  • Please note that "execution context" and `this` binding are different concepts. Mixing them up can create confusion. – trincot Feb 26 '19 at 08:15
  • Yes, this is also true. My explanation was a little bit confusing, mixing terms – n1kkou Feb 26 '19 at 08:17