it-roy-ru.com

Расширение объекта в 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(...);

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

137
Wituz

Правка :
Перед использованием кода, пожалуйста, проверьте комментарии от 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
186
osahyoun

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

И более простой синтаксис с 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.'

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

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

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

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

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

** Обновление 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'

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

78
Calvintwr

Если вы еще не нашли способ, используйте ассоциативное свойство объектов 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);
51
tomilay

Другой подход: 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 документацию.

27
Lior Elrom

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

Если вам не нравится, как работает прототипирование для расширения объектов/классов, взгляните на это: 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"
18
Harold

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

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

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

MDN - Object.assign ()

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

12
KrIsHnA

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

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

8
250R

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.

6
Niek Vandael

Люди, которые все еще борются за простой и лучший подход, вы можете использовать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);

Примечание: Помните, что свойство, наиболее удаленное справа, будет иметь приоритет. В этом примере person2 находится справа, поэтому newObj будет иметь имя Robo .

5
Ali Shahbaz

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

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

3
Cezary Daniel Nowak
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
2
Abdennour TOUMI

ПОЖАЛУЙСТА, ДОБАВЬТЕ ПРИЧИНУ ДЛЯ СКАЧИВАНИЯ

  • Нет необходимости использовать какую-либо внешнюю библиотеку для расширения

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

Класс Person в 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*/

благодаря росс хармес, дастин диаз

0
vijay

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

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

обновление: Я проверил 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
}
0
Mustafa Dwekat

Резюме:

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

  1. Когда запрашивается свойство объекта (например, myObj.foo или myObj['foo']), механизм JS сначала будет искать это свойство в самом объекте
  2. Когда это свойство не найдено в самом объекте, оно поднимается по цепочке прототипов смотрит на объект-прототип. Если это свойство также не найдено здесь, оно будет продолжать подниматься по цепочке прототипов, пока свойство не будет найдено. Если свойство не найдено, оно выдаст ошибку ссылки.

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

Примеры:

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. Явная установка свойства прототипа

При создании объектов с использованием функций конструктора мы можем установить свойства add для его свойства объекта prototype. Созданные объекты формируют функцию конструктора при использовании ключевого слова 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));

0
Willem van der Veen