This question isn't a duplicate of Using "Object.create" instead of "new". The thread in question doesn't focus on passing arguments correctly when using Object.create
I am curious as to how I would go about initializing objects using Object.create as opposed to new. Here is my code so far:
function Human(eyes) {
this.eyes = eyes || false;
}
Human.prototype.hasEyes = function() {
return this.eyes;
}
function Male(name) {
this.name = name || "No name";
}
Male.prototype = new Human(true); //passing true to the Human constructor
var Sethen = new Male("Sethen");
console.log(Sethen.hasEyes());
As you can see above, the Male.prototype = new Human(true); creates a new object with true. When the hasEyes() function is run, this logs true as expected.
So, my question is.. using Object.create how would I go about doing this the same way passing a true parameter??
You must call the constructor using Object.call(this) and then pass your arguments.
function Human(eyes, phrase) {
this.eyes = eyes || false;
this.phrase = phrase;
}
Human.prototype.hasEyes = function() {
return this.eyes;
}
Human.prototype.sayPhrase = function() {
return this.phrase;
}
function Male(name) {
Human.call(this, true, "Something to say"); //notice the call and the arguments
this.name = name || "No name";
}
Male.prototype = Object.create(Human.prototype);
var Sethen = new Male("Sethen");
console.log(Sethen.hasEyes());
console.log(Sethen.sayPhrase());
console.log(Object.getOwnPropertyNames(Sethen));
This works and now the object Male has the properties of eyes and phrase
is this give some clue about prototype inheritance model.
const Human = {
constructor: function (eyes) {
this.eyes = eyes || false;
},
hasEyes: function () {
return this.eyes;
}
};
let Male = Object.create(Human);
Male.constructor = function (name) {
this.name = name || "No name";
return Human.constructor.call(this, "true");
};
let Sethen = Object.create(Male);
Sethen.constructor = function() {
return Male.constructor.call(this, 'Sethen');
};
Sethen.constructor();
console.log(Sethen.hasEyes());
console.log(Object.getOwnPropertyNames(Sethen));
Related
I learned about prototype and proto and i think i understand it but this just doesn't make sense? Can somebody explain to me why accessing directly Object like this doesn't work.
function createObj() {
this.name = 'user';
this.prezime = 'user';
}
var obj1 = new createObj();
createObj.prototype.__proto__.toString = function () {
return 'works';
} //obj1.toString() returns 'works'
createObj.__proto__.__proto__.toString = function () {
return 'this works as well';
} //obj1.toString() returns 'this works as well '
//Then why this doesn't work:
Object.toString = function () {
return true;
}
From my understanding I am directly changing Object object.
So when I do obj1.toString() shouldn't it go to prototype and
then proto inside prototype and find toString() like it does from last two examples?
This is because you're setting a property on the Object constructor, not the Object prototype when you say Object.toString = ....
Trying to understand the difference between prototype and constructor in JavaScript
If you change Object.toString = ... to Object.prototype.toString = ... you get your desired result:
function createObj() {
this.name = 'user';
this.prezime = 'user';
}
var obj1 = new createObj();
createObj.prototype.__proto__.toString = function() {
return 'works';
} //obj1.toString() returns 'works'
console.log(obj1.toString());
createObj.__proto__.__proto__.toString = function() {
return 'this works as well';
}
console.log(obj1.toString());
Object.prototype.toString = function() {
return true;
}
console.log(obj1.toString())
What am I trying to do is as following:
var Person = function(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
// This will return error;
console.log(Person('John').getName());
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());
Am I misunderstanding something?
// This will return error;
console.log(Person('John').getName());
it returns an error bcoz Person() by default returns undefined ,but if you use new it will return the newly created object.
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());
this works bcoz a new object with __proto__ set to Person.prototype is returned and since there is a getName() on it , it works as expected.
you may use scope safe constructor for your constructor to work without explicit new.
function Person(name) {
if(this instanceof Person) {
this.name = name;
} else {
return new Person(name);
}
}
http://www.mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
If you don't want to have the new keyword all over your code (and I can't think of a good reason to want that, you would be basically hiding an important information), you could just do something like:
var pPerson = function(name) {
this.name = name;
};
pPerson.prototype.getName = function () {
return this.name;
};
var Person = function (name) {
return new pPerson(name);
};
You can use Object.create() if you don't want to use the new keyword. Here's an example from MDN:
// Animal properties and method encapsulation
var Animal = {
type: "Invertebrates", // Default value of properties
displayType : function(){ // Method which will display type of Animal
console.log(this.type);
}
}
// Create new animal type called animal1
var animal1 = Object.create(Animal);
animal1.displayType(); // Output:Invertebrates
// Create new animal type called Fishes
var fish = Object.create(Animal);
fish.type = "Fishes";
fish.displayType(); // Output:Fishes
If you really really hate your self, you can do this
var Person = function(name) {
var This = {};
This.name = name;
//See note
Object.setPrototypeOf(This, arguments.callee.prototype);
return This;
}
Person.prototype.getName = function () {
return this.name;
}
var p = Person('John');
console.log(p.getName());
Note
You absolutely have to read about this.
You can try creating prototype functions as a part of parent function itself.
var Person = function(name) {
this.name = name;
this.get_name = function() {
return this.name;
}
return this;
}
Person.prototype.getName = function() {
return this.name;
}
// This will return error;
console.log(Person('John').get_name());
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());
$(document).ready(function () {
var patient = (function (options) {
var age = options.age;
var name = options.name;
function getName() {
return this.name;
}
function setName(val) {
name = val;
}
function getAge() {
return this.age;
}
function setAge(val) {
age = val;
}
return {
getAge: getAge,
setAge: setAge,
getName: getName,
setName: setName
}
})();
});
I realize that I'm never passing any options in my example here.
If I try to do something like patient.setAge('100') and then console.log(patient.getAge()) I get an error saying cannot read property Age of undefined. The overarching theme that I'm trying to get at is within a module, how can I emulate consturctors to instantiate a new patient object while keeping all the OOP goodness of private variables and all that jazz.
I've seen some examples of constructors in a module pattern on here and I haven't understood them very well. Is it a good idea in general to have a constructor in a module? Is its main purpose similarity with class-based languages?
This is a constructor:
function Patient(options) {
options = options || {};
this.age = options.age;
this.name = options.name;
}
$(document).ready(function () {
var patient = new Patient();
});
You can put it inside a module if you want. What you shouldn’t do is provide getters and setters, especially ones that don’t do anything. If you’re exposing a variable through two properties to get and set it, it should just be one property.
Try this
function Patient (options) {
options = options || {};
var age = options.age;
var name = options.name;
function getName() {
return name;
}
function setName(val) {
name = val;
}
function getAge() {
return age;
}
function setAge(val) {
age = val;
}
return {
getAge: getAge,
setAge: setAge,
getName: getName,
setName: setName
}
}); // pass empty object
$(document).ready(function () {
var p1 = new Patient({});
var p2 = new Patient();
var p3 = new Patient({age:20});
var p4 = new Patient({name:"abcd"});
var p5 = new Patient({age:21, name:"abcd"});
});
I have been reading JavaScript Patterns book by Stoyan Stefanov and one of the patterns to enforcing the new operator for constructor functions goes like this
function Waffle() {
if (!(this instanceof Waffle)) {
return new Waffle();
}
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
when writing this way you can invoke Waffle either one of these ways
var first = new Waffle(),
second = Waffle();
I think this is a helpful feature not sure if it's implemented in future versions of ecma/javascript
I came up with something on my own that I thought could just copy and paste each time when creating a constructor function
something like this
function checkInstance (name) {
if (name.constructor.name === undefined) {
return "construct it"
} else {
return false;
}
}
function Waffle() {
var _self = checkInstance.call(this, this);
if (_self === "construct it") {
return new Waffle()
}
this.tastes = "yummy"
}
var waffle = Waffle()
waffle
Therefore I can invoke Waffle either way new Waffle or Waffle() and still have it return an object
My problem that I'm having is here
if (_self === "construct it") {
return new Waffle()
}
Is there anyway I can refer to new Waffle() without referring to the actual name of the constructor function meaning so I could copy and paste this each time and not have to change anything. Meaning I could I save Waffle() as a variable and do something like
return new var
I wish I could use this.name but that doesn't work either until it is invoked.
I have a feeling I can't but wanted to at least ask some of the people here on stack overflow if it was a possibility
Again your comments and feedback is appreciated
I have a better solution. This is what you're currently doing:
function Waffle() {
if (!(this instanceof Waffle))
return new Waffle;
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
This pattern isn't really nice because you're mixing the code to construct a new object with the code to check if the new keyword is being used.
I've mentioned before that you shouldn't use the new keyword in JavaScript as it breaks functional features. Instead let's create another function which does the same thing:
Function.prototype.new = (function () {
return function () {
functor.prototype = this.prototype;
return new functor(this, arguments);
};
function functor(constructor, args) {
return constructor.apply(this, args);
}
}());
This function allows you to create an instance of a function as follows:
var waffle = Waffle.new();
However we don't want to use new at all. So to do away with it we'll create a function which wraps a constructor as follows:
function constructible(constructor) {
function functor() { return Function.new.apply(constructor, arguments); }
functor.prototype = constructor.prototype;
return functor;
}
Now we can define the Waffle function as follows:
var Waffle = constructible(function () {
this.tastes = "yummy";
});
Waffle.prototype.wantAnother = true;
Now you can create objects with or without using new:
var first = new Waffle;
var second = Waffle();
Note: The constructible function is pretty slow. Use the following version of constructible instead - it's a little faster:
function constructible(constructor) {
constructor = Function.bind.bind(constructor, null);
function functor() { return new (constructor.apply(null, arguments)); }
functor.prototype = constructor.prototype;
return functor;
}
Personally I wouldn't use either of these two methods. I would just remember to write new, or (more likely) I would restructure my code as follows:
var waffle = {
create: function () {
var waffle = Object.create(this);
waffle.tastes = "yummy";
return waffle;
},
wantAnother: true
};
var first = waffle.create();
var second = waffle.create();
If you want to know more about this pattern then read the following answer: https://stackoverflow.com/a/17008403/783743
You could use something like this:
var Waffle = (function() {
function Waffle() {
this.tastes = "yummy"
}
return exportCtor( Waffle );
})();
var waffle = Waffle();
alert(waffle.tastes);
console.log(Waffle);
/*
function ConstructorProxy() {
"use strict";
return new Constructor();
}
*/
http://jsfiddle.net/ywQJF/
It handles variable arguments too
arguments.callee, which refers to the current function, is the most simple solution. It's is deprecated, though, so use it at your own risk.
function Waffle() {
if (!(this instanceof arguments.callee))
return new arguments.callee();
this.tastes = 'yummy';
}
It's a hard problem also because you probably want to preserve the arguments you're passing, as Vinothbabu mentioned. But if you real intention is enforcing new, you could simply throw an error, which is a simple two lines of code:
if (!(this instanceof Waffle))
throw new Error('Constructor called without new');
You could even wrap it in a function:
function cons(C) {
var c = function () {
if (!(this instanceof c))
throw new Error('Constructor called without new');
C.apply(this, arguments);
};
c.prototype = C.prototype;
return c;
}
var Waffle = cons(function () {
this.tastes = 'yummy';
});
Waffle.prototype.wantAnother = function () {
return true;
};
new Waffle(); // { tastes: 'yummy', 'wantAnother': true }
Waffle(); // throws error
Now Waffle must be called with new -- otherwise, it throws an error.
The best approach, in my opinion, is not to enable yourself to invoke things incorrectly:
function Waffle() {
if (!(this instanceof Waffle)) {
throw "Waffles need to be fresh or they're gross. Use 'new'.";
}
}
But, if you simply must enable yourself to write inconsistent code, make initialization a separate step.
function Waffle(options) {
var o = options || {};
if (this instanceof Waffle) {
this.init = function() {
/* this is really your constructor */
console.log("initializing ... ");
}
if (!o.__do_not_initialize) {
this.init(arguments);
}
} else {
var rv = new Waffle( { __do_not_initialize: true } );
rv.init(arguments);
return rv;
}
}
If you want to force consistency the other way -- never using the new keyword, create a builder function:
function BuildWaffle(options) {
var o = options || {};
if (this instanceof WaffleBuilder) {
throw "BuildWaffle cannot be instantiated.";
}
var Waffle = function Waffle() { /* whatever */ }
Waffle.prototype.doStuff = function() { /* whatever else */ }
var rv = new Waffle(options);
return rv;
}
There is simpler way how to enforce creation of new object even without new:
function Waffle() {
return {tastes:"yummy"};
}
var a = Waffle();
var b = new Waffle();
alert(a.tastes); // yummy
alert(b.tastes); // yummy
Explanation
Using new with function, there are two possibilities:
the function returns object: the object is the result of the new function() expression
the function doesn't return object: the function itself with new context is returned
See the ECMA script documentation
Workaround: prototype and arguments
function Waffle(taste,how) {
return {
tastes: taste+" "+how,
__proto__: Waffle.prototype
}
}
Waffle.prototype.wantmore = "yes";
var a = Waffle("yummy","much");
var b = new Waffle("gummy","little");
console.log(a.tastes,b.tastes); // yummy much, gummy little
console.log(a.wantmore,b.wantmore); // yes, yes
This deserves a fiddle.
Note: constructor.name (which you used in your pattern) is not standard
Note 2: __proto__ is also not standard, but is supported by modern browsers and will be standardized in ES6.
if (!(this instanceof Waffle)) {
return new Waffle();
}
This has two problems...
one that it won 't work in an anonymous function which has no name
it loses all arguments sent to the constructor.
Using a more generic approach might look something more like this:
if (!instanceExists(this, arguments)) {
return requireInstance(this, arguments);
}
This approach ensures that the constructor is called with new, without having to state the function'
s name, andadds all arguments sent to the constuctor so they aren 't lost during the process.
Here 's the full code for the above:
Function.prototype.callNew = function (args) {
var a = [];
for (var i = 0; i < args.length; i++) a.push("a[" + i + "]");
var fn = new Function("var a=arguments;return new this(" + a.join(",") + ");");
return fn.apply(this, args);
}
function instanceExists(t, args) {
if (t instanceof args.callee) {
return true;
} else {
return false;
}
}
function requireInstance(t, args) {
var fn = args.callee;
if (!instanceExists(t, args)) {
return fn.callNew(args);
}
}
function Waffle(one, two, three) {
if (!instanceExists(this, arguments)) {
return requireInstance(this, arguments);
}
this.one = one;
this.two = two;
this.three = three;
}
Waffle.prototype.serve = function () {
var out = [];
for (var j in this) {
if (!this.hasOwnProperty(j)) continue;
out.push(j + ': ' + this[j]);
}
return ' {
' + out.join(",\n") + '
}
';
}
A fiddle for you to play with.
http://jsfiddle.net/RkPpH/
var waffle = Waffle(1, 2, 3);
alert(waffle.serve());
I didn't get a sense of whether this was client or server-side, but a pattern I use sometimes goes as follows. I use this in Node but have attempted to make it a possible client-side solution as well - the Node-specific stuff is commented out but there for reference depending on your environment.
First, I create something to be used along the lines of a traditional OO base or super class like so:
//// Node:
//module.exports.Base = Base;
function Base(opts) {
var self = this;
if (!(self instanceof Base)) return new Base(opts);
self.opts = opts || {};
}
Upon which you can define your methods, in usual the fashion. You can even manually throw if the method should be provided by subclasses implementing something like abstract:
// commonMethod is available to subclasses:
Base.prototype.commonMethod = function () {
var self = this;
//access self.opts to get the constructor arguments.
//makes self always point to the right object.
}
// Provide abstractMethod, but subclass is responsible for implementation:
Base.prototype.abstractMethod = function () {
//or throw an error if this should be implemented by subclasses:
throw new Error('implement me');
}
Now you can do this:
//// If using Node:
//var inherits = require('util').inherits;
//var Parent = require('./Base').Base;
function Sub (opts) {
var self = this;
//// If using node and you want super_ to be called prior to creating a new Sub:
//if(Sub.super_) Sub.super_.call(this, opts);
// Always do this:
if (!(self instanceof Sub)) return new Sub(opts);
//// If using node and you are ok with super_ called after creating new Sub:
//if(Sub.super_) Sub.super_.call(this, opts);
//// otherwise:
parent(opts);
}
//// If using Node:
//inherits(Sub, Base);
//// Otherwise:
Sub.prototype.constructor = Base;
Sub.prototype.parent = Base.prototype;
//and provide the implementation of abstractMethod:
Sub.prototype.abstractMethod() {
//...
}
And to formally answer the specific question, all of the
if (!(self instanceof Sub)) return new Sub(opts);
is where you get the guaranteed new situation.
Is there a difference between the two codes below, I presume not.
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
this.isActive = true;
this.isMale = false;
}
and
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
}
Agent.prototype.isActive = true;
Agent.prototype.isMale = true;
There is a difference at least if you are assigning a non-primitive object to this.somevar or prototype.somevar.
Try running this:
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
this.isActive = true;
this.isMale = false;
this.myArray = new Array(1,2,3);
}
function Agent2(bIsSecret)
{
if(bIsSecret)
this.isSecret = true;
}
Agent2.prototype.isActive = true;
Agent2.prototype.isMale = true;
Agent2.prototype.myArray = new Array(1,2,3);
var agent_a = new Agent();
var agent_b = new Agent();
var agent2_a = new Agent2();
var agent2_b = new Agent2();
if (agent_a.myArray == agent_b.myArray)
alert('agent_a.myArray == agent_b.myArray');
else
alert('agent_a.myArray != agent_b.myArray');
if (agent2_a.myArray == agent2_b.myArray)
alert('agent2_a.myArray == agent2_b.myArray');
else
alert('agent2_a.myArray != agent2_b.myArray');
No. 'prototype' used for implementing inheritance in Javascript. Such as that:
/** obsolete syntax **/
var Person = Class.create();
Person.prototype = {
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
};
var guy = new Person('Miro');
guy.say('hi');
// -> "Miro: hi"
var Pirate = Class.create();
// inherit from Person class:
Pirate.prototype = Object.extend(new Person(), {
// redefine the speak method
say: function(message) {
return this.name + ': ' + message + ', yarr!';
}
});
var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"
code source and additional info you can find here: http://www.prototypejs.org/learn/class-inheritance
Functionally, this is the same. The latter, however, emphasizes similarities between Agent objects. You can see in a glimpse that these members have that value, while in a more complicated constructor function, with lots of conditionals, it's harder.
It also allows the javascript runtime to choose how it handles Agent member initializations. (do some precompilation, ...)
Assuming that this function is to be used as a constructor, the first with set properties on the new instance and the second on the prototype. If they are independent of the instance the two snippets are equivalent, but if they aren't (as their name suggest), then they are not.