Розширення об’єкта в Javascript


164

В даний час я перетворююсь з 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(...);

Але я не знаю, як змусити цю систему працювати. Якщо це неможливо, покажіть мені ще одну альтернативу, яка поширює об’єкт.


повернути правду; але тому я прошу :)
Wituz

2
Я б запропонував пройти цей прекрасний навчальний посібник на MDN: - developer.mozilla.org/uk/…
Pranav

Якщо після прочитання цих приємних документів ви все ще цікавитесь extendфункцією, я створив приклад тут: jsfiddle.net/k9LRd
Codrin Eugeniu

2
Я б також запропонував не думати про це строго як про «перетворення з Java на JavaScript» і більше про «вивчення нової мови Javascript, що має синтаксис Java»
Toni Leigh

Відповіді:


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

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;" погана ідея, якщо хтось бажає, щоб тип "Робот" мав власний екземпляр прототипу. Додавання нових специфічних функцій робота також додасть їх людині.
Джеймс Вілкінс

20
Цей приклад абсолютно неправильний. Тим самим ви змінюєте прототип Особи. Це не спадщина, і ви ризикуєте поставити величезний безлад у класі Person. Дивіться відповідь, яка рекомендує використовувати Object.create (). Це правильний спосіб робити речі.
Ніколас-ван

6
@osahyoun ця відповідь має високий рейтинг у пошуку Google. Я б дуже радив вам виправити код і виправити прототип ланцюга, як це запропоновано іншими коментарями тут.
raphaëλ

101

Світ без "нового" ключового слова.

І простіший "прозовий" синтаксис з 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 (), який називається 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.

Що ж, чи Дарт Вейдер людина чи машина - це справді суб'єктивно:

"Він зараз більш машинний, ніж людина, скручений і злий". - Оби-Ван Кенобі

"Я знаю, що в тебе добре". - Люк Скайуокер

Додатково - трохи коротший синтаксис з # Object.assign

Ймовірно, цей візерунок скорочує ваш синтаксис. Але ES6 # Object.assign може скоротити ще трохи (Для використання полів заповнення у старих браузерах див. 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.
})

7
мати підсумок для невикористання функції конструктора.
nsmarks

1
"класично навчені" програмісти, що ви розумієте під цим?
Петра

1
Я походжу з класичного мислення OOP, і ця відповідь мені дуже допомогла. Два питання щодо коду: 1) Чи є сьогоднішня ES2015 Object.assign(Robot, {a:1}хорошою альтернативою для вашого extend()методу? 2) Як змінити greet()метод, щоб він повернув той самий текст, але з доданим "привітанням заміни"?
Баррі Стейс

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

18
Будьте уважні, що це створить покажчики на початковий об'єкт у класі "дочірня" при використанні об'єктів / масивів у "батьківському" класі. Для уточнення: Якщо у вас є об'єкт або масив у вашому батьківському класі, модифікуючи його в дочірньому класі, який поширюється на цій базі, він фактично модифікує його для всіх дочірніх класів, які поширюються на цей самий базовий клас.
Гарольд

Гарольд, Дякую, що підкреслив цей факт. Для того, хто використовує функцію, важливо включити умову, яка перевіряє об'єкти / масиви та робить їх копії.
tomilay

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. Клас ключових слів і розширення доступно: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Бенджамін Пойґнант

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"

Що ж, у мене ще два місяці, поки два роки не закінчуються: 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буде ім'я Робо .


8

Ви можете розглянути можливість використання помічникової бібліотеки на зразок underscore.js , для якої є її власна реалізаціяextend() .

І це також хороший спосіб вчитися, дивлячись на його вихідний код. Сторінка з анотованим вихідним кодом є досить корисною.


1
Приклад того, як роботи underscore.js _.extend()досить чітко пояснюють
Lemmings19

6

Mozilla 'оголошує' об'єкт, що поширюється на ECMAScript 6.0:

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

ПРИМІТКА. Це експериментальна технологія, що є частиною пропозиції ECMAScript 6 (Гармонія).

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, а не на функцію, що надається оточуючим середовищем, яка може бути реалізована спочатку?
binki

1
@binki, я мав на увазі реалізацію вбудованого JavaScript - частина стандарту ECMAScript 2015 (ES6)
Cezary Daniel Nowak

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

Створюючи об'єкти за допомогою функцій конструктора, ми можемо встановити додавання властивостей до його властивості прототипу об'єкта. Об'єкти, які створюються при конструюванні 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 все є об’єктом (за винятком трьох примітивних типів даних, і навіть вони автоматично обгортаються об'єктами, коли це потрібно). Крім того, всі об'єкти є змінними.

Особа класу в 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


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

-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
Аркайн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.