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.

4

17 Answers

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 
17

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: function() { 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' 
18

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

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. :)

Different approach: Object.create

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

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, by using Object.create:

Person.prototype.constructor !== Robot 

Check also the MDN documentation.

4

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:

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" 
4

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.

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.

1

Mozilla 'announces' object extending from ECMAScript 6.0:

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.

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:

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 
1

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

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"} 

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 } 

PLEASE ADD REASON FOR DOWNVOTE

  • 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

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 } } 

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 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy