Define a "nested" object constructor in JavaScript? - javascript

Is it possible to define an object within another object? I'm thinking something like this:
function MyObj(name) {
this.name = name;
function EmbeddedObj(id) {
this.id = id;
}
}
And I could then create an EmbeddedObj like this:
var myEmbeddedObj = new MyObj.EmbeddedObj();
Meme for bonus points: Objectception! :o

Yes, and no.
function MyObj(name) {
this.name = name;
}
MyObj.EmbeddedObj = function EmbeddedObj(id) {
this.id = id;
}
new MyObj.EmbeddedObj(42);
Would run, but it might not yield the expected results for "embedded object" (see comment).
Note that in the case of new expr the expression is evaluated first so, in this case it creates a new object using the function-object evaluated from MyObject.EmbeddedObj as a constructor. (There is a silly rule with parenthesis in the expression, but that's another story.)
Now, if a "parent" and "child" relationship was desired, that could be done, using a more round-about method:
function Parent (name) {
this.name = name;
var parent = this; // for closure
this.Child = function Child () {
this.Parent = parent;
}
}
// create new parent object
var parent = new Parent();
// each new parent has a different Child constructor and
// any function-object can be used as a constructor
var child = new parent.Child();
// true: child is "bound" to parent
child.Parent === parent;

function MyObj(name) {
this.name = name;
}
MyObj.EmbeddedObj = function(id) {
this.id = id;
}
var myEmbeddedObj = new MyObj.EmbeddedObj();
Does that look like what you're after?

Here is example of nested constructor.
function cimdb(name,review,year) {
function nestedConstructor(name,review,year) {
this.name = name;
this.review = review;
this.year = year
};
this.name = name;
this[name] = new nestedConstructor(name,review,year);
}
var lionking = new cimdb("The Lion King", "The lion King review ..", 2015);
I guess this is what you mean by nested object constructor.

The easiest way to nest other objects in a constructor is to create its field and then create a new object when invoking the constructor. Below is an example:
function Product(name, price, category, producer) {
this.name = name;
this.price = price;
this.category = category;
// nested constructor
this.producer = producer;
}
function Producer(contributor, address) {
this.contributor = contributor;
this.address = address;
}
let prod1 = new Product("Milk", 2.5, "Dairy", new Producer("Nestle", "Warszawa"));

Related

Update an instance's property, from another instance

I'm looking for the best way to update in object instance, for the example in this case myParentObjects's name property. The only way I understand to achieve this would be to pass reference of the parent object to the child object instance as a parameter into either new myChildObj(this,name) in the constructor, or a method of the myChildObj instance like myChildObj.updateParentProperty(name).
I can't imagine a child object nested 4-5 levels down, and having to update properties on it's parents passing (parent1,parent2,parent3,etc) it's params, that would be a managing nightmare! there must be a better way to update parent properties!
function myParentObj(){
this.name = 'jordan'
this.names = ['jordan','danny','cassie'];
this.init=()=>{
this.names.forEach((name)=>{
var childObj = new myChildObj(this,name);
childObj.updateParentProperty();
})
}
}
function myChildObj(parentObj,name){
this.parent = parentObj;
this.name = name;
this.updateParentProperty=()=>{
this.parent.name = this.name;
};
}
function init(){
var parentObj = new myParentObj();
parentObj.init();
}
document.addEventListener('DOMContentLoaded',init);
Question: What is the best method to update parent object parameters?
What puzzles me is this:
this.init=()=>{
this.names.forEach((name)=>{
var childObj = new myChildObj(this,name);
childObj.updateParentProperty();
})
}
because as soon as all three children are created, your parent will have a name of cassie (since that's the last child calling updateParentProperty). That and your tags is why I'm inclined to claim that you're looking for classical inheritance, like so:
Classical inheritance
function myParentObj (name) {
this.name = name;
this.names = ['jordan','danny','cassie'];
this.init=()=>{
this.names.forEach((name)=>{
var childObj = new myChildObj(name);
console.log(childObj);
});
}
}
function myChildObj (name) {
myParentObj.call(this, name);
// Other stuff, only available for myChildObj
}
function init(){
var parentObj = new myParentObj();
parentObj.init();
}
document.addEventListener('DOMContentLoaded',init);
var parent = new myParentObj();
console.log(parent);
Which would mean the child inherits properties from its parent, but would of course not update them for the parent when their own name changes.
Some simple observer pattern
Okay, your example just has a single property which change should be noticed. I think an observer pattern like in the example below is a bit too much, but for larger applications it's quite useful.. the observer pattern is not distinct to JavaScript only (see enter link description here). Basically, you have an object which changes shall be monitored (observable) and one or many objects which want to perform actions depending on these changes (observers). The implementation can be quite simple (like my demonstration) or really complex. The basic idea is for the observable to maintain a list of its observers. The example uses an own, simple implementation. There are also libraries available, we're using knockout, which offers a MVVM structure for your page and can even update the DOM depending on changes.
function myParentObj(){
this.name = 'jordan'
this.names = ['jordan','danny','cassie'];
this.init=()=>{
this.names.forEach((name)=>{
var childObj = new myChildObj(name);
childObj.subscribe('name', newValue => this.name = newValue);
})
}
}
function myChildObj(name){
this.subscribers = {};
Object.defineProperty(this, 'name', {
set: newValue => {
this._name = newValue;
this.notify('name');
},
get: () => this._name
});
this.subscribe = function (prop, callback) {
if (!this.subscribers.hasOwnProperty(prop)) {
this.subscribers[prop] = [];
}
this.subscribers[prop].push(callback);
};
this.notify = function (prop) {
if (this.subscribers[prop]) {
this.subscribers[prop].forEach(callback => callback(this[prop]));
}
};
}
function init(){
var parentObj = new myParentObj();
parentObj.init();
}
document.addEventListener('DOMContentLoaded',init);
var parent = new myParentObj();
var child = new myChildObj('bob');
child.subscribe('name', newName => parent.name = newName);
console.log(parent.name);
child.name = 'cassie';
console.log(parent.name);
Using Object.assign
You could also use Object.assign, which will copy all enumerable properties from one object to another. You should note, though, that it will copy all properties, even those you might not want to change.
function myParentObj(){
this.name = 'jordan'
this.names = ['jordan','danny','cassie'];
this.init=()=>{
this.names.forEach((name)=>{
var childObj = new myChildObj(this,name);
childObj.updateParentProperty();
})
}
}
function myChildObj(name){
this.name = name;
}
var parent = new myParentObj();
var child = new myChildObj('cassie');
Object.assign(parent, child);
console.log(child);
Classical inheritance
I see you mixed in some ES6, so you might be looking for an answer using the ES6 standards of object-oriented inheritance like so:
class Parent {
constructor(name = 'jordan') {
this.name = name
this.names = ['jordan', 'danny', 'cassie']
}
init() {
return this.names.map((name) => {
return new Child(name)
})
}
}
class Child extends Parent {
constructor(name) {
super(name)
// other stuff for Child
}
}
let parent = new Parent()
console.log(parent)
let children = parent.init()
children.forEach((child) => console.log(child))
In ES5, inheritance was usually implemented like this instead, though this is not exactly what ES6 class does, since ES6 does things like making instance methods non-enumerable, etc.
function Parent(name) {
name = arguments.length > 0 ? name : 'jordan'
this.name = name
this.names = ['jordan', 'danny', 'cassie']
}
// member methods
Parent.prototype = {
init: function init() {
return this.names.map(function (name) {
return new Child(name)
})
}
}
function Child(name) {
// basically, super(name)
Parent.call(this, name)
// other stuff for Child
}
// extending Parent
Child.prototype = Object.create(Parent.prototype)
Parent.prototype.constructor = Parent
var parent = new Parent()
console.log(parent)
var children = parent.init()
children.forEach(function (child) { console.log(child) })
Below is almost exactly the ES5 equivalent for the ES6 code in the first example:
function Parent() {
var name = arguments.length > 0 && name !== undefined ? name : 'jordan'
this.name = name
this.names = ['jordan', 'danny', 'cassie']
}
// member methods
Object.defineProperties(Parent.prototype, {
init: {
configurable: true,
value: function init() {
return this.names.map(function (name) {
return new Child(name)
})
},
writable: true
}
})
function Child(name) {
// basically, super(name)
Parent.call(this, name)
// other stuff for Child
}
// extending Parent
Child.prototype = Object.create(Parent.prototype, {
constructor: {
configurable: true,
value: Child,
writable: true
}
})
var parent = new Parent()
console.log(parent)
var children = parent.init()
children.forEach(function (child) { console.log(child) })
EventEmitter
After looking at the comments below the other answer, it appears you are most interested in observer-type patterns. EventEmitter, defined natively in Node.js, is the most widely used implementation of the observer pattern. Below is a polyfill demo of it for client-side JavaScript:
class Parent extends EventEmitter {
constructor(name = 'jordan') {
super()
this.name = name
}
}
class Child {
constructor(parent, name = parent.name) {
this.parent = parent
this._name = name
}
set name(name) {
console.log('setting child name')
this._name = name
this.parent.emit('name', name)
}
get name() {
return this._name
}
}
let parent = new Parent()
parent.on('name', function (name) {
console.log('setting parent name')
this.name = name
}.bind(parent))
let child = new Child(parent)
console.log('parent', parent.name)
console.log('child', child.name)
child.name = 'danny'
console.log('parent', parent.name)
console.log('child', child.name)
<script src="https://cdn.rawgit.com/mudge/5830382/raw/a4bc230f5bce01ea9a34b0d42247256531b97945/eventemitter.js"></script>
Proxy
Another neat API that JavaScript has is called Proxy, which allows metaprogramming, that is, redefining how JavaScript works in isolated cases:
var parent = {}
var child = {}
var proxy = new Proxy(child, {
set: (target, property, value) => {
// target === child
target['child-' + property] = typeof value + ' ' + value
parent['parent-' + property] = typeof value + ' ' + value
return value
}
})
proxy.name = 'jordan'
proxy.age = 54
console.log(parent)
console.log(child)

Accessing 'this' inside an independent function in a Constructor

I have a Dog Constructor as follows:
var Dog = function(name,type)
{
this.name = name;
this.type = type;
this.normalObjFunc = function()
{
this.name = "kl";
}
var retfunc = function()
{
return this.name;
}
return retfunc;
}
In the retfunc function() , I am trying to access this.name in the following way.
var dogObj = new Dog("hj","labrador");
alert(dogObj());
In the output , I get as "result" in the alert messageBox, I am not getting what does the o/p "result" ,means?
I have purposely not included retfunc to "this" object, does it mean I cant access this.name inside retfunc() because a SEparate "this" would be created?
I am also aware of the fact that assigning var self =this solves the problem.
I just want to know what is "result" which is the output and why not undefined ideally?
The issue is because the scope of this within the functions will be the window. You need to cache the object reference in a variable and call that, like this:
var Dog = function(name, type) {
var _this = this;
this.name = name;
this.type = type;
this.normalObjFunc = function() {
_this.name = "kl";
}
var retfunc = function() {
return _this.name;
}
return retfunc;
}
var dogObj = new Dog("hj", "labrador");
console.log(dogObj());
Alternatively you can prototype the functions to keep the scope of this, however you would need to change your logic as it means that the return value of Dog() could not be the function.
var Dog = function(name, type) {
this.name = name;
this.type = type;
}
Dog.prototype.normalObjFunc = function() {
this.name = "kl";
}
Dog.prototype.retfunc = function() {
return this.name;
}
var dogObj = new Dog("hj", "labrador");
console.log(dogObj.retfunc());

How do I apply methods from a constructor object to an arbitrary object [duplicate]

This question already has answers here:
Casting plain objects to class instances in javascript
(4 answers)
Closed 6 years ago.
I have a constructor object that has various fields; For a simple example, say
function Person(id, name) {
this.id = id;
this.name = name;
etc.
this.someFunction = function(xxx) {...}
}
Now, I have an arbitrary object with an id and name field
var somePerson = {id:123, name:"joe"}
I would like to inject the data from the somePerson instance into a Person constructor, so I can apply all of the methods from the Person class, but I am confused between apply, call, and bind.
I am aware that I can call a new constructor passing in all of the fields, but there are a lot of fields. Is there any easy way to just endow the somePerson instance with the methods from the Person class?
I think you got it wrong, what you are trying to do is :
var somePerson = new Person(123, 'joe');
then you will be able to write :
somePerson.someFunction();
You need to create a new Person instance, there's no need to use call or apply.
var somePerson = {id:123, name:"joe"};
var somePersonInstance = new Person(somePerson.id, somePerson.name);
somePersonInstance.someFunction(xxx);
You could have used call if the method was not inside the constructor, but on the prototype:
function Person(id, name) {
this.id = id;
this.name = name;
}
Person.prototype.someFunction = function(xxx) {…};
var somePerson = {id:123, name:"joe"};
Person.prototype.someFunction.call(somePerson, xxx);
You could use Object.assign() and assign properties of somePerson object to instance of Person
function Person(id, name) {
this.id = id;
this.name = name;
this.someFunction = function() {
return this.name;
}
}
var somePerson = {id:123, name:"joe"}
var p = Object.assign(new Person, somePerson)
console.log(p.someFunction())
Person is set up like a constructor function. You need to use the new keyword to instantiate a new copy of Person.
var joe = new Person(somePerson.id, somePerson.name);
Now joe will be an instance of Person.
joe instanceof Person //true
joe.id //123
joe.someFunction //function (xxx) {...}
Sure How's this;
function PersonFactory(id, name) {
return {
id: id,
name: name,
updateName: function(name) {
this.name = name
}
}
}
Some exmaples of it being used.
var somePerson = PersonFactory(1, "Luke")
var people = {
luke: PersonFactory(1, "Luke"),
will: PersonFactory(2, "Will"),
smith: PersonFactory(3, "Smith")
}
var persons = [
PersonFactory(1, "Luke"),
PersonFactory(1, "Will"),
PersonFactory(1, "Smith")
]
people.luke.updateName("Harry");

How to use object oriented without using keyword ('new')

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());

Passing arguments to anonymous function of module

$(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"});
});

Categories