I'm creating javascript object by doing something like:
function field(name,label){
this.name = name
this.label= label;
}
var a = new field("market","Mkt").
Then I assign a to another object.
object.newField = a;
The second way of doing it is to create a new property directly
object.2ndNewField = {
name: "market2",
label:"Mkt2"
}
I try to read the objects in other functions. They behave differently, however, when i stringify the object, it looks ok. What's the difference between the two properties i created?
btw is there any difference of the following object?
object.2ndNewField = {
"name": "market2",
"label":"Mkt2
}
The difference is that in the first case, the created object inherits from field.prototype then Object.prototype (i.e. its internal [[Prototype]] is field.prototype, whose internal [[Prototype]] is Object.prototype), where as in the second case it inherits only from Object.prototype.
Another way to look at it is:
object.newField instanceof field; // true
object.newField instanceof Object; // true
object.newField2 instanceof field; // false
object.newField2 instanceof Object; // true
or the inheritance chains are:
object.newField -> field.prototype -> Object.prototype -> null
object.newField2 -> Object.prototype -> null
where '->' means "inherits from".
For the First option...Stay away from using "new". You can badly effect your global namespace if "new" is used wrong, or omitted when it should be used. Plus you have to be careful with the use of "this" in some places within your code, as it could be bound to something that you don't think it is, or even to your global data.
In your 2nd option you gave, you can safely use it for objects that are only used as a collection of data/methods (i.e. not "class-like" behavior) . If you want something that you can create multiple instances of with private and public variables/methods and can be inherited from, then you should use a function that returns an object.
I did a pretty big write up and example here of how to safely create base objects and use inheritance. If you follow the link, you will see why I didn't retype it all on this post ;).
Hope this helps...
Related
I try to understand the following sentence at github airnb/javascript
https://github.com/airbnb/javascript#objects--prototype-builtins
Why? These methods may be shadowed by properties on the object in
question
What is meant with "shadowed" in this case?
For easier reference here the full section:
3.7 Do not call Object.prototype methods directly, such as hasOwnProperty, propertyIsEnumerable, and isPrototypeOf.
Why? These methods may be shadowed by properties on the object in
question - consider { hasOwnProperty: false } - or, the object may be
a null object (Object.create(null)).
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object,key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from 'has';
// ...
console.log(has.call(object, key));
When you creating an object
const anObject = {};
it almost always has the Object in prototype chain. It allow the created object to have access to functions defined in Object like hasOwnProperty.
Shadowed means a method or a property that defined in the created object has the same name as those functions or properties that in prototype chain.
Example of shadowing:
const obj = {};
obj.hasOwnProperty // => ƒ hasOwnProperty() { [native code] }
obj.hasOwnProperty = 'don\'t do this!';
obj.hasOwnProperty // => "don't do this!"
Consider some example below:
const object = { hasOwnProperty: false }
console.log(object.hasOwnProperty(key)) // Error: hasOwnProperty is not a function
or
const object = null
console.log(object.hasOwnProperty(key)) // Error: Can not read property of null
So you can understand shallowed in this case is your object methods in prototype is shallowed by an object property (has the same name)
See an example. Here I have created an function with name hasOwnProperty directly on the my object. So it hides the parent version of the hasOwnProperty. In it I write a logic which will return everytime true. So anybody who will use my object and tries to detect if it has some property in it (he/she doesn't know I have shadowed the base on) he can have a logic errors in his/her code. Because JS will try to find the function first in the object and call that version which actually does another work.
But when you call this method from the Object.prototype, which is the correct version of the method, and pass the context to it, it will work correctly, because it will call the Object.prototypes method with name hasOwnProperty and just pass this object as the context of the method. So from here is the warning that you must use this methods from the prototype.
Actually you can also change the Object.prototype version of the method, but there is a rule, Not change the prototypes of the built in objects.
const object = {
hasOwnProperty: function() {
return true;
}
};
console.log(object.hasOwnProperty('name'));
console.log(Object.prototype.hasOwnProperty.call(object, 'name'));
The first log says that there is a property name in the object, but it isn't. This may cause a logic error. The second one uses the correct version and gives a correct result.
I'm trying my best to understand javascript. Here is a simple experiment in Chrome console which gets me very confused:
var foo=function(){this.p=1;}
foo.prototype.p=2;
var bar=new foo();
//foo{p:1,p:2} <- this is the output of Chrome console, from the last command above
The output of Chrome is what confuses me. It seems like bar is an object with 2 parameters, p:1 and p:2. Does this mean bar has 2 p??? What is the reasoning behind this?
Chrome DevTools console's inline (non-extended) object representation currently does not display any difference between own properties and inherited prototype properties.
Now let's break what's going on into smaller steps.
new foo() creates a new object whose internal proto property points to foo.prototype. This means this object can access all properties defined in foo.prototype. It's called prototype chain.
Now when you set a property of the same name in the object, it "shadows" the prototype's property by the same name, turning the latter inaccessible through regular property access (see #loxxy's answer using Object.getPrototypeOf(obj) to access the shadowed prototype property).
Once you add a function to the object or its prototype, the console allows you to display the extended object representation, which does differ own properties from prototype properties. In the next example I've added a q method to the prototype to allow this behavior. The properties inherited from the prototype are shown inside the object's proto internal property:
If you just want to have the number of instanced objects in the constructor's prototype, you can use:
var foo = function() {
Object.getPrototypeOf(this).p++;
}
foo.prototype.p = 0;
console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}
Or without the ES5 dependency:
var foo = function() {
foo.prototype.p++;
}
foo.prototype.p = 0;
console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}
Yes. Sort of.
bar has both:
A p property of its own.
bar.hasOwnProperty('p'); // true
bar.p; // 1
A p property still remaining on the prototype that it has through inheritance.
Object.getPrototypeOf(bar).p; // 2
Though, only 1 of them is accessible directly from bar at a time, with preference to the own property.
bar.p; // 1
delete bar.p;
bar.p; // 2
And, Chrome is showing both because it's traversing the prototype chain and looking for any enumerable properties.
The bar object has only one p with value 1
The earlier p with value 2 can be viewed in a readonly object which you can access with getPrototypeOf:
Object.getPrototypeOf(bar).p
You see both because the developer toolbar is designed to print an XML representation of the specified object which should intuitively show all the properties, whether directly accessible or not.
var foo=function(){this.p=1;} is constructor and executes after var bar=new foo();. So at the beginning p=2 and then p becomes 1. So:
var foo=function(){
// here this.p is equal to 2
this.p=1;
// here this.p is equal to 1
}
foo.prototype.p=2;
var bar=new foo();
EDIT:
JSON.stringify(bar);
When you acces a property, the javascript engine will seek it on the object instance, then on all its prototype chain.
So the meaning of p as a prototype property is to have a default value for p, wether you define it on any instance of the class or not. One example might be the number of wheel for a vehicle, that could default to 4, for instance.
If later you write to this property :
function Vehicle() {};
Vehicle.protoype.wheelCount = 4;
var myBike = new Vehicle();
myBike.wheelCount = 2 ; // this is a bike.
You won't change the value set on the prototype, but rather you'll create a new property on the instance, having the new value, so for instance :
var myCar = new Vehicle();
myCar.wheelCount // === 4
Now the very scenario you mention -setting a default value, and setting also an instance value in the constructor - doesn't make much sense, since you will have to use Object.getPrototypeOf to get to reach the default value. This is just a possibility that is of no use, just like there are many in all languages.
The question I have deals with an application of adding a new method to the existing String constructor. In Object Oriented Program for Javascript by Stoyan Stefanov, there is an example of using the Array constructor's .reverse() method to create one for the String constructor. Here is the example:
String.prototype.reverse = function() {
return Array.prototype.reverse.apply(this.split('')).join('');
}
I thought the .reverse() method of Array belonged directly to the object of Array. In fact, when I try to do the second bit of code with this statement:,
String.prototype.reverse = function() {
return Array.reverse.apply(this.split('')).join(''); //WITHOUT the .prototype
}
var rev = "karunesh".reverse(); //applying the code here
I get an error in the Firebug Console stating: "TypeError: missing argument 0 when calling function Array.reverse". That does not make any sense to me.
And of course, if I add back in the .prototype, it works perfectly fine.
Also, if is the case that I have to call upon prototype to access the .reverse() method from the Array object, then is it the case that I have to do that for any built-in object in Javascript?
Thanks for the help in advance!
Is it the case that I have to call upon prototype to access the .reverse() method from the Array object
No. To access a method on an object, just access it with dot notation. What you want to do is simply
return this.split('').reverse().join('');
That is just what apply (or call) does:
var arr = this.split('');
return arr.reverse.apply(arr).join('');
and finally arr.reverse === Array.prototype.reverse since that's where Array objects do inherit from. You are not accessing the reverse method on the Array constructor function object itself, you are to access the property that all Array instances share - via their prototype. Yet you hardly will ever need to use the prototype object explicitly, that's only when you're dealing with objects that are not Array instances (do not share the prototype) like arguments objects or NodeLists.
TypeError: missing argument 0 when calling function Array.reverse. That does not make any sense to me.
Array.reverse is a non-standard Array generic method which is only available in Firefox. It's purpose is to simplify the construct of applying Array prototype methods on other objects, and it does take the array-like object as it's first parameter. An example:
Array.reverse([0, 1]) // [1, 0]
which is equivalent to
Array.prototype.reverse.apply([0, 1]);
However, you were doing
Array.reverse.apply([…]/*, undefined*/)
which is calling the Array.reverse function with the array for the (irrelevant) this value and no actual argument, equivalent to
Array.prototype.reverse.apply(undefined)
and that throws the rightful exception.
Array.reverse is undefined (at least in Chrome 29) - Array.prototype.reverse is a function that will reverse the order of the "iterable" it is called on.
The key thing to note here is that Array is not a class like you would have in Java - rather it is a constructor:
[].constructor === Array;
// true
The prototype property of Array is actually what is providing the behavior to any particular instance of Array:
Object.getPrototypeOf([]) === Array.prototype;
// true
// Bad idea, just for an example
var guys = ['Tom', 'Harry', 'Richard'];
Array.prototype.exclaim = function() {
return this.join(", ") + "?!?!?!";
};
guys.exclaim();
// Tom, Harry, Richard?!?!?!
The key here is that JavaScript uses a prototype-based object-oriented pattern, rather than the classical pattern you are more likely familiar with. Instead of having "classes" which contain all the behaviors, but which are distinct from instances, JavaScript has objects, which can be the "prototypes" of other objects, providing data and behavior to the child objects.
// Totally licit OO pattern in JavaScript
var prototypeClass = {
method1: function() { console.log("Hello from method 1!"); },
method2: function() { console.log("Hello from method 2!"); },
classData: 42
};
var prototypeInstance = Object.create(prototypeClass);
prototypeInstance.method1() // Hello from method 1!
prototypeInstance.classData // 42
// And you can modify the class after
// instantiating instances and the changes
// will be picked up by the instances
prototypeClass.happyPrimes = "Don't they teach recreational mathematics anymore?";
prototypeInstance.happyPrimes // The quote from 42
This is a purely trivial question for academic value:
If I create a new object, either by doing:
var o = { x:5, y:6 };
or
var o = Object.create({ x:5, y:6 });
when I query the o.prototype property, I get undefined. I thought that any newly created object automatically inherits the Object.prototype prototype.
Furthermore, invoking toString(), (a method of Object.prototype) on this object works just fine, implying that o does inherit from Object.prototype. So why do I get undefined?
There is a difference between instances and their constructors.
When creating an object like {a: 1}, you're creating an instance of the Object constructor. Object.prototype is indeed available, and all functions inside that prototype are available:
var o = {a: 1};
o.hasOwnProperty === Object.prototype.hasOwnProperty; // true
But Object.create does something different. It creates an instance (an object), but inserts an additional prototype chain:
var o = {a: 1};
var p = Object.create(o);
The chain will be:
Object.prototype - o - p
This means that:
p.hasOwnProperty === Object.prototype.hasOwnProperty; // true
p.a === o.a; // true
To get the prototype "under" an instance, you can use Object.getPrototypeOf:
var o = {a: 1};
var p = Object.create(o);
Object.getPrototypeOf(p) === o; // true
Object.getPrototypeOf(o) === Object.prototype; // true
(Previously, you could access an instance's prototype with o.__proto__, but this has been deprecated.)
Note that you could also access the prototype as follows:
o.constructor === Object; // true
So:
o.constructor.prototype === Object.prototype // true
o.constructor.prototype === Object.getPrototypeOf(o); // true
This fails for Object.create-created objects because they do not have a constructor (or rather, their constructor is Object and not what you passed to Object.create because the constructor function is absent).
Not a direct answer, but knowledge that everybody, who deal with inheritance in Javascript, should have.
Prototype inheritance in Javascript is a tricky concept. Up until now, it has been impossible to create an empty object (by empty I mean lacking even properties form Object via prototype). So this means that creating a new object always had a link to the original Object prototype. However, according to the specification, the prototype chain of an object instance isn't visible, but some vendors have decided to implement their own proprietary object properties so that you could follow it, but it's highly recommended not to use it in production code.
The following sample code demonstrates just two ways of creating an object instance.
var someObject = {};
var otherObject = new Object();
var thirdObject = Object.create({});
Even though you don't manually add object properties to empty curly braces, you still get automatically added prototype chain. The same goes for the second example. To visualize it better, you can type those lines into Chrome console and then enter either someObject, otherObject or thirdObject to see details. Chrome shows the prototype chain by adding a proprietary property __proto__ which you can expand to see what is inherited and where it's from. If you executed something like
Object.prototype.sayHello = function() {
alert('hello');
};
you would be able to call it on all instances, by executing otherObject.sayHello().
However, using something that was implemented quite recently (therefore not supported by all browsers), you can actually create a truly empty object instance (doesn't inherit even from Object itself).
var emptyObject = Object.create(null);
When you enter it into Chrome console and then expand the emptyObject to see it's prototype chain, you can see that it doesn't exist. So even if you implemented the sayHello function to Object prototype, it would be impossible to call emptyObject.sayHello() since emptyObject does not inherit from Object prototype.
Hope it helps a bit with the general idea.
JavaScript has two types of objects: function object and non-function object. Conceptually, all objects have a prototype (NOT A PROTOTYPE PROPERTY). Internally, JavaScript names an object's prototype as [[Prototype]].
There are two approaches to get any object (including non-function object)'s [[prototype]]: the Object.getPrototypeOf() method and the __proto__ property. The __proto__ property is supported by many browsers and Node.js. It is to be standardized in ECMAScript 6.
Only a function (a callable) object has the prototype property. This prototype property is a regular property that has no direct relationship with the function's own [[prototype]]. When used as a constructor ( after the new operator), the function's prototype property will be assigned to the [[Prototype]] of a newly created object. In a non-function object, the prototype property is undefined . For example,
var objectOne = {x: 5}, objectTwo = Object.create({y: 6});
Both objectOne and objectTwo are non-function objects therefore they don't have a prototype property.
this page states:
Note: isPrototypeOf differs from
instanceof operator. In the expression
object instanceof AFunction, the
object prototype chain is checked
against AFunction.prototype, not
against AFunction itself
Ok I don't really get what they are trying to tell us. Isn't object instanceof AFunction exactly the same as `AFunction.prototype.isPrototypeOf(object)? or am I wrong?
Why do we need the isPrototypeOf at all?
If i ever need to do p.isPrototypeOf(o) couldn't I just do o instanceof p.constructor ?
Addtionally, is p.isPrototypeOf(o) functionally equivalent to p===Object.getPrototypeOf(o)?
Object constructors are funky things. From this answer:
As Pointy has pointed out, in his
answer
The "constructor" property is a
reference to the function that created
the object's prototype, not the object
itself.
The usual way to deal with this is to
augment the object's prototype
constructor property after assigning
to the prototype.
An object's constructor is not read-only, which is why this is possible to do at all. I could assign any value to p.constructor after p is created, and this would completely break using
o instanceof p.constructor
instead of
p.isPrototypeOf(o)
Further reading
constructor # MDC
What it the significance of the Javascript constructor property?
OO Programming in JS
Constructors considered mildly confusing
Edit re: OP edit
Addtionally, is p.isPrototypeOf(o) functionally equivalent to p===Object.getPrototypeOf(o)?
Those are more similar than your original question, aside from the fact that Object.getPrototypeOf wasn't introduced until JavaScript 1.8.1? See John Resig - Object.getPrototypeOf. Perhaps more relevant, the two functions are different in the spec! (warning, PDF link)
I think the most important distinction here is that the isPrototypeOf method allows you to check if an object inherits directly from another object. Consider the following:
var t = new Object();
var f = new Object();
var c = Object.create(t);
c instanceof f.constructor; // true
c instanceof t.constructor; // true
f.isPrototypeOf(c); // false
t.isPrototypeOf(c); // true
As you can see the constructor is only the function that instantiated the object. Not the implementation specifier. So if t.y = function(){ return true; } and f.y = function(){ return false; } and I needed to check that c would return the appropriate implementation through it's prototype chain, instanceof wouldn't help very much.
instanceOf --> This object (or the objects it was derived from ) used the named object as a prototype
isPrototypeOf --> This object was used by the named Object (or the Objects it was derived from) as a prototype.
ie.
instanceOf is querying the objects ancestors.
IsPrototypeOf is querying the objects descendants.