3

Maybe this is a newbie question, but I cannot find or think out the explanation.

Start the Node.js console, and:

> global.hasOwnProperty === hasOwnProperty
true

Then why

> global.hasOwnProperty("x")
false

but

> hasOwnProperty("x")
TypeError: Cannot convert undefined or null to object
at hasOwnProperty (<anonymous>)
at repl:1:1
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:96:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:313:29)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer.<anonymous> (repl.js:513:10)
at emitOne (events.js:101:20)

?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexander Mihailov
  • 1,050
  • 1
  • 12
  • 19
  • 1
    Personally, I dislike these theoretical questions that don't show what actual problem you're trying to solve. In Javascript and also in node.js, there is no standard definition of a globally accessible function named `hasOwnProperty()` that can be accessed without any prefix so you should not be using one. If you describe the problem you're actually trying to solve, then we can better explain how you should be coding it. – jfriend00 Jan 05 '17 at 20:55
  • 1
    @jfriend00 [according to mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty#Specifications), there is a standard ecmascript definition for `hasOwnProperty` function. – Yerko Palma Jan 05 '17 at 20:59
  • 1
    @YerkoPalma I believe he refers to one being accessible globally, as browser and node have different concepts of a global object. – Joseph Jan 05 '17 at 21:00
  • @YerkoPalma - I'm aware of `Object.prototype.hasOwnProperty()` which would also be available on the `global` object in node.js since it derives from Object. I'm not aware of a standalone version (called without any prefix) that is in any standard. Can you point to any std doc on that? – jfriend00 Jan 05 '17 at 21:00
  • It's worth noting that this also manifests in Chrome for me (with `window` instead of `global`, of course). There surely *is* a specification that maps how properties on the global object are made available as top-level variables, right? And one that specifices whether and how the global object inherits from `Object.prototype`? I wouldn't be surprised if Node doesn't have such a spec, but WebIDL might do so for the browser, if ECMAScript doesn't. (@jfriend00) – apsillers Jan 05 '17 at 21:02
  • But it doesn't matter _which_ one is the global object, the thing is, it is an object, so it inherits the object prototype functions, which includes the `hasOwnProperty` function. – Yerko Palma Jan 05 '17 at 21:03
  • The same error message will manifest when doing `Object.prototype.hasOwnProperty.call(null, 'x')` which could only mean calling it directly causes `this` to be something other than the global object (which you'd normally expect on directly-called functions). The spec doesn't mention how `this` is determined tho. http://www.ecma-international.org/ecma-262/6.0/#sec-object.prototype.hasownproperty but I may be reading it wrong. – Joseph Jan 05 '17 at 21:04
  • 4
    My point is that if you want to see if the `global` object has a property, then use `global.hasOwnProperty()`. Works like a champ. Problem solved. If you're trying to do something else besides check if the global object has a property, then describe that problem so we can advise a different solution. Calling a method without an object reference as in `obj.method()` or using `.call()` or `.apply()` is asking for trouble and probably causes problems with `this` when `hasOwnProperty()` executes. But frankly, I'm not all that interested in why because it's the wrong way to code it. – jfriend00 Jan 05 '17 at 21:05
  • 1
    @JosephtheDreamer `this` is determined by the runtime semantics of a function call expression: http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls – apsillers Jan 05 '17 at 21:08
  • 1
    sorry @jfriend00 I didn't mean to bother you. If one does the same in a browser it works just fine (there is no difference calling `window.hasOwnProperty` and `hasOwnProperty`). Many people write `alert()`, for example, instead of `window.alert()` and it does not raise comments like "there is no standard definition of ..." - it just works. But there is a difference in node.js. And maybe you are right - maybe it is some odd side effect. I just wanted to know ... if it is not important enough for this site I could ask somewhere else. Thanks anyway! – Alexander Mihailov Jan 05 '17 at 21:11
  • 1
    `alert()` is just a global function. It's not a method that carries out an operation on the object it is attached to. `hasOwnProperty()` is a method that needs to be called in the context of a particular object because it operates on that object. If you try calling `Object.prototype.hasOwnProperty("foo")` that won't work either. n It would need to be `Object.prototype.hasOwnProperty.call(someObj, "foo")` or `someObj.hasOwnProperty("foo")`. Same with `global`. – jfriend00 Jan 05 '17 at 21:15
  • 1
    @jfriend00 I do not quite agree with you. 1) alert is not a global function , but a method of the `window` object. [link](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) 2) how would you comment [this](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) - especially the section called **Simple Call** – Alexander Mihailov Jan 05 '17 at 21:23
  • 1
    @AlexanderMihailov Global functions *are* methods of `window`. That's how global scope works. In fact, I think (mis)understanding how global scope works is at the heart of your confusion. (That said, I have a mild ideological disagreement with jfriend00; I think this is good question and an opportunity to learn about some low-level ECMAScript-specified behaviors.) – apsillers Jan 05 '17 at 21:25
  • 1
    @apsillers OK, but isn't the `hasOwnProperty` also a method of the window object? and so also global function (according Your logic?) – Alexander Mihailov Jan 05 '17 at 21:29
  • 1
    @AlexanderMihailov Yes it is! It is a "global function" insofar as the `hasOwnProperty` identifier is globally accessible from all scopes, and this is the case because it is a property that exists on `window` (via inheritance of `Object.prototype`). It can be called, because it is a function, but that doesn't mean it has a sensible result when called as bare `hasOwnProperty()`, of course, as jfriend00 already explained. – apsillers Jan 05 '17 at 21:33
  • 1
    @apsillers well at this point I could only repeat my question. In a browser the `hasOwnProperty` is mapped directly to the global scope (`window`). In node.js it is not so. Why ? (I mean here: the code works perfectly in the browser if you change `global` with `window`) – Alexander Mihailov Jan 05 '17 at 21:35
  • 1
    You are missing the `hasOwnProperty()` requires a `this` value in order to do it's job and that `this` value has to be the object you are trying to operate on. So calling `hasOwnProperty("foo")` only works if the default value of `this` when a function is called happens to be what you need it to be. In strict mode, that will NEVER be the case because `this` will be `undefined`. In non-strict mode, you "might" get lucky. But, the overall point is that a method that operates on an object MUST be called with the context of THAT particular object or it can't do it's job properly. – jfriend00 Jan 05 '17 at 21:38
  • 1
    `alert()` does not operate on an object so it can be called anyway you dang please and it will work just fine. `hasOwnProperty()` must be called in the context of a particular object (unless you're hoping the system magically defaults to the right `this` which will never be true in strict mode and should never be relied upon in good Javascript programming). Do you understand that `hasOwnProperty()` is a method of an object and must be given an object reference to operate on when called? That is the key here. – jfriend00 Jan 05 '17 at 21:39
  • 1
    When you just call `hasOwnProperty()`, how does the method know what object to operate on? There are zillions of potential objects. How does it know which one you're asking to look at a property on? Unless you're relying on non-strict mode assignment of `this` to the `window` object in a browser (which is a bad coding behavior), it will never work. Methods that operate on an object must be called with the context of the object that you want them to operate on or they can't do their job properly. – jfriend00 Jan 05 '17 at 21:41
  • I'd suggest you read [When you pass 'this' as an argument](http://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676) for some help in understanding what happens with `this` in a function call. You are essentially asking why wrong code happens to work in some environments. IMO, the learning here is how to write proper code that works in all environments rather than deep dive on why it happens to work in some environments. – jfriend00 Jan 05 '17 at 21:44
  • 1
    `alert()` is a global. It just happens that in a browser environment (for mostly bad historical reasons), all globals pre-ES6 are properties of the `window` object. In ES6, a global declared with `const` or `let` is NOT on the `window` object as Javascript/browsers try to correct bad behavior (globals declared with `var` still are on the `window` object in ES6 for backwards compatibility). node.js does not have the same bad behavior with globals and part of that is because you never actually get to run any code in the true global namespace since all code runs in a module context. – jfriend00 Jan 05 '17 at 21:48
  • @jfriend00 [in this link](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this) they explain how `this` is resolved in the case of a **simple call** and it works exactly so in Mozilla FF. They say "Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object:". So it seems that in **strict mode** a call does not default to the global object but to `null` (or `undefined` I dont no). And at this moment I learned something and I think this is the answer. Thank you sir! – Alexander Mihailov Jan 05 '17 at 21:51
  • 2
    Keep in mind that MDN documents the behavior that Firefox and mostly browsers in general use. The global object is one thing that is treated differently in node.js and you cannot assume all browser behaviors related to the global object are the same in node.js. Plus, please learn how to program in strict mode. All strict mode code works fine in non-strict mode and is a lot safer in ALL envrionments (that's why you should use it). If you are relying on some non-strict mode automatic setting of `this`, that is BAD code. Don't do it. Immediately change all your code to strict mode. – jfriend00 Jan 05 '17 at 21:55

4 Answers4

3

The issue here is that hasOwnProperty() is a method of an object and its entire function is to operate on properties of that object. As such, it only works if, when it is called, it is given a proper object context. Normally they are written methods, expect that object context is to arrive in the value of this when the method is invoked.

In most cases in JavaScript (except for functions defined with the arrow syntax), the value of this is determined by how a method is called. The usual and most common way to invoke a method on the appropriate object is with:

obj.method()

This will cause JavaScript to set this to obj when it called method().

If you do something like this:

var myFunction = obj.method;

And, then you call that method with no object reference as in:

var myFunction = obj.method;
myFunction();

Then, the object reference in obj is lost and is not given to the method in any way. The JavaScript interpreter will pick a default value for this.

In strict mode, this will be set to undefined and any method that attempts to use that value, expecting it to be an object reference, will fail.

In non-strict mode, a browser will set this to point to "some default value". In a browser, that is the window object. So, if you were trying to use the method on the window object, lo and behold, it would happen to work. I consider this somewhat of an accident, not good code.

IMO, the moral of the story is that any method that expects to be associated with an object should be called with an explicit object reference. Then, that removes all confusion, removes all difference between strict mode and non-strict mode and removes all difference between a browser and Node.js.

So why does this happen:

hasOwnProperty("x")

TypeError: Cannot convert undefined or null to object

If you're trying to call hasOwnProperty() to test a property of the global object in node.js, then call the method with the context of the global object as in:

global.hasOwnProperty("a")

That will work everywhere and is considered good and proper Javascript code. Calling it without the proper object context causes the this value to be set to a default value. In node.js, that default value will not necessarily be the global object. But, in all cases, you should NEVER rely on what that default value will be. Program correctly by always specifying the desired object reference and your code will work fine everywhere.


FYI, there are more ways to control what this is passed a function than just obj.method(). You can read about the other ways here in this other answer. They include things such as .call(), .apply(), arrow functions (in ES6), etc...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    @alexandermihailov - I've collected my comments into an answer. – jfriend00 Jan 05 '17 at 23:07
  • I think the essence of the answer is how `this` defaults to `undefined` or `global(window)` in `strict` \ `non-strict` mode. The details You describe go beyond that, but they are really good and will be really helpful for others. Thanks for the discussion! – Alexander Mihailov Jan 05 '17 at 23:14
1

Update 2017-01-16: Node.js does not work in strict mode until one sets it explicitly. Still there is a difference between Node.js in non strict mode and Firefox (in Firefox, the simple call to hasOwnProperty works without exception). I'll search further and update this answer when/if I find the result.


The solution: The Node.js way works in strict mode and

in strict mode, if this was not defined by the execution context, it remains undefined.

(This is the case when I called hasOwnProperty directly.)

More information is here (in the section Simple Call).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexander Mihailov
  • 1,050
  • 1
  • 12
  • 19
1

The main point you need to understand here is that the value of this within a function execution changes depending on how the function is called. The two relevant ways here are:

  • When a function is called as a property of an object (e.g., foo.bar()) then this is set to the owning object

  • When a function is invoked as a "bare" function (e.g., bar()), then the this value is either

    • the global object, if the function has non-strict-mode code, or
    • undefined, if the function has strict-mode code

The purpose of the hasOwnProperty function is to test if some object (supplied as the this value) has a property with a particular name (supplied as a function argument). foo.hasOwnProperty("baz") uses a this value of foo and tests if the this value has a property named baz.

When you call hasOwnProperty("baz"), the standalone identifier hasOwnProperty refers to the globally-accessible value from window.hasOwnProperty, but the invocation is of the form bar(...), not of the form foo.bar(...). Therefore, the second rule, above, for supplying a this value applies.

It appears that Node.js' hasOwnProperty method is in strict-mode, so hasOwnProperty("baz") is supplied undefined as its this value. It is not sensible to ask undefined if it has any property, so this invocation produces an error.

By contrast, it appears that Firefox's hasOwnProperty method is non-strict, so it gets the global object as this. That makes the result of the calls window.hasOwnproperty(...) and hasOwnproperty(...) identical, because they both get a this equal to window.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
apsillers
  • 112,806
  • 17
  • 235
  • 239
  • The only thing I couldn't understand was why calling `hasOwnProperty` on its own does not default to the global object. The `strict` vs. `non-strict` answered my question. I understand the rest, but it will help someone else for sure. The discussion helped me to come the solution. Thank You! – Alexander Mihailov Jan 05 '17 at 22:50
1

When you use hasOwnProperty("x"),

  1. hasOwnProperty is an identifier. See runtime semantics

  2. The identifier is resolved using ResolveBinding, which calls GetIdentifierReference

  3. Possibly after some recursion, this produces the reference

    { base: globalEnvRec, referencedName: "hasOwnProperty", strict: strictFlag }
    
  4. Then you call it. See runtime semantics

  5. It gets the function using GetValue, like this:

    1. Calls the GetBindingValue for global environment records
    2. Assuming there is no declared binding, it will call GetBindingValue for the object record
    3. That will call Get with the binding object
  6. Since the base of the reference is an environment record, the thisValue is obtained from WithBaseObject for global environment records, which always returns undefined.

  7. Finally, the call is evaluated by EvaluateDirectCall, which uses that thisValue set to undefined.

When you use globalObj.hasOwnProperty("x"),

  1. Identifier resolution happens for globalObj. Let's say it gets the global object.

  2. The property accessor is evaluated. See runtime semantics

  3. It returns the reference

    { base: globalObj, referencedName: "hasOwnProperty", strict: strictFlag }
    
  4. Then you call it. See runtime semantics

  5. It gets the function using GetValue. Since it's a property reference and the base is an object, the [[Get]] internal method is used

  6. Since the reference is a property reference, the thisValue is obtained from GetThisValue, which returns the base (the global object).

  7. Finally, the call is evaluated by EvaluateDirectCall, which uses that thisValue set to the global object.

Now it's important how the function will treat the this value.

By default, [[Call]] uses OrdinaryCallBindThis which in sloppy mode transforms a null or undefined thisArgument to the global object. This does not happen if the function is defined in strict mode.

Finally, the definition of Object.prototype.hasOwnProperty uses ToObject on the this value. That will throw if it's null or undefined.

console.log(function(){ return this }() === window);
console.log(function(){ "use strict"; return this }() === undefined);

So, is hasOwnProperty defined in strict mode? Well, for built-in function objects,

For each built-in function, when invoked with [[Call]], the [[Call]] thisArgument provides the this value, the [[Call]] argumentsList provides the named parameters, and the NewTarget value is undefined

So the this value is passed as is, without converting null and undefined to the global object. Like in strict functions.

As a corollary, if you want to use hasOwnProperty directly without specifying the global object as the base, you could just redefine it with a sloppy-mode function. I don't recommend this; it's just for fun.

(function() {
  var has = Object.prototype.hasOwnProperty;
  Object.prototype.hasOwnProperty = function() {
    return has.apply(this, arguments);
  };
})();
console.log(hasOwnProperty('hello')); // false
console.log(hasOwnProperty('window')); // true

Or a getter approach:

Object.defineProperty(window, 'hasOwnProperty', {get: function() {
  return Object.prototype.hasOwnProperty.bind(this);
}});
console.log(hasOwnProperty('hello')); // false
console.log(hasOwnProperty('window')); // true

However, the ECMASCript standard does not ensure that the global object will inherit from Object.prototype.

From InitializeHostDefinedRealm, it's completely implementation-dependent.

If the host requires use of an exotic object to serve as realm's global object, let global be such an object created in an implementation defined manner.

So in general you should not use globalObj.hasOwnProperty nor hasOwnProperty. For some implementation it may be OK (e.g., for web browsers this is enforced by W3C and WHATWG standards), but for others it might completely fail.

Even if it's OK for your implementation, it's still bad. hasOwnProperty could be shadowed. For example, I just said on the web window inherits from Object.prototype, but the global polluter is closer in the prototypical chain, and there could be an element with id="hasOwnProperty"!!

Instead, I recommend one of these:

Object.prototype.hasOwnProperty.call(globalObj, prop)
Object.getOwnPropertyDescriptor(globalObj, prop) !== undefined
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Oriol
  • 274,082
  • 63
  • 437
  • 513