Extending an Object in Javascript
Asked Answered
N

17

201

I am currently transforming from Java to Javascript, and it's a bit hard for me to figure out how to extend objects the way I want it to do.

I've seen several people on the internet use a method called extend on object. The code will look like this:

var Person = {
   name : 'Blank',
   age  : 22
}

var Robot = Person.extend({
   name : 'Robo',
   age  : 4
)}

var robot = new Robot();
alert(robot.name); //Should return 'Robo'

Does anyone know how to make this work? I've heard that you need to write

Object.prototype.extend = function(...);

But I don't know how to make this system work. If it is not possible, please show me another alternative that extends an object.

Neighboring answered 3/5, 2012 at 11:18 Comment(3)
return true; but that is why I am asking :)Neighboring
If after reading those nice docs you're still curious about an extend function, I've set up an example here: jsfiddle.net/k9LRdCarlitacarlo
i'd also suggest not thinking about it strictly as 'transforming from Java to JavaScript' and more as 'learning a new language, Javascript, that has similar syntax to Java'Accredit
B
207

You want to 'inherit' from Person's prototype object:

var Person = function (name) {
    this.name = name;
    this.type = 'human';
};

Person.prototype.info = function () {
    console.log("Name:", this.name, "Type:", this.type);
};

var Robot = function (name) {
    Person.apply(this, arguments);
    this.type = 'robot';
};

Robot.prototype = Person.prototype;  // Set prototype to Person's
Robot.prototype.constructor = Robot; // Set constructor back to Robot

person = new Person("Bob");
robot = new Robot("Boutros");

person.info();
// Name: Bob Type: human

robot.info();
// Name: Boutros Type: robot
Banker answered 3/5, 2012 at 11:55 Comment(17)
I have one question: how is the Person() constructor being called when you do new Robot()? It seems to me that you should call that base class constructor instead of doing this.name = name; in the Robot() constructor...Linkman
@AlexisWilke: Yep, you should call Person.apply(this, arguments);. It would also be better do use Robot.prototype = Object.create(Person.prototype); instead of new Person();.Botulinus
As stated by Felix, 'Robot.prototype = Person.prototype;' is a bad idea if anyone desires the 'Robot' type to have its own prototype instance. Adding new Robot specific functions would also add it to person.Silviasilviculture
Instead of assign Person.prototype; to Robot.prototype, use: Object.create(Person.prototype)Affright
what is this Person.apply(this,arguments) doing exactly?Fairfax
@Sumit It's applying the Person's constructor function to the Robot's constructor function. It's an automated way to run one function's body in the context of the body of another function. You could replace Person.apply(this,arguments) with this.name = name; this.type = 'human'; and it would have the same effect...until you need to change Person, at which point, Robot won't automatically get changed to match. You'll have to remember to update Robot to match yourself.Noteworthy
This example is completely wrong. By doing that you alter the prototype of Person. That's not inheritance and you risk to put a huge mess in the Person class. See the answer that recommends using Object.create(). That is the correct way to do things.Evildoer
@user2491400 It isn't completely wrong. It'll do the basic job of extending the Person object. But more importantly, it's what works for IE <= 8. If you don't have any IE 6/7/8 users using your javascript, then definitely use the new and improved Object.create method.Noteworthy
@Noteworthy It is completely wrong as it does not extend the Person class. Extending a class involves at least creating a new prototype. Here if we want to add methods to Robot we can't do so without also modifying the prototype of Person. The only difference between Person and Robot is the constructor. And not having Object.create() is not an excuse as there existed class extension techniques long before Object.create() existed. The simple form is to do Robot.prototype = new Person();. This answer is a shame and it should be removed as it could mislead junior developers.Evildoer
@user2491400 You're right, but instead of removing it, @Banker should edit it to use Robot.prototype = new Person(); in place of their two lines with prototype. And maybe add a blurb about Object.create() in modern browsers for bonus points.Noteworthy
@Banker this answer has a high ranking in google's search. I would really suggest you fix the code and correct the prototype chain as suggested by other comments here.Eurhythmic
Maybe this doesn't look as pretty as Robot.prototype = new Person (note the lack of parentheses there; you should also instantiate without calling the constructor in this case if you want to avoid throwing errors from invalid constructor arguments), but I'd normally do something like Robot.prototype.__proto__ = Person.prototype. Not only does it result in the same Robot.prototype but it also saves a little bit of memory by not extraneously creating an unused instance of Person.Loudmouthed
If I omit the Robot.prototype.constructor = Robot; I still get a robot object with the correct output. Whats the use of the constructor here- it only serves to identify the "class", but does not change the creation behaviour?Sememe
I got fooled by this answer and indeed the first object extended is overwritten by the new one. Read answer from @Lior Elrom down below to prevent any unwanted side effect : Different approach: Object.createTsar
This is not called "extending" it's just copying the prototype. Any modifications in each prototype will affect all prototypes, so function overriding is not possible with modifying the prototype without a workaround.Loosing
Comments from user2491400 is deleted so please remove this Edit: Before using the code, please check the comments from user2491400 that reports about the side effects of simply assigning to prototypeStocking
Robot.prototype = Person.prototype and then Robot.prototype.constructor = Robot causes Person.prototype to be unintentionally mutated. Looks like a bug! Not sure why so many votes.Maturity
S
140

Simpler "prose-like" syntax with Object.create()

And the true prototypial nature of Javascript

*This example is updated for ES6 classes and TypeScript.

Firstly, Javascript is a prototypal language, not class-based. Its true nature is expressed in the prototypial form below, which you may come to see that is very simple, prose-like, yet powerful.

TLDR;

Javascript

const Person = { 
    name: 'Anonymous', // person has a name
    greet() { console.log(`Hi, I am ${this.name}.`) } 
} 
    
const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'
jack.greet()                         // outputs "Hi, I am Jack."

TypeScript

In TypeScript, you will need to set up interfaces, which will be extended as you create descendents of the Person prototype. A mutation politeGreet shows an example of attaching new method on the descendent jack.

interface IPerson extends Object {
    name: string
    greet(): void
}

const Person: IPerson =  {
    name:  'Anonymous',  
    greet() {
        console.log(`Hi, I am ${this.name}.`)
    }
}

interface IPolitePerson extends IPerson {
    politeGreet: (title: 'Sir' | 'Mdm') => void
}

const PolitePerson: IPolitePerson = Object.create(Person)
PolitePerson.politeGreet = function(title: string) {
    console.log(`Dear ${title}! I am ${this.name}.`)
}

const jack: IPolitePerson = Object.create(Person)
jack.name = 'Jack'
jack.politeGreet = function(title): void {
    console.log(`Dear ${title}! I am ${this.name}.`)
}

jack.greet()  // "Hi, I am Jack."
jack.politeGreet('Sir') // "Dear Sir, I am Jack."

This absolves the sometimes convoluted constructor pattern. A new object inherits from the old one, but is able to have its own properties. If we attempt to obtain a member from the new object (#greet()) which the new object jack lacks, the old object Person will supply the member.

In Douglas Crockford's words: "Objects inherit from objects. What could be more object-oriented than that?"

You don't need constructors, no new instantiation. You simply create Objects and then extend or morph them.

This pattern also offers immutability (partial or full), and getters/setters.

Clean and clear. It's simplicity does not compromise features. Read on.

Creating an descendant/copy of Person prototype (technically more correct than class).

*Note: Below examples are in JS. To write in Typescript, just follow the example above to set up interfaces for typing.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'
Skywalker.firstName = ''
Skywalker.type = 'human'
Skywalker.greet = function() { console.log(`Hi, my name is ${this.firstName} ${this.lastName} and I am a ${this.type}.`

const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true

If you feel less safe throwing away the constructors in-lieu of direct assignments, one common way is to attach a #create method:

Skywalker.create = function(firstName, gender, birthYear) {

    let skywalker = Object.create(Skywalker)

    Object.assign(skywalker, {
        firstName,
        birthYear,
        gender,
        lastName: 'Skywalker',
        type: 'human'
    })

    return skywalker
}

const anakin = Skywalker.create('Anakin', 'male', '442 BBY')

Branching the Person prototype to Robot

When you branch the Robot descendant from Person prototype, you won't affect Skywalker and anakin:

// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'

Attach methods unique to Robot

Robot.machineGreet = function() { 
    /*some function to convert strings to binary */ 
}

// Mutating the `Robot` object doesn't affect `Person` prototype and its descendants
anakin.machineGreet() // error

Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false

In TypeScript you would also need to extend the Person interface:

interface Robot extends Person {
    machineGreet(): void
}
const Robot: Robot = Object.create(Person)
Robot.machineGreet = function() { console.log(101010) }

And You Can Have Mixins -- Because.. is Darth Vader a human or robot?

const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.
Object.assign(darthVader, Robot)

Darth Vader gets the methods of Robot:

darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...

Along with other odd things:

console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.

Which elegantly reflects the "real-life" subjectivity:

"He's more machine now than man, twisted and evil." - Obi-Wan Kenobi

"I know there is good in you." - Luke Skywalker

Compare to the pre-ES6 "classical" equivalent:

function Person (firstName, lastName, birthYear, type) {
    this.firstName = firstName 
    this.lastName = lastName
    this.birthYear = birthYear
    this.type = type
}

// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }

function Skywalker(firstName, birthYear) {
    Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}

// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker

const anakin = new Skywalker('Anakin', '442 BBY')

// #isPrototypeOf won't work
Person.isPrototypeOf(anakin) // returns false
Skywalker.isPrototypeOf(anakin) // returns false

ES6 Classes

Clunkier compared to using Objects, but code readability is okay:

class Person {
    constructor(firstName, lastName, birthYear, type) {
        this.firstName = firstName 
        this.lastName = lastName
        this.birthYear = birthYear
        this.type = type
    }
    name() { return this.firstName + ' ' + this.lastName }
    greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}

class Skywalker extends Person {
    constructor(firstName, birthYear) {
        super(firstName, 'Skywalker', birthYear, 'human')
    }
}

const anakin = new Skywalker('Anakin', '442 BBY')

// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true

Further reading

Writability, Configurability and Free Getters and Setters!

For free getters and setters, or extra configuration, you can use Object.create()'s second argument a.k.a propertiesObject. It is also available in #Object.defineProperty, and #Object.defineProperties.

To illustrate its usefulness, suppose we want all Robot to be strictly made of metal (via writable: false), and standardise powerConsumption values (via getters and setters).


// Add interface for Typescript, omit for Javascript
interface Robot extends Person {
    madeOf: 'metal'
    powerConsumption: string
}

// add `: Robot` for TypeScript, omit for Javascript.
const Robot: Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,  // defaults to false. this assignment is redundant, and for verbosity only.
        configurable: false, // defaults to false. this assignment is redundant, and for verbosity only.
        enumerable: true  // defaults to false
    },
    // getters and setters
    powerConsumption: {
        get() { return this._powerConsumption },
        set(value) { 
            if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k') 
            this._powerConsumption = value
            throw new Error('Power consumption format not recognised.')
        }  
    }
})

// add `: Robot` for TypeScript, omit for Javascript.
const newRobot: Robot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

And all prototypes of Robot cannot be madeOf something else:

const polymerRobot = Object.create(Robot)
polymerRobot.madeOf = 'polymer'
console.log(polymerRobot.madeOf) // outputs 'metal'
Steamboat answered 2/2, 2015 at 16:8 Comment(18)
- Object.create doesn't exist in many (older) browser, notably Internet Explorer 8 and below. - Object.create() still calls the constructor of the function you pass through it. - For each property declaration, you'll have to configure the same settings over and over again (as you've shown in the example code). There is no real benefit over using Object.create instead of the new keyword.Wisdom
@Wisdom the real benefit comes when you try to explain to a 10 year old what the code does. Using this Object.create() method is much easier to comprehend than having constructors, re-pointing of prototypes or setting up classes.Steamboat
"classical-trained" programmers, what do you mean by that?Trituration
There is the "classical" way of doing things, and the "prototypial" way of doing things. See #19634262Steamboat
Possibly because it's STAR WARS, and you called it D2R2. Never f* up STAR WARS.Ungenerous
If I'm correct Robot.type = "robot" shadows the original Person.type. Also r2d2.name = 'R2D2' doesnt write to Person.name but creates new variable on object r2d2Ioneionesco
you are correct. When calling a property (say Robot.type), Javascript first tries to find whether it exist on the object (Robot), if not i will traverse as far up the prototype chain as it need to until it finds a defined property (Person.type), or when it reaches the base prototype (the very first one that copies are made out of -- Person).Steamboat
I come from a classical OOP mindset and this answer helped me a lot. Two questions on the code: 1) Is todays ES2015 Object.assign(Robot, {a:1} a good alternative for your extend() method? 2) How to override the greet() method so it returns the same text, but with " a greet override" appended?Waive
1) #Object.assign does looke like a good alternative. But browser support is lower atm. 2) You will use the __proto__ property of the object to access its prototype's greet function. then you call the prototype greet function with the callee's scope passed in. in this case the function was a console log, so it's not possible to "append". But with this example i think you get the drift. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }Steamboat
Object.create cannot be used to create a new instance of Map or Set, and JavaScript is not a classless language.Counterstamp
@TinyGiant you might want to give an example of why permitting "Object.create to create new instance of Map or Set" is so important.Steamboat
... because without new, you cant use map or set? I thought that was obvious.Counterstamp
@TinyGiant I see. I get what you mean now. But you ought you consider that map was introduced in 2015 because classical programmers want to make Javascript syntax familiar. For not because of the community it could have been Object.create(Map) instead of new Map(). I'm okay with it moving towards a hybrid by incorporating useful things in ways most familiar, but we shouldn't lose its intuitive style to the monster of classes and instantiation where there are no reasons to.Steamboat
Well that's a discussion that should be had with the ECMAScript Language Specification maintainers. I generally agree, but I have to work with what I have.Counterstamp
is it possible to extends multiple prototypes in one object?Magnetochemistry
@Magnetochemistry Can you give an example of what you are trying to achieve?Steamboat
I don't understand line let self = this in Robot.charge() function. I mean.... somewhere they call this., properties, somewhere self. and some properties without anything prepended....Malleolus
I admit that I usually get rid of the confusion in this scoping in such scenarios (calling another function from a function and passing it arguments which are properties of the function calling it), which eradicates problems of making the common mistake. In this particular scenario let self = this and passing self into Math.min is redundant.Steamboat
K
52

If you haven't yet figured out a way, use the associative property of JavaScript objects to add an extend function to the Object.prototype as shown below.

Object.prototype.extend = function(obj) {
   for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
         this[i] = obj[i];
      }
   }
};

You can then use this function as shown below.

var o = { member: "some member" };
var x = { extension: "some extension" };

o.extend(x);
Kyd answered 4/11, 2013 at 20:38 Comment(2)
Beware that this will create pointers to the original object in the 'child' class when using objects / arrays in the 'parent' class. To elaborate: If you have an object or array in your parent class, modifying it in a child class that extends on that base, will actually modify it for all child classes that extend on this same base class.Wisdom
Harold,Thanks for highlighting that fact. It is important for the whoever uses the function to incorporate a condition that checks for objects/arrays and makes copies of them.Kyd
F
48

In ES6, you may use spread operator like

var mergedObj = { ...Obj1, ...Obj2 };

Note that Object.assign() triggers setters whereas spread syntax doesn't.

For more info see link, MDN -Spread Syntax


Old Answer :

In ES6, there is Object.assign for copying property values. Use {} as first param if you don't want to modify the target object (the first param passed).

var mergedObj = Object.assign({}, Obj1, Obj2);

For more details see link, MDN - Object.assign()

In case if you need is a Polyfill for ES5, the link offers it too. :)

Franek answered 15/1, 2016 at 8:33 Comment(0)
A
32

Object.create (different approach)

Per @osahyoun's answer, I find the following to be a better and more efficient way to inherit from the Person's prototype object.

Consider the following:

function Person(name) {
  this.name = name;
  this.type = 'Human';
}

Person.prototype.info = function() {
  console.log(`Name: ${this.name}, Type: ${this.type}`);
}

function Robot(name) {
  Person.call(this, name)
  this.type = 'Robot';
}

/* Set Robot's prototype to Person's prototype by
   creating a new object that inherits from Person.prototype,
   and assigning it to Robot.prototype */
Robot.prototype = Object.create(Person.prototype);

// Set constructor back to Robot
Robot.prototype.constructor = Robot;

// Create new instances
var person = new Person("Bob");
var robot = new Robot("Boutros");

person.info(); // Name: Bob, Type: Human
robot.info();  // Name: Boutros, Type: Robot

Now, and this is important, by using Object.create:

Person.prototype.constructor !== Robot // true

Check also the MDN documentation.

Affright answered 4/8, 2014 at 16:42 Comment(4)
Just want to say @GaretClaborn it works correctly, but you're not passing the name parameter to the parent constructor, like this: jsfiddle.net/3brm0a7a/3 (difference is in line #8)Dallapiccola
@Dallapiccola Ah I see, thanks. I edited the answer to reflect that changeStpeter
@xPheRe, I guess I was more focus of proving a point when I added this solution. Thanks.Affright
Nice answer +1, you can take a look to ECMAScript 6. Keywords class and extends is available : developer.mozilla.org/en-US/docs/Web/JavaScript/…Shutdown
W
19

And another year later, I can tell you there is another nice answer.

If you don't like the way prototyping works in order to extend on objects/classes, take alook at this: https://github.com/haroldiedema/joii

Quick example code of possibilities (and many more):

var Person = Class({

    username: 'John',
    role: 'Employee',

    __construct: function(name, role) {
        this.username = name;
        this.role = role;
    },

    getNameAndRole: function() {
        return this.username + ' - ' + this.role;
    }

});

var Manager = Class({ extends: Person }, {

  __construct: function(name)
  {
      this.super('__construct', name, 'Manager');
  }

});

var m = new Manager('John');
console.log(m.getNameAndRole()); // Prints: "John - Manager"
Wisdom answered 22/1, 2014 at 15:9 Comment(4)
Well, I still have 2 months until the 2 years are up :P Either way, JOII 3.0 is about to release :)Wisdom
Make that 3 years later.Pyrrhotite
Interesting concept, but the syntax looks real ugly. You'd be better off waiting for ES6 classes to become stableGeist
I completely agree @sleepycal. But unfortunately, it'll be at least 5 more years before all major/common browsers have implemented this. So until that time, this'll have to do...Wisdom
C
17

People who are still struggling for the simple and best approach, you can use Spread Syntax for extending object.

var person1 = {
      name: "Blank",
      age: 22
    };

var person2 = {
      name: "Robo",
      age: 4,
      height: '6 feet'
    };
// spread syntax
let newObj = { ...person1, ...person2 };
console.log(newObj.height);

Note: Remember that, the property is farthest to the right will have the priority. In this example, person2 is at right side, so newObj will have name Robo in it.

Cassiterite answered 8/10, 2018 at 11:2 Comment(0)
T
8

You might want to consider using helper library like underscore.js, which has it's own implementation of extend().

And it's also a good way to learn by looking at it's source code. The annotated source code page is quite useful.

Touchandgo answered 3/5, 2012 at 12:45 Comment(1)
An example of how underscore.js's _.extend() works makes its functionality quite clear: lostechies.com/chrismissal/2012/10/05/…Hardwick
C
6

Mozilla 'announces' object extending from ECMAScript 6.0:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends

NOTE: This is an experimental technology, part of the ECMAScript 6 (Harmony) proposal.

class Square extends Polygon {
  constructor(length) {
    // Here, it calls the parent class' constructor with lengths
    // provided for the Polygon's width and height
    super(length, length);
    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.area = value;     } 
}

This technology is available in Gecko (Google Chrome / Firefox) - 03/2015 nightly builds.

Circumambient answered 9/4, 2015 at 11:30 Comment(0)
P
5

In the majority of project there are some implementation of object extending: underscore, jquery, lodash: extend.

There is also pure javascript implementation, that is a part of ECMAscript 6: Object.assign: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Psychopathist answered 14/3, 2015 at 18:26 Comment(2)
Doesn’t “pure javascript implementation” refer to something that is implemented with just JavaScript, not to an environment-provided function which might be implemented natively?Den
@binki, I meant native javascript implementation - part of the ECMAScript 2015 (ES6) standardPsychopathist
N
2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Then:

function Person() {
    this.name = "anonym"
    this.skills = ["abc"];
}
Person.prototype.profile = function() {
    return this.skills.length // 1
};

function Student() {} //well extends fom Person Class
Student.extends(Person)

var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

Update 01/2017:

Please, Ignore my answer of 2015 since Javascript is now supports extends keyword since ES6 (Ecmasctipt6 )

- ES6 :

class Person {
   constructor() {
     this.name = "anonym"
     this.skills = ["abc"];
   }

   profile() {
    return this.skills.length // 1
   }

}

Person.MAX_SKILLS = 10;
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

- ES7 :

class Person {
    static MAX_SKILLS = 10;
    name = "anonym"
    skills = ["abc"];

    profile() {
      return this.skills.length // 1
    }

}
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2
Nye answered 19/2, 2015 at 6:43 Comment(1)
By calling new ParentClass() before overwriting the constructor, you've already executed the parent constructor. I don't think thats correct behavior if you ask me...Wisdom
C
2

Summary:

Javascript uses a mechanism which is called prototypal inheritance. Prototypal inheritance is used when looking up a property on an object. When we are extending properties in javascript we are inheriting these properties from an actual object. It works in the following manner:

  1. When an object property is requested, (e.g myObj.foo or myObj['foo']) the JS engine will first look for that property on the object itself
  2. When this property isn't found on the object itself it will climb the prototype chain look at the prototype object. If this property is also not found here it will keep climbing the prototype chain until the property is found. If the property is not found it will throw a reference error.

When we want to extend from a object in javascript we can simply link this object in the prototype chain. There are numerous ways to achieve this, I will describe 2 commonly used methods.

Examples:

1. Object.create()

Object.create() is a function that takes an object as an argument and creates a new object. The object which was passed as an argument will be the prototype of the newly create object. For example:

// prototype of the dog
const dogPrototype = {
  woof: function () { console.log('woof'); }
}

// create 2 dog objects, pass prototype as an argument
const fluffy = Object.create(dogPrototype);
const notFluffy = Object.create(dogPrototype);

// both newly created object inherit the woof 
// function from the dogPrototype
fluffy.woof();
notFluffy.woof();

2. Explicitly setting the prototype property

When creating objects using constructor functions, we can set add properties to its prototype object property. Objects which are created form a constructor function when using the new keyword, have their prototype set to the prototype of the constructor function. For example:

// Constructor function object
function Dog (name) {
   name = this.name;
}

// Functions are just objects
// All functions have a prototype property
// When a function is used as a constructor (with the new keyword)
// The newly created object will have the consturctor function's
// prototype as its prototype property
Dog.prototype.woof = function () {
  console.log('woof');
}

// create a new dog instance
const fluffy = new Dog('fluffyGoodBoyyyyy');
// fluffy inherits the woof method
fluffy.woof();

// can check the prototype in the following manner
console.log(Object.getPrototypeOf(fluffy));
Caryloncaryn answered 3/10, 2018 at 17:39 Comment(0)
U
1
  • No need to use any external library to extend

  • In JavaScript, everything is an object (except for the three primitive datatypes, and even they are automatically wrapped with objects when needed). Furthermore, all objects are mutable.

Class Person in JavaScript

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    getName: function() {
        return this.name;
    },
    getAge: function() {
        return this.age;
    }
}

/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);

Modify a specific instance/object.

alice.displayGreeting = function() 
{
    alert(this.getGreeting());
}

Modify the class

Person.prototype.getGreeting = function() 
{
    return 'Hi ' + this.getName() + '!';
};

Or simply say : extend JSON and OBJECT both are same

var k = {
    name : 'jack',
    age : 30
}
 
k.gender = 'male'; /*object or json k got extended with new property gender*/

thanks to ross harmes , dustin diaz

Unhandled answered 20/4, 2016 at 14:24 Comment(0)
G
1

simple and readable solution is to use spread operator

...

for example:

const obj1 = {a: "a"} const obj2 = {b: "b"} const result = {...obj1, ..obj2,} console.log("result", result) // must be {a: "a", b: "b"}
Gradygrae answered 7/9, 2021 at 11:55 Comment(0)
B
0

You can simply do it by using:

Object.prototype.extend = function(object) {
  // loop through object 
  for (var i in object) {
    // check if the extended object has that property
    if (object.hasOwnProperty(i)) {
      // mow check if the child is also and object so we go through it recursively
      if (typeof this[i] == "object" && this.hasOwnProperty(i) && this[i] != null) {
        this[i].extend(object[i]);
      } else {
        this[i] = object[i];
      }
    }
  }
  return this;
};

update: I checked for this[i] != null since null is an object

Then use it like:

var options = {
      foo: 'bar',
      baz: 'dar'
    }

    var defaults = {
      foo: false,
      baz: 'car',
      nat: 0
    }

defaults.extend(options);

This well result in:

// defaults will now be
{
  foo: 'bar',
  baz: 'dar',
  nat: 0
}
Blackman answered 23/2, 2016 at 13:36 Comment(0)
T
-1

This will make extend your properties create a new Object with the object parameter prototypes without altering the passed object.

function extend(object) {
    if (object === null)
        throw TypeError;
    if (typeof object !== "object" && typeof object !== "function")
        throw TypeError;
    if (Object.create)
        return Object.create(object);
    function f() {}
    ;
    f.prototype = p;
    return new f();
}

But if you want to extend your Object without modifying it parameters, you can add extendProperty to your object.

var Person{
//some code
extend: extendProperty
}

//Enforce type checking an Error report as you wish
    function extendProperty(object) {
        if ((object !== null && (typeof object === "object" || typeof object === "function"))){
            for (var prop in object) {
                if (object.hasOwnProperty(prop))
                    this[prop] = object[prop];
            }
        }else{
            throw TypeError; //Not an object
        }
    }
Tenpin answered 19/1, 2018 at 10:18 Comment(0)
C
-2

While this work it is not 100% correct

// Parent
var Parent = function (name) {
  this.name = name;
  this.test = function () {
    console.log("parent test");
  }
  this.testOverride = function () {
    console.log("parent testOverride");
  }
}
// define a function extend
Parent.prototype.extend = function () {
  // parent properties to override or add
  var override = arguments[0];
  return function () {
    Parent.apply(this, arguments);
    // add and override properties
    Object.keys(override).forEach(el =>{
      this[el] = override[el];
    })
   }
}
// create a Child from the Parent and override
// the function "testOverride" and keep "test" unchanged
var Child = Parent.prototype.extend({
  y: 10,
  testOverride: function () { 
    console.log("child testOverride"); 
  }
});
// Create an object of type Parent
var p = new Parent("Parent");
// Create an object of type Child
var c = new Child("Child");
console.log(p.name);
// Parent
console.log(c.name);
// Child
p.test();
//parent test
p.testOverride();
//parent testOverride
c.test();
//parent test
c.testOverride();
//child testOverride
Crystallography answered 4/7, 2021 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.