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.
Related
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
What is the difference between this constructor-based syntax for creating an object:
person = new Object()
...and this literal syntax:
person = {
property1 : "Hello"
};
It appears that both do the same thing, although JSLint prefers you use object literal notation.
Which one is better and why?
There is no difference for a simple object without methods as in your example.
However, there is a big difference when you start adding methods to your object.
Literal way:
function Obj( prop ) {
return {
p : prop,
sayHello : function(){ alert(this.p); },
};
}
Prototype way:
function Obj( prop ) {
this.p = prop;
}
Obj.prototype.sayHello = function(){alert(this.p);};
Both ways allow creation of instances of Obj like this:
var foo = new Obj( "hello" );
However, with the literal way, you carry a copy of the sayHello method within each instance of your objects. Whereas, with the prototype way, the method is defined in the object prototype and shared between all object instances.
If you have a lot of objects or a lot of methods, the literal way can lead to quite big memory waste.
They both do the same thing (unless someone's done something unusual), other than that your second one creates an object and adds a property to it. But literal notation takes less space in the source code. It's clearly recognizable as to what is happening, so using new Object(), you are really just typing more and (in theory, if not optimized out by the JavaScript engine) doing an unnecessary function call.
These
person = new Object() /*You should put a semicolon here too.
It's not required, but it is good practice.*/
-or-
person = {
property1 : "Hello"
};
technically do not do the same thing. The first just creates an object. The second creates one and assigns a property. For the first one to be the same you then need a second step to create and assign the property.
The "something unusual" that someone could do would be to shadow or assign to the default Object global:
// Don't do this
Object = 23;
In that highly-unusual case, new Object will fail but {} will work.
In practice, there's never a reason to use new Object rather than {} (unless you've done that very unusual thing).
In JavaScript, we can declare a new empty object in two ways:
var obj1 = new Object();
var obj2 = {};
I have found nothing to suggest that there is any significant difference these two with regard to how they operate behind the scenes (please correct me if i am wrong – I would love to know). However, the second method (using the object literal notation) offers a few advantages.
It is shorter (10 characters to be precise)
It is easier, and more structured to create objects on the fly
It doesn’t matter if some buffoon has inadvertently overridden Object
Consider a new object that contains the members Name and TelNo. Using the new Object() convention, we can create it like this:
var obj1 = new Object();
obj1.Name = "A Person";
obj1.TelNo = "12345";
The Expando Properties feature of JavaScript allows us to create new members this way on the fly, and we achieve what were intending. However, this way isn’t very structured or encapsulated. What if we wanted to specify the members upon creation, without having to rely on expando properties and assignment post-creation?
This is where the object literal notation can help:
var obj1 = {Name:"A Person",TelNo="12345"};
Here we have achieved the same effect in one line of code and significantly fewer characters.
A further discussion the object construction methods above can be found at: JavaScript and Object Oriented Programming (OOP).
And finally, what of the idiot who overrode Object? Did you think it wasn’t possible? Well, this JSFiddle proves otherwise. Using the object literal notation prevents us from falling foul of this buffoonery.
(From http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/)
On my machine using Node.js, I ran the following:
console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');
console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');
console.log('Testing Object:');
console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');
console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');
Note, this is an extension of what is found here: Why is arr = [] faster than arr = new Array?
my output was the following:
Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms
so clearly {} and [] are faster than using new for creating empty objects/arrays.
Everyone here is talking about the similarities of the two. I am gonna point out the differences.
Using new Object() allows you to pass another object. The obvious outcome is that the newly created object will be set to the same reference. Here is a sample code:
var obj1 = new Object();
obj1.a = 1;
var obj2 = new Object(obj1);
obj2.a // 1
The usage is not limited to objects as in OOP objects. Other types could be passed to it too. The function will set the type accordingly. For example if we pass integer 1 to it, an object of type number will be created for us.
var obj = new Object(1);
typeof obj // "number"
The object created using the above method (new Object(1)) would be converted to object type if a property is added to it.
var obj = new Object(1);
typeof obj // "number"
obj.a = 2;
typeof obj // "object"
If the object is a copy of a child class of object, we could add the property without the type conversion.
var obj = new Object("foo");
typeof obj // "object"
obj === "foo" // true
obj.a = 1;
obj === "foo" // true
obj.a // 1
var str = "foo";
str.a = 1;
str.a // undefined
Actually, there are several ways to create objects in JavaScript. When you just want to create an object there's no benefit of creating "constructor-based" objects using "new" operator. It's same as creating an object using "object literal" syntax. But "constructor-based" objects created with "new" operator comes to incredible use when you are thinking about "prototypal inheritance". You cannot maintain inheritance chain with objects created with literal syntax. But you can create a constructor function, attach properties and methods to its prototype. Then if you assign this constructor function to any variable using "new" operator, it will return an object which will have access to all of the methods and properties attached with the prototype of that constructor function.
Here is an example of creating an object using constructor function (see code explanation at the bottom):
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
Person.prototype.fullname = function() {
console.log(this.firstname + ' ' + this.lastname);
}
var zubaer = new Person('Zubaer', 'Ahammed');
var john = new Person('John', 'Doe');
zubaer.fullname();
john.fullname();
Now, you can create as many objects as you want by instantiating Person construction function and all of them will inherit fullname() from it.
Note:
"this" keyword will refer to an empty object within a constructor function and whenever you create a new object from Person using "new" operator it will automatically return an object containing all of the properties and methods attached with the "this" keyword. And these object will for sure inherit the methods and properties attached with the prototype of the Person constructor function (which is the main advantage of this approach).
By the way, if you wanted to obtain the same functionality with "object literal" syntax, you would have to create fullname() on all of the objects like below:
var zubaer = {
firstname: 'Zubaer',
lastname: 'Ahammed',
fullname: function() {
console.log(this.firstname + ' ' + this.lastname);
}
};
var john= {
firstname: 'John',
lastname: 'Doe',
fullname: function() {
console.log(this.firstname + ' ' + this.lastname);
}
};
zubaer.fullname();
john.fullname();
At last, if you now ask why should I use constructor function approach instead of object literal approach:
*** Prototypal inheritance allows a simple chain of inheritance which can be immensely useful and powerful.
*** It saves memory by inheriting common methods and properties defined in constructor functions prototype. Otherwise, you would have to copy them over and over again in all of the objects.
I hope this makes sense.
Also, according to some of the O'Really javascript books....(quoted)
Another reason for using literals as opposed to the Object constructor is that there is no scope resolution. Because it’s possible that you have created a local constructor with the same name, the interpreter needs to look up the scope chain from the place you are calling Object() all the way up until it finds the global Object constructor.
2019 Update
I ran the same code as #rjloura on my OSX High Sierra 10.13.6 node version 10.13.0 and these are the results
console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');
console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');
console.log('Testing Object:');
console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');
console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');
Testing Array:
using[]: 117.613ms
using new: 117.168ms
Testing Object:
using{}: 117.205ms
using new: 118.644ms
I have found one difference, for ES6/ES2015. You cannot return an object using the shorthand arrow function syntax, unless you surround the object with new Object().
> [1, 2, 3].map(v => {n: v});
[ undefined, undefined, undefined ]
> [1, 2, 3].map(v => new Object({n: v}));
[ { n: 1 }, { n: 2 }, { n: 3 } ]
This is because the compiler is confused by the {} brackets and thinks n: i is a label: statement construct; the semicolon is optional so it doesn't complain about it.
If you add another property to the object it will finally throw an error.
$ node -e "[1, 2, 3].map(v => {n: v, m: v+1});"
[1, 2, 3].map(v => {n: v, m: v+1});
^
SyntaxError: Unexpected token :
The only time i will use the 'new' keyowrd for object initialization is in inline arrow function:
() => new Object({ key: value})
since the below code is not valid:
() => { key: value} // instead of () => { return { key: value};}
There are a lot of great answers here, but I want to come with my 50 cents.
What all of these answers are missing is a simple analogy which would work for a person who just starts his journey in the programming languages.
Hopefully, I will fill this gap with this analogy:
Object Literal Creation vs Constructor-based Syntax
Feel the difference with a sentence creation.
If I have a sentence "I like cheese", I can tell you clearly and loudly (literally, or verbatim): I like cheese.
This is my literal (word by word) creation of the sentence.
All other ways are some tricky ways of making you to understand of what sentence I created exactly. For example, I tell you:
In my sentence, the subject is "I", the object is "cheese", and the predicate is "to like".
This is another way of YOU to learn without any ambiguities the very same sentence: "I like cheese".
Or,
My sentence has 3 words: the first one is the n-th word in the English dictionary, the the second one is the m-th word in the English dictionary and the last one is the l-th word in the English dictionary.
In this case, you also come to the same result: you know exactly what the sentence is.
You can devise any other methods which would differ from "word-by-word" sentence creation (LITERAL), and which would be INDIRECT (non literal, non verbatim) method of sentence creation.
I think this is the core concept which lays here.
Memory usage is different if you create 10 thousand instances.
new Object() will only keep only one copy while {} will keep 10 thousand copies.
This question already has answers here:
Use cases for Object.create(null)
(2 answers)
Closed 8 years ago.
If this question is too vague, lemme know and I'll take it down or try to add more code examples, thanks!
This post is inspired by Yehuta Katz' article on "Understanding Prototypes"
In Javascript you can utilize prototypes by using Object.create() and this will produce a dependency/inheritance much like seen in many OOP languages. If a parameter of null is passed to the create() method, then this new object will be a top-level object, the same level as Object.prototype.
Now, maybe this is just my years of Java and C#, but when would one ever create a top-level object? If you aren't satisfied with the fields/methods in Object.prototype, why not just extend it and make your own pseudo-top-level object?
Example:
In this example, person is a top-level object. Thus, it did not inherit the standard methods contained in Object.prototype such as toString(), hasOwnProperty(), valueOf(), etc.
var person = Object.create(null);
// instead of using defineProperty and specifying writable,
// configurable, and enumerable, we can just assign the
// value directly and JavaScript will take care of the rest
person['fullName'] = function() {
return this.firstName + ' ' + this.lastName;
};
// this time, let's make man's prototype person, so all
// men share the fullName function
var man = Object.create(person);
man['sex'] = "male";
var yehuda = Object.create(man);
yehuda['firstName'] = "Yehuda";
yehuda['lastName'] = "Katz";
yehuda.sex // "male"
yehuda.fullName() // "Yehuda Katz"
Constructing {} or new Object yields an object which has a prototype, as you said. Constructing with Object.create(null) builds an object with empty prototype and thus no inherited members.
A good use case I can think about is when you actually need an absolutely memberless object, e.g., to perform a safe iteration:
for(var key in obj) {
/*
in normal conditions, you must ensure that object hasOwnProperty(key)
so you know you're iterating on actual members.
*/
if (obj.hasOwnProperty(key)) {
console.log("key: " + key + "; value: " + obj[key]);
}
}
but with this approach you ensure you don't have ANY prototype and thus every property will be own by default.
obj = Object.create(null);
//to-do populate your object keys here, treating it like a hash instead of an object.
for(var key in obj) {
/*
this operation is safe and also this object is safe to be populated
in server-side javascript (e.g. nodejs) via a POST request.
a common use case is to SERIALIZE this object quickly, while the
previous IF could provide some overhead.
*/
console.log("key: " + key + "; value: " + obj[key]);
}
So you can safely treat the object as a hash and iterate it as I told, holding only true data.
Another possible use case is when you want to build your own prototype from scratch (even a toString function OR NOT DEFINING CERTAIN FUNCTIONS in the Object prototype) and create a brand-new hierarchy. This could be useful only for frameworks, perhaps. It's a bit cumbersome but could be useful in the OOP approach.
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.