Расширение объекта в Javascript

В настоящее время я перехожу из Java в Javascript, и мне немного сложно понять, как расширять объекты так, как я хочу.

Я видел, как несколько человек в интернете использовали метод под названием «расширять объект». Код будет выглядеть так:

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

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

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

Кто-нибудь знает, как заставить это работать? Я слышал, что вам нужно написать

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

Но я не знаю, как заставить эту систему работать. Если это невозможно, пожалуйста, покажите мне другую альтернативу, которая расширяет объект.

Ответы на вопрос(16)

Люди, которые все еще борются за простой и лучший подход, вы можете использоватьSpread Syntax для расширения объекта.

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: Помните, что свойство, наиболее удаленное справа, будет иметь приоритет. В этом примереperson2 находится на правой стороне, такnewObj будет иметь имяRobo в этом.

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*/

Росс Хармс, Дастин Диаз

In ES6, естьObject.assign для копирования значений свойств. использование{} в качестве первого параметра, если вы не хотите изменять целевой объект (первый пройденный параметр).

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

Для более подробной информации смотрите ссылку,

MDN - Object.assign ()

В случае, если вам нужно этоPolyfill for ES5, ссылка предлагает это тоже. :)

Summary:

Javascript использует механизм, который называетсяprototypal inheritance, Прототип наследования используется при поиске свойства объекта. Когда мы расширяем свойства в javascript, мы наследуем эти свойства от реального объекта. Это работает следующим образом:

  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.

Когда мы хотим расшириться от объекта в javascript, мы можем просто связать этот объект в цепочке прототипов. Есть множество способов добиться этого, я опишу 2 наиболее часто используемых метода.

Examples:

1. Object.create()

Object.create() это функция, которая принимает объект в качестве аргумента и создает новый объект. Объект, который был передан в качестве аргумента, будет прототипом вновь создаваемого объекта. Например:

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

При создании объектов с использованием функций конструктора мы можем установить свойства add для его свойства объекта-прототипа. Созданные объекты формируют функцию конструктора при использованииnew ключевое слово, их прототип установлен в прототип функции конструктора. Например:

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

World without the "new" keyword.

And simpler syntax with Object.create().

Я в лагере, который считает, что Javascript должен пытаться жить без «нового». Это бесклассовый язык, ему не нужны конструкторы. Вы просто создаете объекты, а затем расширяете или изменяете их. Конечно, есть подводные камни, но это гораздо мощнее и проще:

// base `Person` prototype
const Person = {
   name : '',
   age  : 22,
   type : 'human',
   greet() {
       console.log('Hi, my name is ' + this.name + ' and I am a ' + this.type + '.' )
   }
}

// create an instance of `Person`:
const skywalker = Object.create(Person)
skywalker.name = 'Anakin Skywalker'
skywalker.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Extending the base prototype

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

// Robots speak in binaries, so we need a different greet function:
Robot.greet = function() { //some function to convert strings to binary }

One more level deeper

// create a new instance `Robot`
const Astromech = Object.create(Robot)
Astromech.variant = 'astromech'

const r2d2 = Object.create(Astromech)
r2d2.name = 'R2D2'
r2d2.greet() // '0000111010101011100111....'

// morphing the `Robot` object doesn't affect `Person` prototypes
skywalker.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Further reading

** Обновление 3 октября 18. Принять синтаксис ES6 и использоватьconst а такжеlet, Добавлен пример, чтобы показать, как сделать свойства неизменяемыми.

** Обновление 22 января 17. Включен ES6 Object.assign ().

Как видите, назначение требует нескольких операторов. В ES6 вы можете использовать метод #assign для сокращения назначений. (Для использования polyfill в старых браузерах см.MDN на ES6.)

//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"
Robot.powerConsumption_kW = 5

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal",
    powerConsumption_kWh: 5,
    fullCharge_kWh: 10,
    currentCharge_kWh: 5
})

//attach some methods unique to Robot prototype.
Robot.charge = function(kWh) {
    let self = this
    this.currentCharge_kWh = Math.min(self.fullCharge_kWh, self.currentCharge_kWh + kWh)
    var percentageCharged = this.currentCharge_kWh / this.fullCharge_kWh * 100
    console.log(this.name + (percentageCharged === 100) ? ' is fully charged.' : ' is ' + percentageCharged +'% charged.')
}

Robot.charge(5) // outputs "Robot is fully charged."

Вы также можете использовать второй аргумент Object.create () a.k.a propertiesObject, который я считаю слишком длинным. Единственная причина использовать его вместо #assign - если вам нужен больший контроль над значениями, т. Е. Возможность записи / конфигурирования и т. Д. Обратите внимание, какRobot строго должно быть все сделано из металла.

const Robot = Object.create(Person, {
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    powerConsumption: {
        value: "5kWh",
        writable: true,
        configurable: true,
        enumerable: true   
    }
})

И все прототипыRobot не может быть сделано из чего-то другого.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

console.log(polymerRobot.madeOf) // outputs 'metal'

В этом паттерне есть ошибки, которые могут сработать как «классические». программисты. Тем не менее, я нахожу этот шаблон гораздо более читабельным.

Different approach: Object.create

Согласно ответу @osahyoun, я считаю, что следующее - лучший и эффективный способ «наследовать»; от объекта-прототипа Person:

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;

Создайте новые экземпляры:

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

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

Теперь, используяObject.create:

Person.prototype.constructor !== Robot

Проверьте такжеMDN документация.

Это позволит расширить ваши свойства и создать новый объект с прототипами параметров объекта, не изменяя переданный объект.

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

Но если вы хотите расширить свой объект без изменения его параметров, вы можете добавить exteProperty к своему объекту.

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
        }
    }
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Затем:

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:

Пожалуйста, проигнорируйте мой ответ 2015 года, так как теперь Javascript поддерживаетextends ключевое слово с 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

Вы можете рассмотреть возможность использования вспомогательной библиотеки, напримерunderscore.js, у которого естьэто собственная реализацияextend().

И это также хороший способ изучения, взглянув на его исходный код.аннотированная страница исходного кода довольно полезно.

Если вы еще не нашли способ, используйте ассоциативное свойство объектов JavaScript, чтобы добавить функцию расширения кObject.prototype как показано ниже.

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

Затем вы можете использовать эту функцию, как показано ниже.

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

o.extend(x);

Вы можете просто сделать это, используя:

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

Тогда используйте это как:

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

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

defaults.extend(options);

Это хорошо приводит к:

// defaults will now be
{
  foo: 'bar',
  baz: 'dar',
  nat: 0
}

Edit:
Перед использованием кода, пожалуйста, проверьте комментарии от пользователя 2491400, в которых сообщается о побочных эффектах простого назначенияprototype.

Original answer:

Вы хотите "наследовать" от объекта-прототипа Person:

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.name = name;
  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

Mozilla "объявляет" объект, расширяющийся из ECMAScript 6.0:

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

ПРИМЕЧАНИЕ. Это экспериментальная технология, часть предложения ECMAScript 6 (Harmony).

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

Эта технология доступна в Gecko (Google Chrome / Firefox) - ночные сборки 03/2015.

В большинстве проектов есть некоторая реализация расширения объекта: подчеркивание, jquery, lodash:extend.

Существует также чистая реализация javascript, которая является частью ECMAscript 6:Object.assign: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Прототипирование - хороший способ, но иногда прототип довольно опасен и может привести к ошибкам. Я предпочитаю инкапсулировать это в базовый объект, как это делает Ember.js для Ember.Object.extend и Ember.Object.reopen. Это гораздо безопаснее в использовании.

Я создал суть с тем, как вы бы настроить что-тоsimilar к тому, что использует Ember.Object.

Вот ссылка:https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

И еще год спустя, я могу сказать вам, что есть еще один хороший ответ.

Если вам не нравится, как работает прототипирование для расширения объектов / классов, взгляните на это:https://github.com/haroldiedema/joii

Краткий пример кода возможностей (и многих других):

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"

Ваш ответ на вопрос