Here is an example:
var cat1 = Object.create({
name: "mia"
});
cat1.hasOwnProperty('name') // false
cat1.name = "haha";
cat1.hasOwnProperty('name') // true
This is rather surprising to me.
1) What is the design intention here?
2) How can I use = without create new properties?
What is the design intention here?
I didn't design JavaScript, but my guess would be to restrict the "scope" of mutations. Imagine you had two objects:
var proto = {name: "mia"};
var cat1 = Object.create(proto);
var cat2 = Object.create(proto);
If assignment to cat1.name would not create a new property, but update the prototype property instead, then cat2.name would suddenly be updated as well.
In other words, if assignment was updating prototype properties instead of the object's own properties, other objects could be affected by the change, without you even knowing it.
How can I use = without create new properties?
You cannot. You could assign to the prototype explicitly, but that requires you to know that the property is defined on the prototype:
Object.getPrototypeOf(cat1).name = 'haha';
hasOwnProperty shows properties defined on the object. At the same time:
Object.create({
name: "mia"
});
Creates new object with prototype {name: "mia"}. This means that property name will be defined for prototype not for object. Using prototypes makes some sort of optimization. Different object share the same logic from the prototype. Also the methods are not duplicated, so less memory is used.
When you defines own property by = you are showdowing the property with the same name from the prototype, so as #Felix Kling indicated you are not changing property in the prototype and other objects that use the same prototype will not be affected. You also can use Object.defineProperty(obj, prop, descriptor) instead of = in order to define own property of the object, but you can not use = on object without defining new properties you can do that on the prototype directly like this:
cat1.__proto__.name="other name" //avoid, this is not the best practive at all
By design, When you create object from a prototype, the new objects will share the properties with prototype object until you assign value explicitly to that property on that object, once its assigned since then the object will maintain its own state. below is sample code for the same.
var x = {"name":"mia"};
var o1= Object.create(x);
var o2= Object.create(x);
console.log(x.name,o1.name,o2.name); //output: mia,mia,mia
x.name="xxx";
console.log(x.name,o1.name,o2.name); //output: xxx,xxx,xxx
o1.name="yyy";
console.log(x.name,o1.name,o2.name); //output: xxx,yyy,xxx
Related
My understanding of prototypes is as follows:
let Animal = function() {
this.bark = "woof";
}
Animal.prototype.barkLoud = function() {
return this.bark.toUpperCase();
}
let x = new Animal();
x.barkLoud() = "WOOF";
Everything above makes sense to me but then I saw a tutorial what seemingly appears to be 2 different ways to pass prototypes to an object. Are these the same thing? If so, which approach is better:
let obj = {
age: 45;
__proto__: Animal
}
vs
let obj = {
age: 45;
}
obj.prototype = Object.create(Animal.protoype);
As a rule of thumb, the more underscore (_) characters you see around a property name in JS, the more of implementation details it is - and the more discouraged you are from even querying it, let alone attempting to modify.
While __proto__ is indeed supported by all the existing browsers, its usage to set up a prototype is not recommended. Use Object.create() instead.
BTW, two ways you've showed are not even equivalent. See, __proto__ refers to the prototype object, but Animal is not the one - it's a function. Animal.prototype is an object that will be used as a prototype (__proto__ value) for all the objects created by this function with new` operator.
So the first object won't be able to resolve barkLoud name from the prototype chain:
> obj.barkLoud // undefined
__proto__ way is deprecated by the way and I've never seen it implemented anywhere.
Go with Object.create as the official and recommended way to create/assign prototype of existing object to the newly created object.
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.
Ok am just going through basics of JavaScript and I was learning objects where I came across this example...
JavaScript
var person = {
firstname : "Smith",
lastname : "Bach"
};
And what we write in PHP is
$person = array(
"firstname"=>"Smith",
"lastname"=>"Bach"
);
So is this the same thing or am making a mistake in understanding the concept?
No, objects are more than that.
Object is indeed a map/dictionary, but additionally every object inherits some of the properties (key-value pairs) from another object. That other object is called prototype.
For example:
var o = {
x: 1
};
console.log(o.x === undefined); // false, obviously
console.log(o.toString === undefined); // false, inherited from prototype
Most commonly a prototype is set by creating an object with a constructor function:
var d = new Date();
console.log(d.hasOwnProperty('getYear')); // false, it's inherited
EDIT:
Here's how the prototype works using constructor functions (it's one of the ways to do OOP in JS):
// constructor function
// starts with capital letter, should be called with new
var Person = function (name, age) {
// set properties of an instance
this.name = name;
this.age = age;
};
// functions to be inherited are in the prototype
Person.prototype.sayHello = function () {
return this.name + ' is ' + this.age + ' old';
};
// new:
// - creates the object
// - sets up inheritance from prototype
// - sets the object as the context of the constructor function call (this)
var p = new Person('Jason', 27);
console.log(p.sayHello());
They are associative arrays, but not just associative arrays. There are functions available from the Object prototype (like .toString()) whose names can collide with property names. Objects can be constructed via other functions and given more inherited properties too. (Note that one thing that plain objects don't have is a .length property to count entries, like array objects have. The term "associative array" is probably not the best one to use for JavaScript objects; they're objects and that should be enough once you're familiar with JavaScript.)
edit — what I mean is this:
var o = {};
alert("toString" in o); // alerts "true"
Thus a newly-created empty object appears to have a property called "toString". The issue with JavaScript is that there's only one property accessor operator (well two, but they're two flavors of the same thing), so there's no way to distinguish between accesses to the array's contents and access to the array's API. (Also, in JavaScript it's really not a good idea to think of them using the word "array", as that means something different in JavaScript — arrays are a type of Object with special properties.)
EcmaScript 5 has mechanisms for defining object properties in such a way as to make them immutable and non-iterable, which helps some. It's still problematic if you want to store a property called "toString" in an object.
Some projects use Object.create() or Object.defineProperties() function. I wonder is is recommended? Whats the difference between
x = Object.create(null);
vs
x = {}
And
x = {}
x.__proto__.hello = function() {
console.log("hello");
}
vs
x = Object.create(null);
Object.defineProperty(x, "hello", {
value: function() {
console.log("hello");
}
});
defineProperty/create seems very verbose and long to me. When/Why do I use them? Perhaps the good might be to enforce getters/setters/overriding properties?
There is a huge difference. Have a look at the docs!
Object.create does create an Object that inherits from the first argument, null in your case. In contrast, {} - or new Object() - creates a new object that inherits from Object.prototype.
__proto__ is non-standard and should not be used. However, in your case you just do Object.prototype.hello = function() {…};. Never extend that object with enumerable properties, never ever!
Object.defineProperty does define a property on an object with a special descriptor object. The enumerable, configurable and writable attributes default to false, which means that you wont be able to delete x.hello for example, or assign any other value.
Your first snippet creates a plain object, which inherits a hello method from Object.prototype, while your second snippet creates an object inheriting from nothing and having a non-editable hello property. I don't see much relatedness.
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.