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

164

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

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

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

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

Wituz
источник
вернуть истину; но вот почему я спрашиваю :)
Wituz
2
Я хотел бы предложить пройти этот прекрасный учебник по MDN: - developer.mozilla.org/en/…
Pranav
Если после прочтения этих хороших документов вам все еще интересно узнать о extendфункции, я привел
Codrin Eugeniu
2
я бы также предложил не думать об этом строго как о «преобразовании из Java в JavaScript», а скорее как о «изучении нового языка, Javascript, с синтаксисом, похожим на Java»
Тони Ли,

Ответы:

195

Вы хотите «наследовать» от объекта-прототипа 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.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
osahyoun
источник
4
У меня один вопрос: как вызывается Person()конструктор new Robot()? Мне кажется, что вы должны вызывать этот конструктор базового класса, а не делать это this.name = name;в Robot()конструкторе ...
Алексис Уилк
21
@AlexisWilke: Да, вы должны позвонить Person.apply(this, arguments);. Также было бы лучше использовать Robot.prototype = Object.create(Person.prototype);вместо new Person();.
Феликс Клинг
18
Как сказал Феликс, «Robot.prototype = Person.prototype;» плохая идея, если кто-то желает, чтобы тип «Robot» имел свой собственный экземпляр прототипа. Добавление новых специальных функций робота также добавит его в личность.
Джеймс Уилкинс
20
Этот пример совершенно неверен. Этим вы изменяете прототип Person. Это не наследство, и вы рискуете навести беспорядок в классе Person. Смотрите ответ, который рекомендует использовать Object.create (). Это правильный способ делать вещи.
Николас ван
6
@osahyoun этот ответ имеет высокий рейтинг в поиске Google. Я бы действительно предложил вам исправить код и исправить цепочку прототипов, как это было предложено другими комментариями здесь.
Raphaël
103

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

И более простой «прозаоподобный» синтаксис с Object.create ().

* Этот пример обновлен для классов ES6.

Прежде всего, помните, что Javascript - это прототип языка . Это не на основе класса. Следовательно, письмо в прототипной форме раскрывает его истинную природу и может быть очень простым, подобным прозе и мощным.

TLDR;

const Person = { name: 'Anonymous' } // person has a name

const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'

Нет, вам не нужны конструкторы, не нужно создавать newэкземпляры ( читайте, почему вы не должны их использоватьnew ), нет super, не смешно, смешно __construct. Вы просто создаете объекты, а затем расширяете или изменяете их.

( Если вы знаете о методах получения и установки, обратитесь к разделу «Дальнейшее чтение», чтобы узнать, как этот шаблон дает вам бесплатные методы получения и установки, как Javascript изначально предназначался, и насколько они мощны .)

Прозе-подобный синтаксис: Базовый прототип

const Person = {

   //attributes
   firstName : 'Anonymous', 
   lastName: 'Anonymous',
   birthYear  : 0,
   type : 'human',

   //methods
   name() { return this.firstName + ' ' + this.lastName },
   greet() {
       console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' )
   },
   age() {
      // age is a function of birth time.
   }
}

const person = Object.create(Person). // that's it!

На первый взгляд выглядит очень читабельно.

Расширение, создающее потомка Person

* Правильные условия есть prototypes, и их descendants. Нет classesи не нужно instances.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'

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

Один из способов обеспечить «по умолчанию» способ создания descendant, это присоединение #createметода:

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

Способы ниже имеют более низкую читаемость:

Сравните с «классическим» эквивалентом:

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

Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns false!

Читаемость кода с использованием «классического» стиля не так хороша.

ES6 Классы

Следует признать, что некоторые из этих проблем устранены классами ES6, но все же:

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

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

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

Прикрепите методы, уникальные для Robot

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

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

Проверка наследования

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

У вас уже есть все, что вам нужно! Нет конструкторов, нет экземпляров. Чистая, ясная проза.

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

Пишемость, конфигурируемость и бесплатные геттеры и сеттеры!

Для свободных методов получения и установки или для дополнительной настройки вы можете использовать второй аргумент Object.create () aka propertiesObject. Он также доступен в # Object.defineProperty и # Object.defineProperties .

Чтобы проиллюстрировать, насколько это мощно, предположим, что мы хотим, чтобы все Robotбыли строго сделаны из металла (через writable: false), и стандартизировали powerConsumptionзначения (через геттеры и сеттеры).

const Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    // getters and setters, how javascript had (naturally) intended.
    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.')
        }  
    }
})

const newRobot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

И все прототипы Robotне могут быть madeOfчем-то еще потому что writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Миксины (используя # Object.assign) - Анакин Скайуокер

Вы чувствуете, куда это идет ...?

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

Object.assign(darthVader, Robot)

Дарт Вейдер получает методы Robot:

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

Наряду с другими странными вещами:

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

Что ж, Дарт Вейдер - человек или машина, действительно субъективен:

«Теперь он больше машина, чем человек, извращенный и злой». - Оби-Ван Кеноби

«Я знаю, что в тебе есть добро». - Люк Скайуокер

Extra - немного более короткий синтаксис с # Object.assign

По всей вероятности, этот шаблон сокращает ваш синтаксис. Но ES6 # Object.assign может укоротить еще немного (о том, как polyfill использовать в старых браузерах, см. MDN на ES6 ).

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

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal"
    // for brevity, you can imagine a long list will save more code.
})
Calvintwr
источник
8
есть воздержание от использования функции конструктора.
nsmarks
1
«классические» программисты, что вы имеете в виду?
Петра
1
Я пришел из классического мышления ООП, и этот ответ мне очень помог. Два вопроса по коду: 1) Является ли сегодняшний ES2015 Object.assign(Robot, {a:1}хорошей альтернативой для вашего extend()метода? 2) Как переопределить greet()метод, чтобы он возвращал тот же текст, но с добавлением «greet override»?
Барри Стес
2
1) #Object.assignвыглядит как хорошая альтернатива. Но поддержка браузера ниже. 2) Вы будете использовать __proto__свойство объекта для доступа к функции приветствия его прототипа. затем вы вызываете функцию приветствия прототипа с переданной областью действия вызываемого. В этом случае функция была консольным журналом, поэтому «добавить» невозможно. Но с этим примером я думаю, что вы получите дрейф. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr
1
Что ж, это обсуждение, которое следует провести с сопровождающими Спецификации языка ECMAScript. Я в целом согласен, но я должен работать с тем, что у меня есть.
51

Если вы еще не нашли способ, используйте ассоциативное свойство объектов 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);
tomilay
источник
18
Помните, что это создаст указатели на исходный объект в классе 'child' при использовании объектов / массивов в классе 'parent'. Чтобы уточнить: если у вас есть объект или массив в родительском классе, его изменение в дочернем классе, который распространяется на эту базу, фактически изменит его для всех дочерних классов, которые расширяются в этом же базовом классе.
Гарольд
Гарольд, спасибо, что выдвинули на первый план этот факт. Для того, кто использует эту функцию, важно включить условие, которое проверяет объекты / массивы и делает их копии.
Томай
30

Другой подход: 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 .

Лиор Элром
источник
2
Просто хочу сказать, что @GaretClaborn работает правильно, но вы не передаете nameпараметр родительскому конструктору, например: jsfiddle.net/3brm0a7a/3 (разница в строке № 8)
xPheRe
1
@xPheRe Ах, понятно, спасибо. Я отредактировал ответ, чтобы отразить это изменение
Гарет Клаборн
1
@xPheRe, я думаю, что я больше сосредоточился на доказательстве момента, когда я добавил это решение. Спасибо.
Лиор Элром
1
Хороший ответ +1, вы можете взглянуть на ECMAScript 6. Доступны
классы ключевых слов и расширения
26

В ES6 вы можете использовать оператор распространения, как

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

Обратите внимание, что Object.assign () запускает сеттеры, а синтаксис распространения - нет.

Для получения дополнительной информации см. Ссылку, MDN-Распространенный синтаксис


Старый ответ:

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

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

Для более подробной информации смотрите ссылку, MDN - Object.assign ()

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

Кришна
источник
18

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

Если вам не нравится, как работает прототипирование для расширения объектов / классов, взгляните на это: 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"
Гарольд
источник
Ну, у меня еще есть 2 месяца, пока 2 года не истекут: P В любом случае, JOII 3.0 собирается выпустить :)
Гарольд
1
Сделайте это через 3 года.
Интересная концепция, но синтаксис выглядит очень некрасиво. Вам лучше подождать, пока классы ES6 станут стабильными
сонный
Я полностью согласен с @sleepycal. Но, к сожалению, пройдет не менее 5 лет, прежде чем все основные / распространенные браузеры реализуют это. Так что до этого времени это придется делать ...
Гарольд
12

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

Али Шахбаз
источник
8

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

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

250R
источник
1
Пример того, как работы underscore.js _.extend()делают его функционал достаточно ясным: lostechies.com/chrismissal/2012/10/05/…
Lemmings19
6

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.

Ниек Вандаэль
источник
4

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

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

Цезарь Даниил Новак
источник
Разве «чистая реализация javascript» не относится к чему-то, что реализовано только с помощью JavaScript, а не к функции, предоставляемой средой, которая может быть реализована изначально?
Бинки
1
@binki, я имел в виду собственную реализацию javascript - часть стандарта ECMAScript 2015 (ES6)
Цезарь Даниэль Новак
2
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
Абденнур ТУМИ
источник
1
Позвонив new ParentClass()перед перезаписью конструктора, вы уже выполнили родительский конструктор. Я не думаю, что это правильное поведение, если вы спросите меня ...
Гарольд
1

Резюме:

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

При создании объектов с использованием функций конструктора мы можем установить свойства 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

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

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

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

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

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

благодаря Россу Хармсу, Дастину Диасу

Виджей
источник
-1

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

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
        }
    }
Ndifreke
источник
-2

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

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

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

Виниций Даллаква
источник
9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.Что ты имеешь в виду? Использование цепочки прототипов в JavaScript может привести к ошибкам? Это все равно что сказать, что использование классов на Java может привести к ошибкам и не имеет никакого смысла.
HMR
@HMR говорит, что расширение предоставленных средой прототипов объектов приводит к хрупкому коду, который может конфликтовать с будущей базовой функцией языка JavaScript. Если вы добавите полезную служебную функцию ко всему, расширив Objectпрототип, ваша функция может иметь то же имя, что и будущая функция JavaScript, и заставить ваш код взорваться при запуске в будущем. Например, скажем, вы добавили repeat()функцию Objectи вызвали ее в Stringэкземплярах, а затем ваша среда выполнения JavaScript обновилась до ES6?
Бинки
@binki Спасибо за ваш вклад. Вы говорите об изменении прототипа классов, которые вам не «принадлежат» и тем самым нарушении ссылки на инкапсуляцию: developer.mozilla.org/en/docs/Web/JavaScript/… JS не имеет закрытых переменных, поэтому ваш API предоставляет членов реализации , это обычно решается соглашением (имя элемента начинается с подчеркивания). Не уверен, является ли это основной проблемой, с которой сталкивается опера, или что синтаксис сбивает с толку, и многие люди не понимают его.
HMR
@HMR, я могу ошибаться, но я думаю, что «но прототип довольно опасен» относится к печально известной среде прототипов, которая может злоупотреблять prototypeязыковой функцией .
Бинки
Прототипирование опасно, потому что если вы используете объекты, которые не создавали, вы не всегда знаете, какие побочные эффекты будут от использования их в качестве прототипов. Посмотрите на эту скрипку, например: jsfiddle.net/fo6r20rg
Аркейн