Equivalence of object constructors - javascript

Often, when I create an object in Javascscript, I will do something like this:
function getObj(property) {
return {
property,
displayProp: function() {
console.log(this.property);
}
}
}
let obj = getObj("Hello World!);
I know that the usual way to create a constructor would be as such:
function getObj(property) {
this.property = property;
this.displayProp = function() {
console.log(this.property);
}
}
let obj = new getObj("Hello World!);
Now, my question is, are these two methods equivalent. As far as I can tell, they are the same, and you can also use the 'new' keyword when creating an object using the first case. For me, the first case makes more sense, but it doesn't matter too much to me. Thanks.

The first example is a function that returns a litteral object (which constructor will remain simply "Object").
The second one creates a new constructor.
function getObj(property) {
return {
property,
displayProp: function() {
console.log(this.property);
}
}
}
// this will be useless because the prototype of getObj is not related to the returned object
getObj.prototype.test_prop = "Test prop";
let obj = getObj("Hello World!");
console.log(obj.constructor.name) // Object
console.log(obj.test_prop) // undefined
function Obj(property) {
this.property = property;
this.displayProp = function() {
console.log(this.property);
}
}
Obj.prototype.test_prop = "Test prop";
obj = new Obj("Hello World!");
console.log(obj.constructor.name) // Obj
console.log(obj.test_prop) // Test prop

Related

Call a member function of a class inside JSON object in a shorter way

My code is as follows,
class myClass
{
constructor()
{
this.memberVar1="";
this.memberVar2="";
}
memberFunction1()
{
// memberFunction1 code
}
}
var myObj = {
objVar1 : someJsonObject,
objVar2 : new myClass()
}
Instead of calling the memberFunction and memberVar1,memberVar2 like
myObj.objVar2.memberVar1;
myObj.objVar2.memberFunction1();
I wish to call them as follows
myObj.memberVar1;
myObj.memberFunction1();
Is there any way i can restructure myObj to achieve this ?
Thanks in advance
Functions are first class objects in Javascript, and a member of a Javascript class is just an object, so there's nothing stopping you setting the reference that myObj.memberFunction1 to whatever you like, including someJsonObject.memberFunction1, however you need to be aware that the behavior of this will be different depending on how you set the reference. This may be important to make your memberFunction behave correctly depending on context.
class myClass
{
constructor()
{
this.memberVar1="";
this.memberVar2="";
}
memberFunction1()
{
// memberFunction1 code
}
}
let someJsonObject = {
memberFunction1: function(source) {
if (this === myObj) { console.log(`${source}: "this" is myObj`) }
else if (this === someJsonObject) { console.log(`${source}: "this" is someJsonObject`) }
else { console.log('JavaScript interpreter is insane') }
}
}
var myObj = {
objVar1 : someJsonObject,
objVar2 : new myClass(),
memberFunction1: someJsonObject.memberFunction1 // the assignment will cause "this" to point to myObj
}
console.log('==== setting the reference (changes this) ====')
myObj.memberFunction1('myObj')
someJsonObject.memberFunction1('someJsonObject')
myObj.objVar1.memberFunction1('myObj.objVar1') // myObj.objVar1 is === someJsonObject
myObj.keepThis = myObj.memberFunction1 // You can hang onto the "myObj" referenced version of the function if you want
console.log('==== binding to someJsonObject ====')
myObj.memberFunction1 = myObj.memberFunction1.bind(someJsonObject) // using bind will make "this" point to whatever you like (i.e someJsonObject)
myObj.memberFunction1('myObj')
someJsonObject.memberFunction1('someJsonObject')
myObj.objVar1.memberFunction1('myObj.objVar1')
myObj.keepThis('myObj.keepThis')
This is one way of doing it:
const someObj = new myClass();
var myObj = {
objVar1 : {},
memberFunction1 : someObj.memberFunction1
}
Then call it like you want:
myObj.memberFunction1()
EDIT:
If you want to merge N number of members you can use Object.create like this:
const instance = new myClass();
const myObj = Object.create(instance);
myObj.memberFunction1()

Mass create methods for an object

I know that a new method for an object can be declare like so:
var MyObject = function() {return new MyObject.prototype};
MyObject.prototype.exists = function() {alert("The object exists.")};
How can I create many methods as a bunch for MyObject instead of one by one?
I have tried:
MyObject.prototype = {
exists: function() {alert("The object exists.")},
isBorn: function() {alert("The object is born.")},
isDead: function() {alert("The object has left our world.")}
}
Calling MyObject.exists() returns: Uncaught TypeError: MyObject.exists is not a function
What I am trying to do:
I am trying to do something like jQuery does.
jQuery is defined like so:
jQuery = function(selector, context) {included)
return new jQuery.fn.init(selector, context);
}
We don't say var j = new jQuery; when we call it like jQuery("#foo").
Then the files says:
jQuery.fn = jQuery.prototype = {
jquery: version,
constructor: jQuery,
length: 0,
toArray: function() {
return slice.call( this );
}
...
}
Isn't toArray() a method of the jQuery object? Why doesn't it show the same error when I call it.
When the jQuery function is called, you're not creating an instance of jQuery which is why you don't use the new keyword. Instead, you're returning an instance of jQuery.fn.init.
Follow it down and you'll see that the prototype of init being declared:
init.prototype = jQuery.fn;
And the definition for jQuery.fn is:
jQuery.fn = jQuery.prototype = { ... };
Which means that (new jQuery.fn.init(selector, context)) has all the methods from jQuery.prototype.
So, toArray is not a method of the jQuery object, but rather a method on the prototype of the return value from calling jQuery().
You can achieve the same thing in fewer steps by manually assigning the prototype of the return value.
function MyObject() {
var obj = {};
return Object.setPrototypeOf(obj, MyObject.prototype);
}
MyObject.prototype.toArray = function() {};
MyObject().toArray();
You were very close, you just have to create a new instance of the object for it to inherit from its own prototype chain.
var myObj = function () {};
myObj.prototype = {
a: function () { console.log(1) },
b: function () { console.log(2) },
c: function () { console.log(3) }
};
var myObject = new myObj();
myObject.a(); // 1
myObject.b(); // 2
myObject.c(); // 3
The first one is still better because prototype objects have predefined properties (currently only constructor, but later the standard can be extended), and totally overwriting the prototype object will effectively remove those properties. But still it can be shortened like:
function Foo() {}
const p = Foo.prototype;
console.log(Object.getOwnPropertyNames(p));
p.exists = function() { console.log("exists"); };
p.isBorn = function() { console.log("isBorn"); };
(new Foo).exists();
But hey, it's 2016! We have javascript classes in most major browsers (check compatibility at MDN)!
class Foo {
exists() { console.log("exists"); }
isBorn() { console.log("isBorn"); }
}
(new Foo).exists();

JavaScript prototypal inheritance to show parent object name

I've been reading about JavaScript prototypal inheritance and the prototype property, and I started making a fiddle to understand the concepts better. But I need help understanding why my example isn't working as I thought it would.
In the following example, I'm trying to create a hierarchy where when you create an object, it tells you the name of the parent object. However, my logs always return "object".
One article explained that prototype chaining works so that if a property is not found on the object, the prototype of the parent is checked, and it keeps going up until 'Object', and if not found returns undefined.
Here's a fiddle to go along: http://jsfiddle.net/hqozqd0m/
Object.prototype.cname = 'object';
function plant() {
function parentname() { return this.cname; }
return {
parentname:parentname
}
}
plant.prototype.cname = 'plant';
function tomato() {
function parentname() { return this.cname; }
return {
parentname:parentname
}
}
tomato.prototype = new plant(); // <-- settings it to plant as parent
var p = new plant();
var t = new tomato();
console.log(p.parentname()); //object
console.log(t.parentname()); //object
updated code - same result
Object.prototype.cname = 'object';
function plant() {
this.sayparentname = function() { console.log(cname); };
}
plant.prototype.cname = 'plant';
function tomato() {
this.sayparentname = function() { console.log(cname); };
}
tomato.prototype = new plant();
var p = new plant();
var t = new tomato();
p.sayparentname();
t.sayparentname();
Normally a constructor function will modify the object that new creates, with statements such as this.foo = bar, and not return anything. Then the result of the new expression is the object.
However, if the function returns an object, that object will replace the one that new created; so when you use new plant() you're just getting a plain Object instance back.
To fix your code you just need to make it like this:
function Plant() {
function parentName() { return this.cname; }
this.parentName = parentName;
}

Classes inside object literals

I was just not sure how to search this out despite many tries, so forgive me if this has been answered before.
The question is simple: can I create an instance of class window.A.class() as window.B?
To clarify, I have an object literal holding all my data for a browser game:
var gameName = {
environment: function() {
this.place = "...";
// ...
// ...
},
game: function() {
this.player = function() {
// ...
}
}
// and so on...
}
Could I create a window-level gameName.environment() instance with var A = new gameName.environment()? Are there any restrictions to creating an object-bound class's instance outside the class' parent object?
It doesn't really matter in this case how/where a function is defined. Consider these two examples:
function Foo() {}
var obj = {
bar: Foo
};
and
var obj = {
bar: function () { }
};
As far as the function and the object are concerned, those two examples are equivalent. So no, there is no problem calling a function assigned to an object property with new. All you need is a reference to the function, it doesn't matter how you get that reference.
You could do
var Environment = gameName.environment;
var A = new Environment();
if you like that better, but that's totally unnecessary.

Javascript prototype on properties

I'd like to have an object with multiple levels of methods and properties. The top level will have properties and methods. Some of these properties will then act as name-spaces for second level methods and properties.
e.g.
//first level methods
base.doStuff();
base.doMore();
//second level methods
base.level2.doStuff();
Doing the first level is straight forward:
function Base(foo) {
this.foo = foo;
}
Base.prototype.doStuff = function () {
console.log(this.foo);
}
Base.prototype.doMore = function () {
console.log(this.foo);
}
base = new Base("bar");
base.doStuff();
Is it possible to get a second level, where in the function expression the "this" keyword points back to the Base constructor?
It's much easier to do this without prototypes:
function Base() {
var base = this;
base.level2 = {
moreStuff: function() {
// use "base" instead of "this" here
}
};
}
This can be combined with either prototypical methods, as in your example, or methods defined directly on base in the constructor. The downside of this is that you are creating the method functions every time you instantiate a new object, so you miss some of the shared-prototype goodness of standard prototypical methods.
You could create a new prototype-based object to be your level2:
function Level2() {}
Level2.prototype.moreStuff = function() {
// do stuff
}
function Base() {
this.level2 = new Level2();
}
But the methods of base.level2 won't be bound to base unless you bind them explicitly. Various libraries have bind support (e.g. Underscore's _.bind), or you can do it in plain JS:
function Base() {
var base = this;
base.level2 = new Level2();
base.level2.moreStuff = function() {
return Level2.prototype.moreStuff.apply(base, arguments);
}
}
You could further simplify here, but you're always going to have to make new methods bound in one way or another, because JS is never going to assign this in base.level2.moreStuff() to base without explicit binding - so in most cases the first option is the easiest and cleanest.
But really, is it worthwhile just for namespacing? If there's no functional value, it's a lot harder than simply calling your methods level2MoreStuff(), etc.
Well,
base.doStuff();
is calling doStuff in context of base. It is the same as
base.doStuff.call(base);
You can call and apply any function, for overriding this:
var base = new Base();
var someFun = function () {
console.log (this === base); // true
};
someFun.call(base);
Further anonymous example:
var anObj = {
method0: function () {
console.log (this === anObj); // true
}
};
anObj.method1 = function () {
console.log (this === anObj); // true
};
anObj.method0();
anObj.method1();
So the "second level" points this to level2, not to the "first level" object.
This is a really bad idea, but here goes:
function Base() {
this.name = 'Base';
this.level2 = new Level2(this);
}
Base.prototype.whatsMyName = function(){
alert(this.name);
};
function Level2(base) {
this.name='Level2';
for(var func in Level2.prototype) {
this[func] = Level2.prototype[func].bind(base);
}
}
Level2.prototype.whatsMyName = function(){
alert(this.name);
};
var b = new Base();
b.whatsMyName(); //Base
b.level2.whatsMyName(); //Also Base
You can see it running here: http://jsfiddle.net/zLFgd/1/

Categories