I understand that there are multiple ways to create an object in javascript and I have been reading that object literal syntax is generally preferred. (Correct?)
What I haven't been able to figure out is if there is ever a reason to use any of the other ways to create objects, such as a custom constructor function (var p = new Person("Adam"))? Is it true to use a custom constructor function only if I want private variables or to add methods or properties to its prototype? Is there no way to do these in a literal?
You can use the custom constructor function when you want to create instances of objects, similar to Java.
For example:
function MyObj(x){
this.x = x;
}
MyObj.prototype.printX = function(){
alert(this.x);
}
var obj1 = new MyObj("hello");
var obj2 = new MyObj("hello2");
obj1.printX();//prints hello
obj2.printX();//prints hello2
Now I have two instances of this object. If I used String literals I would need to clone the object into a new var in order to get another instance.
The discussion usually is about to prefer
var myObject = {};
over
var myObject = new Object();
If you however create your own constructor functions you are perfectly allowed to instantiate them with the new keyword, nothing controversial there.
The preferred method would be to use JSON: var p = { "name":"Adam" };
If you have a lot of member variables you need to initialize, or will be using a lot of objects (such as an array of them), etc. then it only makes sense to go ahead and create a function (constructor) which will do all of this for you. Unless you want your code to look like this:
var a = { "name":"Adam", "age":23, "city":"Boston" };
var b = { "name":"Jeff", "age":24, "city":"San mateo" };
var c = { "name":"Aaliyah", "age":25, "city":"New York" };
var d = { "name":"Mary", "age":26, "city":"Dallas" };
Related
When I run the following code
var ExtendedObject = function() {
this.standard = 5;
};
Object = ExtendedObject.bind(Object);
var p = new Object();
console.dir(p.standard);
, the output is
5
as expected.
If I instead instantiate the variable p as an object literal like this:
var ExtendedObject = function() {
this.standard = 5;
};
Object = ExtendedObject.bind(Object);
var p = {};
console.dir(p.standard);
The result is
undefined
I am trying to find a way to modify the constructor of Object such that I can add some standard content to all new objects being created.
No, it is absolutely impossible to redefine how an object literal evaluates; it will always become a native object with the builtin Object.prototype, not a subclass or anything and it will also not invoke a custom constructor.
This is in fact a security feature, as it prevents JSON hijacking.
… such that I can add some standard content to all new objects being created
That's a horrible idea and will break every library you'd ever use in this environment (including all functions you'd write yourself). However, if you insist on having a common (not individual!) property on all objects, you might consider defining it on Object.prototype. Not that I would recommend it, but at least do it correctly.
You can create a class and extend it from Object.
class MyObject extends Object {
constructor() {
super();
this.standard = 5;
}
}
const obj = new MyObject();
console.log(obj);
Define the property on the prototype of Object like this:
Object.defineProperty(Object.prototype, 'standard', {
value: 5,
writable: true,
enumerable: true,
configurable: true
});
var p = {};
console.dir(p.standard);
This may be a helpful link that discuss about JavaScript objects. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
In JavaScript one can make an object by using the incorporated constructor of Object:
var person = new Object();
person.firstName = 'John';
person.lastName = 'Doe';
Almost all people seem to prefer the way of object-creation as a literal:
var person2 = {
firstName: 'Peter',
lastName: 'Smith'
}
Now I'm wondering:
Why is the constructor-way ignored completely?
But especially:
Are there cases in which one should prefer one way over the other?
I mean the constructor-way must be in there for some reason ...
I mean the constructor-way must be in there for some reason ...
The Object constructor was originally the only way to create an object. The object initializer syntax ({}) was added in JavaScript 1.2, the updated JavaScript in Netscape Navigator 4.0 in 1997.
There are several reasons to prefer initializer syntax to the Object constructor:
It's shorter
It's more expressive, particularly when using property initializers
It can't be overridden/shadowed (whereas Object can be)1
In contrast, there is basically no reason to use Object to create objects except indirectly, when using a variable that might point to the Object function or might point to some other function, e.g.:
function constructAndInit(ctor, props) {
var obj = new ctor();
if (props) {
for (var key in props) {
obj[key] = props[key];
}
}
return obj;
}
// Maybe use use Object...
var foo = constructAndInit(Object);
// ...or maybe you use somnething else
var bar = constructAndInit(NiftyThingy);
We do, of course, routinely use the Object function without calling it to create objects:
Any time we want to get access to the root object prototype, Object.prototype
To use the functions that are properties of Object, like Object.create, Object.defineProperty, and such
1 "can't be overridden/shadowed (whereas Object can be)" Here's an example of shadowing Object:
function foo() {
var Object = {
foo: "bar"
};
// ...later...
var o = new Object(); // fails
}
foo();
I have an object that looks like
var customObject = function() {
this.property = "value";
};
customObject.prototype = new otherObject();
customObject.prototype.property2 = function() {};
etc. - it's much bigger than this.
I can successfully instantiate the object by writing new customObject().
Now I would like to create a rather similar object, although a little different. This involves modifying certain properties and perhaps even adding or removing some. As in the above example, I would like it to be invokable by writing new customObject2().
I thought I could simply do:
var customObject2 = new customObject();
customObject2.prototype = customObject.prototype;
customObject2.property = "modified value";
etc.
However, when I try to instantiate it by doing new customObject2() I receive an error, stating that the customObject2 is not a function.
I hope I could illustrate well enough as to what pattern I desire to create. What approach should I take to create such a pattern?
If customObject is not a host object (i.e. won't give you an illegal invocation error if you try to call it differently to expected) you can apply the constructor to a different this Object;
var customObject2 = function () {
customObject.call(this); // construct as if `customObject`
// now do more stuff
this.anotherProperty = 'foo';
};
customObject2.prototype = Object.create(customObject.prototype);
// inherit prototype but keep original safe
new customObject2();
Backwards compatible Object.create
function objectWithProto(proto) {
var f;
if (Object.create) return Object.create(proto);
f = function () {};
f.prototype = proto;
return new f();
}
I think this should answer your question. Basically, the new keyword is returning an object and not a function.
Why are you not using the same formula you used the first time? For example:
var customObject2 = function(){};
customObject2.prototype = new customObject();
customObject2.property = "modified value";
new customObject2(); // works!
All properties of customObject will be inherited by the instances of customObject2 through the prototype chain.
I have multiple eatable classes in javascript eg: food, drinks, snacks.
Each of this class requires a different set of parameters. I have another factory class which creates an instance of the eatable item that is sent to it.
I am not able to figure out how can we dynamically select the eatable item and pass the arguments (which are in an array form) using this factory?
I have come up with two solutions -
Solution 1:
var factory = function(eatable, argumentList){
var obj = new eatable(argumentList);
return obj
};
This is a problem because argumentList is an array.
Solution 2
var factory = function(eatable, argumentList){
var obj = eatable.apply({}, argumentList);
return obj
};
this does not really create an object of the eatable type.
The effect that I really want
Say I am able to convert the argumentList into a js argument type object then -
var obj = new eatable(argumentList.toArguments());
obj instanceOf eatable; // should return true
Please help!
Ah, yes. I've encountered this problem before - you can't use new and apply together in JavaScript. A similar question has been asked before: Use of .apply() with 'new' operator. Is this possible?
The problem is quite apparent - new is a keyword, not a function; and apply can only be used on a function. If new was a function instead of a keyword then we could use it in conjuction with apply.
To understand how to do so let's create a function called new which does exactly what the keyword new does:
Function.prototype.new = (function () {
function Factory(constructor, args) {
return constructor.apply(this, args);
}
return function() {
Factory.prototype = this.prototype;
return new Factory(this, arguments);
};
}());
Now instead of calling a constructor as follows:
var object = new constructor(arg1, ...);
You can call a constructor as follows:
var object = constructor.new(arg1, ...);
What's the advantage of doing so you ask? Well it's simple really. Because new is now a function instead of a keyword you can use it in conjunction with apply as follows:
var object = Function.new.apply(constructor, [arg1, ...]);
Hence your eatable factory function now becomes:
var factory = function(eatable, argumentList) {
var obj = Function.new.apply(eatable, argumentList);
return obj;
};
Edit: If all your factory function does is take an eatable constructor and an argumentList and return new.apply(eatable, argumentList) then as Bergi pointed out in his comment you could define factory as follows instead:
var factory = Function.apply.bind(Function.new);
Hope this helped.
You can use Object.create to set up the prototype chain correctly:
function factory(eatable, argumentList){
var obj = Object.create(eatable.prototyope);
return eatable.apply(obj, argumentList) || obj;
}
This is basically what the new operator does.
You can define a function init to initialize the object .
function Eatable(){
}
Eatable.prototype.init = function(/** arg1, arg2, arg3 **/){
// initialize object
}
In factory function
var eatable = new Eatable();
eatable.init.apply(eatable, /** pass arguments array here **/);
return eatable;
You have to provide context to apply, The context is the object you are trying to apply the arguments to. The context you are currently passing {} is of type Object
var factory = function(eatable, argumentList){
var obj = eatable.apply(new Eatable(), argumentList);
return obj
};
I can not use factories with out polymorphism so if you didn't create those eatables in way they extend an Eatalbe object you will not be able to do it.
One more way to achieve this is as follows -
var _bind = Function.prototype.bind;
var factory = function(_constructor, _argumentList){
var obj = _bind.apply(_constructor, [null].concat(_argumentList));
return obj
};
I'm trying to generate a class from an object in JavaScript. For example:
var Test = {
constructor: function() { document.writeln('test 1'); },
method: function() { document.writeln('test 2'); }
};
var TestImpl = function() { };
TestImpl.prototype.constructor = Test.constructor;
TestImpl.prototype.method = Test.method;
var x = new TestImpl();
x.method();
But this doesn't work: it'll only write 'test 2' (for whatever reason, constructor isn't being defined properly). Why?
I think you're doing it wrong.
Remember, JavaScript doesn't actually have classes at all. It has prototypes instead. So what you're really trying to do is create a prototype object that works like a collection of functions that you've built on another object. I can't imagine any useful purpose for this -- could you elaborate as to what you're trying to do?
Although I think you could make it work by using something like:
var TestImpl = function() {
Test.constructor.apply(this);
};
TestImpl.prototype.method = Test.method;
Your TestImpl function is the constructor. Usually you would do something like this:
var Test1 = function () {
document.writeln('in constructor');
};
Test1.prototype = {
x: 3,
method1: function() { document.writeln('x='+this.x); }
}
var y1 = new Test1();
y1.method1();
y1.x = 37;
y1.method1();
var y2 = new Test1();
y2.method1();
y2.x = 64;
y2.method1();
I think you have things a little backwards. Usually you will assign a prototype to a constructor, rather than assigning a constructor to a prototype.
The reason for assigning a method to the constructor's prototype, rather than to the "this" object inside the constructor, is that the former method creates only 1 shared function, whereas the latter method creates separate instances of a function. This is important (to keep memory allocation to a reasonable amount) if you create lots of objects each with lots of methods.
var Test = function () {
document.writeln('test 1');
this.method = function() { document.writeln('test 2'); }
};
var x = new Test();
x.method();
Javascript doesn't have a "Class" concept, It's all about prototype and the way you use them [ and you can simulate any kind of inheritance with this little neat feature. ]
In javascript "Function" plays the role of [ Class, Method and Constructor ].
so inorder to create "Class" behaviour in Javascript all you need to do is to use the power of "Function".
var A = function(){
alert('A.Constructor');
}
A.prototype = {
method : function(){
alert('A.Method');
}
}
var b = new A(); // alert('A.Constructor');
b.method(); // alert('A.Method');
now the neat thing about JS is that you can easily create "Inheritance" behaviour by using the same method. All you need to do is to connect the second class "Prototype Chain" to the first one, How?
B = function(){
this.prototype = new A(); // Connect "B"'s protoype to A's
}
B.prototype.newMethod = function() { alert('testing'); }
var b = new B();
b.method(); // Doesn't find it in B's prototype,
// goes up the chain to A's prototype
b.newMethod(); // Cool already in B's prototype
// Now when you change A, B's class would automatically change too
A.prototype.method = function(){ alert('bleh'); }
b.method(); // alert('bleh')
If you need any more references I suggest to take a look at Douglas Crockford's Site
Happy JS ing.