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

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

Я видел, как несколько человек в Интернете используют метод, называемый extend on object. Код будет выглядеть так:

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

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

4b9b3361

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

Оригинальный ответ:

Вы хотите "наследовать" от объекта прототипа 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
181
ответ дан 03 мая '12 в 14:55
источник

Мир без ключевого слова "новое".

И более простой синтаксис с Object.create().

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

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

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

Расширение базового прототипа

// create a `Robot` prototype by extending the `Person` prototype:
var 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 }

Еще один уровень глубже

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

var 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.'

Дальнейшее чтение

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

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

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

//you can do this
var 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) {
    var 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."

//you can also use Object.create() second argument a.k.a propertiesObject,
//which I find to be a little too lengthy. The only reason to use it over #assign is if you need more control over the values i.e writability/configurability etc...
var Robot = Object.create(Person, {
    madeOf: { 
        value: "metal",
        writable: true,
        configurable: true,
        enumerable: true
    },
    powerConsumption: {
        value: "5kWh",
        writable: true,
        configurable: true,
        enumerable: true   
    }
});

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

62
ответ дан 02 февр. '15 в 19:08
источник

Если вы еще не определили способ, используйте ассоциативное свойство объектов 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);
48
ответ дан 04 нояб. '13 в 23:38
источник

Разный подход: 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 prototype to Person prototype
Robot.prototype = Object.create(Person.prototype);

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

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

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

Теперь, используя Object.create, Person.prototype.constructor !== Robot

Также проверьте документацию MDN.

21
ответ дан 04 авг. '14 в 19:42
источник

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

Если вам не нравится, как работает прототипирование, чтобы расширить объекты/классы, сделайте следующее: 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"
17
ответ дан 22 янв. '14 в 18:09
источник

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

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

Подробнее см. ссылку,

MDN - Object.assign()

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

9
ответ дан 15 янв. '16 в 11:33
источник

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

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

7
ответ дан 03 мая '12 в 15:45
источник

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

5
ответ дан 09 апр. '15 в 14:30
источник

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

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

3
ответ дан 14 марта '15 в 21:26
источник
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

Обновление 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
3
ответ дан 19 февр. '15 в 9:43
источник

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

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: Я проверил для this[i] != null, так как null является объектом

Затем используйте его как:

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
}
1
ответ дан 23 февр. '16 в 16:36
источник
  • Нет необходимости использовать внешнюю библиотеку для расширения

  • В JavaScript все является объектом (за исключением трех примитивные типы данных, и даже они автоматически завернуты в объекты при необходимости). Кроме того, все объекты изменяемы.

Лицо класса в 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);

Изменить конкретный экземпляр/объект.

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

Изменить класс

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

Или просто скажите: расширение JSON и OBJECT одинаковы

var k = {
    name : 'jack',
    age : 30
}

k.gender = 'male'; /*object or json k got extended with new property gender*/

благодаря ross harmes, dustin diaz

0
ответ дан 20 апр. '16 в 17:24
источник

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

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

Здесь ссылка: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

-1
ответ дан 31 июля '14 в 0:23
источник