1

My understanding is that the Object.hasOwnProperty method checks if the object has a property name of it's own, meaning a non-inherited property. That would mean that the function should return false whenever the property a. doesn't exist, or b. if it's inherited.

Correct me if I'm wrong, but unless this doesn't use classical inheritance, doesn't bar inherit from Foo in the code below? Why is the hasOwnProperty method returning true when the propname property is an inherited property? What did I get wrong here?

Also, how would I use the hasOwnProperty on the Foo object? The code here returns false when checking the the Foo object.

function Foo() {
    this.propname = 'test';
}

var bar = new Foo();

console.log(bar.hasOwnProperty('propname')); // returns true
console.log(Foo.hasOwnProperty('propname')); // returns false
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
shmuli
  • 5,086
  • 4
  • 32
  • 64
  • The this on line 2 === bar, no prototype properties are set here. Add prototype ones by setting Foo.prototype.propname = ... – Douglas Apr 12 '15 at 09:07
  • 1
    Bar is an instance of Foo, rather than a descendant. – joews Apr 12 '15 at 09:07
  • @Douglas can you please elaborate? Why does this require a prototype at all? The method is checking up the property... – shmuli Apr 12 '15 at 09:13
  • 1
    I've elaborated a bit in an answer below, but the point is that 'propname' is not an inherited property, the prototype needs to get involved somewhere for there to be inherited properties. – Douglas Apr 12 '15 at 09:20

5 Answers5

5

The stumbling point here is that Javascript uses prototypal inheritance. What you're seeing there isn't actually inheritance at all.

hasOwnProperty will return false if the property:

  1. Does not exist.
  2. Exists but only on the prototype chain.

The 'class' in your code is nothing to do with inheritance at all, it's just a function which sets some properties on an object.

That object happens to be an instance of a new empty object, because you called the function with the new keyword, which is probably where the confusion is coming from.

Imagine rewriting the function as this:

function foo() {
  var bar = {};
  bar.propname = 'test';
  return bar;
}

var baz = foo();

Would you expect baz.hasOwnProperty('propname') to return true? Absolutely, because we explicitly defined the property on the object.

The alternative way to declare the property would have been to declare it on Foo's prototype.

function Foo() {
  this.bar = 'baz';
}

Foo.prototype.propname = 'test';

var baz = new Foo();

baz.propname; // 'test'
baz.hasOwnProperty('propname'); // false

Again, the magical stuff happening here is all down to the new keyword. When you call a function with new the function assigns the value of this to be a new object and sets the prototype of that object to be the same as the prototype of the function you are calling.

Maybe the easiest way of explaining this is that there is a hasOwnProperty method on bar, but if you call bar.hasOwnProperty('hasOwnProperty') it will return false.

This is because the hasOwnProperty method lives at the very top of the prototype chain, on Object.prototype. Every object in Javascript inherits from here, which is why every object will have a hasOwnProperty method.

There's a good article on why new makes object oriented programming difficult in Javascript.

Dan Prince
  • 29,491
  • 13
  • 89
  • 120
  • Is that perhaps why Addy Osmani suggests in "Learning JavaScript Design Patterns" (http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript) not to use the basic constructor pattern, but rather to use the prototype pattern? He says that the constructor pattern "makes inheritance difficult", but doesn't elaborate further. – shmuli Apr 12 '15 at 09:59
  • Exactly. Same reason as Doug Crock doesn't use new (although he no longer uses `Object.create` either. Spending some time working in another language with prototypal inheritance (I can recommend Lua and Io) is __really helpful__ for understanding prototypes. In Javascript they are slightly lost under syntax that feels classical. – Dan Prince Apr 12 '15 at 10:36
3

The initial code sample is equivalent to:

function Foo() {
}

var bar = new Foo();
bar.propname = 'test';

console.log(bar.hasOwnProperty('propname')); // returns true
console.log(Foo.hasOwnProperty('propname')); // returns false

This is why bar.hasOwnProperty('propname') returns true (the property has been explicitly set on the bar object), and Foo.hasOwnProperty('propname') returns false (the property has not been set on Foo at all, neither on the Foo object itself nor the prototype).

The hasOwnProperty check is normally used like this:

function Foo() {
    this.propname = 'test';
}
Foo.prototype.inheritedprop = 'test';

var bar = new Foo();

console.log(bar.hasOwnProperty('propname')); // returns true
console.log(bar.hasOwnProperty('inheritedprop')); // returns false
Douglas
  • 36,802
  • 9
  • 76
  • 89
  • Why hasn't the property actually been set on `Foo`? – shmuli Apr 12 '15 at 11:50
  • Let me reword that: Why isn't the property actually set on `Foo` when the `this` keyword or the `prototype` is used? Within the `Foo` context, shouldn't the `this` keyword set the property? Why doesn't this work either: `function Foo(){Foo.propname = 'test';}`. I guess that's all the same question. Why does it only work when I write `Foo.propname = 'test';` outside of the function? – shmuli Apr 12 '15 at 11:57
  • There are three distinct objects in the example: bar, Foo, and Foo.prototype. The hasOwnProperty method checks a particular object for the property, so if propname only gets set on one of the three objects, only that object will return true for `obj.hasOwnProperty("propname")`. `function Foo(){Foo.propname = 'test';}` will set propname on Foo, but it will only get set when Foo gets called. – Douglas Apr 12 '15 at 19:40
2

No, propname is actually set on the instance of Foo that is created by new, based on Foo.prototype (that is this). Another approximation of the constructor pattern makes it clear(er) what is going on:

var FooPrototype = {};
var bar = Object.create(FooPrototype);
bar.propname = "test";
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
1

When you first wrote Foo, you simply defined a function to be used later.

The "bar" instantiates that function and essentially activates everything inside of it.

Check out this fiddle with these console.logs

console.log(Foo)
console.log(bar)

https://jsfiddle.net/7pzwcrjo/

Neil
  • 81
  • 1
  • 6
1

You first have to instantiate a new object of the Foo class.

This JS bin further illustrates that point: http://jsbin.com/zaredowive/2/edit?js,console,output

As you can see the constructor is only called when you instantiate a new object of class Foo which in this case is a variable called bar. You are calling the hasOwnProperty on the function Foo. This function holds no properties.

JKaan
  • 359
  • 2
  • 14