Memperluas Objek dalam Javascript

164

Saat ini saya mengubah dari Jawa ke Javascript, dan agak sulit bagi saya untuk mengetahui cara memperluas objek dengan cara yang saya inginkan.

Saya telah melihat beberapa orang di internet menggunakan metode yang disebut extended on object. Kode akan terlihat seperti ini:

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

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

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

Adakah yang tahu cara membuat ini bekerja? Saya pernah mendengar bahwa Anda perlu menulis

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

Tetapi saya tidak tahu bagaimana cara membuat sistem ini bekerja. Jika tidak memungkinkan, tolong tunjukkan saya alternatif lain yang memperluas objek.

Wituz
sumber
kembali benar; tapi itu sebabnya saya bertanya :)
Wituz
2
Saya akan menyarankan untuk pergi melalui peringatan indah ini di MDN: - developer.mozilla.org/en/…
Pranav
Jika setelah membaca dokumen yang bagus itu Anda masih penasaran tentang suatu extendfungsi, saya telah membuat contoh di sini: jsfiddle.net/k9LRd
Codrin Eugeniu
2
saya juga menyarankan untuk tidak memikirkannya secara ketat sebagai 'mentransformasikan dari Java ke JavaScript' dan lebih sebagai 'belajar bahasa baru, Javascript, yang memiliki sintaksis yang mirip dengan Java'
Toni Leigh

Jawaban:

195

Anda ingin 'mewarisi' dari objek prototipe Orang:

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
sumber
4
Saya punya satu pertanyaan: bagaimana Person()konstruktor dipanggil ketika Anda melakukannya new Robot()? Sepertinya saya bahwa Anda harus menelepon bahwa konstruktor kelas dasar bukannya melakukan this.name = name;di Robot()konstruktor ...
Alexis Wilke
21
@AlexisWilke: Ya, Anda harus menelepon Person.apply(this, arguments);. Ini juga akan lebih baik melakukan penggunaan Robot.prototype = Object.create(Person.prototype);bukan new Person();.
Felix Kling
18
Seperti yang dikatakan oleh Felix, 'Robot.prototype = Person.prototype;' adalah ide yang buruk jika ada yang menginginkan tipe 'Robot' untuk memiliki contoh prototipe sendiri. Menambahkan fungsi spesifik Robot baru juga akan menambahkannya ke orang.
James Wilkins
20
Contoh ini sepenuhnya salah. Dengan melakukan itu Anda mengubah prototipe Orang. Itu bukan warisan dan Anda berisiko membuat kekacauan besar di kelas Person. Lihat jawaban yang merekomendasikan menggunakan Object.create (). Itu adalah cara yang benar untuk melakukan sesuatu.
nicolas-van
6
@osahyoun jawaban ini memiliki peringkat tinggi dalam pencarian google. Saya benar-benar menyarankan Anda memperbaiki kode dan memperbaiki rantai prototipe seperti yang disarankan oleh komentar lain di sini.
raphaëλ
103

Dunia tanpa kata kunci "baru".

Dan sintaksis "prosa-seperti" yang lebih sederhana dengan Object.create ().

* Contoh ini diperbarui untuk kelas ES6.

Pertama, ingatlah bahwa Javascript adalah bahasa prototipe . Ini bukan berbasis kelas. Oleh karena itu, menulis dalam bentuk prototipe memperlihatkan sifat aslinya, dan bisa sangat sederhana, seperti prosa, dan kuat.

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'

Tidak, Anda tidak perlu konstruktor, tidak ada newInstansiasi ( baca mengapa Anda tidak boleh menggunakannew ), tidak super, tidak lucu lucu __construct. Anda cukup membuat Objek dan kemudian memperluas atau mengubah mereka.

( Jika Anda tahu tentang getter dan setter, lihat bagian "Bacaan lebih lanjut" untuk melihat bagaimana pola ini memberi Anda getter dan setter gratis dengan cara yang awalnya dimaksudkan untuk Javascript , dan seberapa kuat mereka .)

Sintaks yang mirip prosa: Protoype dasar

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!

Sekilas, terlihat sangat enak dibaca.

Extension, menciptakan keturunan Person

* Istilah yang benar adalah prototypes, dan mereka descendants. Tidak ada classes, dan tidak perlu 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

Salah satu cara untuk menyediakan cara "default" untuk menciptakan descendant, adalah dengan melampirkan #createmetode:

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

Cara di bawah ini memiliki keterbacaan yang lebih rendah:

Bandingkan dengan padanan "klasik":

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!

Keterbacaan kode menggunakan gaya "klasik" tidak begitu bagus.

Kelas ES6

Memang, beberapa masalah ini diberantas oleh kelas ES6, tetapi masih:

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

Percabangan prototipe dasar

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

Lampirkan metode yang unik untuk 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

Memeriksa warisan

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

Anda sudah mendapatkan semua yang Anda butuhkan! Tidak ada konstruktor, tidak ada Instansiasi. Prosa bersih, jelas.

Bacaan lebih lanjut

Ketelitian, Dapat Dikonfigurasi, dan Gratis Setter dan Setter!

Untuk getter dan setter gratis, atau konfigurasi tambahan, Anda dapat menggunakan argumen kedua Object.create () alias propertiesObject. Ini juga tersedia di # Object.defineProperty , dan # Object.defineProperties .

Untuk mengilustrasikan betapa kuatnya ini, misalkan kita ingin semua Robotterbuat dari logam (via writable: false), dan menstandarkan powerConsumptionnilai-nilai (via getter dan setter).

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

Dan semua prototipe Robottidak bisa menjadi madeOfsesuatu yang lain karena writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Mixins (menggunakan # Object.assign) - Anakin Skywalker

Bisakah Anda merasakan ke mana arahnya ...?

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

Object.assign(darthVader, Robot)

Darth Vader mendapatkan metode Robot:

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

Bersama dengan hal-hal aneh lainnya:

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

Ya, apakah Darth Vader adalah manusia atau mesin memang subjektif:

"Dia lebih mesin sekarang daripada manusia, bengkok dan jahat." - Obi-Wan Kenobi

"Aku tahu ada kebaikan di dalam dirimu." - Luke Skywalker

Extra - Sintaks sedikit lebih pendek dengan # Object.assign

Kemungkinan besar, pola ini mempersingkat sintaksis Anda. Tetapi ES6 # Object.assign dapat mempersingkat lebih banyak (Untuk polyfill untuk digunakan pada browser lama, lihat MDN pada 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
sumber
8
memiliki upvote untuk tidak menggunakan fungsi konstruktor.
nsmarks
1
programmer "terlatih klasik", apa yang Anda maksud dengan itu?
Petra
1
Saya berasal dari pola pikir OOP klasik dan jawaban ini banyak membantu saya. Dua pertanyaan pada kode: 1) Apakah ES2015 todays Object.assign(Robot, {a:1}adalah alternatif yang baik untuk extend()metode Anda ? 2) Bagaimana cara mengganti greet()metode sehingga mengembalikan teks yang sama, tetapi dengan "override ucapan" ditambahkan?
Barry Staes
2
1) #Object.assignmemang terlihat seperti alternatif yang baik. Tetapi dukungan browser lebih rendah. 2) Anda akan menggunakan __proto__properti objek untuk mengakses fungsi sambutan prototipe-nya. maka Anda memanggil fungsi sapaan prototipe dengan lingkup callee yang dimasukkan. dalam hal ini fungsinya adalah log konsol, jadi tidak mungkin untuk "menambahkan". Tetapi dengan contoh ini saya pikir Anda mengerti. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr
1
Nah itulah diskusi yang harus dilakukan dengan pengelola Spesifikasi Bahasa ECMAScript. Saya umumnya setuju, tetapi saya harus bekerja dengan apa yang saya miliki.
51

Jika Anda belum menemukan cara, gunakan properti asosiatif objek JavaScript untuk menambahkan fungsi perluasan ke Object.prototypeseperti yang ditunjukkan di bawah ini.

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

Anda kemudian dapat menggunakan fungsi ini seperti yang ditunjukkan di bawah ini.

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

o.extend(x);
tomilay
sumber
18
Berhati-hatilah karena ini akan membuat pointer ke objek asli di kelas 'child' saat menggunakan objek / array di kelas 'parent'. Untuk menguraikan: Jika Anda memiliki objek atau array di kelas induk Anda, memodifikasinya dalam kelas anak yang meluas pada basis itu, sebenarnya akan memodifikasinya untuk semua kelas anak yang diperluas pada kelas dasar yang sama ini.
Harold
Harold, Terima kasih telah menyoroti fakta itu. Penting bagi siapa pun yang menggunakan fungsi untuk menggabungkan kondisi yang memeriksa objek / array dan membuat salinannya.
tomilay
30

Pendekatan berbeda: Object.create

Per @osahyoun menjawab, saya menemukan yang berikut ini sebagai cara yang lebih baik dan efisien untuk 'mewarisi' dari objek prototipe 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;

Buat instance baru:

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

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

Sekarang, dengan menggunakan Object.create :

Person.prototype.constructor !== Robot

Periksa juga dokumentasi MDN .

Lior Elrom
sumber
2
Hanya ingin mengatakan @GaretClaborn berfungsi dengan benar, tetapi Anda tidak mengirimkan nameparameter ke konstruktor induk, seperti ini: jsfiddle.net/3brm0a7a/3 (perbedaan ada di baris # 8)
xPheRe
1
@ xPheRe Ah begitu, terima kasih. Saya mengedit jawaban untuk mencerminkan perubahan itu
Garet Claborn
1
@ xPheRe, saya kira saya lebih fokus membuktikan poin ketika saya menambahkan solusi ini. Terima kasih.
Lior Elrom
1
Jawaban yang bagus +1, Anda dapat melihat ke ECMAScript 6. Kelas kata kunci dan ekstensi tersedia: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Benjamin Poignant
26

Di ES6 , Anda dapat menggunakan spread operator like

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

Perhatikan bahwa Object.assign () memicu setter sedangkan sintaks penyebaran tidak.

Untuk info lebih lanjut, lihat tautan, Sintaksis Menyebar MDN


Jawaban lama:

Di ES6 , ada Object.assignuntuk menyalin nilai properti. Gunakan {}sebagai param pertama jika Anda tidak ingin memodifikasi objek target (param pertama berlalu).

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

Untuk detail lebih lanjut lihat tautan, MDN - Object.assign ()

Jika Anda membutuhkan Polyfill untuk ES5 , tautannya juga menawarkannya. :)

KrIsHnA
sumber
18

Dan setahun kemudian, saya bisa memberi tahu Anda ada jawaban yang bagus.

Jika Anda tidak menyukai cara kerja prototipe untuk memperluas objek / kelas, perhatikan hal ini: https://github.com/haroldiedema/joii

Contoh kode kemungkinan cepat (dan banyak lagi):

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"
Harold
sumber
Yah, saya masih punya 2 bulan sampai 2 tahun habis: P Either way, JOII 3.0 akan dirilis :)
Harold
1
Buat itu 3 tahun kemudian.
Konsep yang menarik, tetapi sintaksinya terlihat sangat jelek. Anda akan lebih baik menunggu kelas ES6 menjadi stabil
sleepycal
Saya sepenuhnya setuju @sleepycal. Tetapi sayangnya, itu akan menjadi setidaknya 5 tahun lagi sebelum semua browser utama / umum telah menerapkan ini. Jadi sampai saat itu, ini harus dilakukan ...
Harold
12

Orang-orang yang masih berjuang untuk pendekatan sederhana dan terbaik, dapat Anda gunakan Spread Syntaxuntuk memperluas objek.

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

Catatan: Ingatlah bahwa, properti yang paling jauh ke kanan akan mendapat prioritas. Dalam contoh ini, person2ada di sisi kanan, jadi newObjakan ada nama Robo di dalamnya.

Ali Shahbaz
sumber
6

Objek 'mengumumkan' Mozilla membentang dari ECMAScript 6.0:

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

CATATAN: Ini adalah teknologi eksperimental, bagian dari proposal 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;     } 
}

Teknologi ini tersedia di Gecko (Google Chrome / Firefox) - 03/2015 malam membangun.

Niek Vandael
sumber
4

Di sebagian besar proyek ada beberapa implementasi dari objek extending: garis bawah, jquery, lodash: memperpanjang .

Ada juga implementasi javascript murni, yang merupakan bagian dari ECMAscript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Cezary Daniel Nowak
sumber
Bukankah "implementasi javascript murni" mengacu pada sesuatu yang diimplementasikan hanya dengan JavaScript, bukan ke fungsi yang disediakan lingkungan yang mungkin diterapkan secara asli?
binki
1
@binki, maksud saya adalah implementasi javascript asli - bagian dari standar ECMAScript 2015 (ES6)
Cezary Daniel Nowak
2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Kemudian:

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

Pembaruan 01/2017:

Tolong, Abaikan jawaban saya tahun 2015 karena Javascript sekarang mendukung extendskata kunci sejak 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
Abdennour TOUMI
sumber
1
Dengan menelepon new ParentClass()sebelum menimpa konstruktor, Anda sudah mengeksekusi konstruktor induk. Saya tidak berpikir itu perilaku yang benar jika Anda bertanya kepada saya ...
Harold
1

Ringkasan:

Javascript menggunakan mekanisme yang disebut pewarisan prototypal . Warisan prototipe digunakan ketika mencari properti pada objek. Saat kami memperluas properti dalam javascript, kami mewarisi properti ini dari objek yang sebenarnya. Ini bekerja dengan cara berikut:

  1. Ketika properti objek diminta, (misalnya myObj.fooatau myObj['foo']) mesin JS pertama-tama akan mencari properti itu pada objek itu sendiri
  2. Ketika properti ini tidak ditemukan pada objek itu sendiri, ia akan memanjat rantai melihat prototipe objek prototipe. Jika properti ini juga tidak ditemukan di sini, ia akan terus memanjat rantai prototipe sampai properti ditemukan. Jika properti tidak ditemukan maka akan menimbulkan kesalahan referensi.

Ketika kita ingin memperluas dari suatu objek dalam javascript kita cukup menautkan objek ini dalam rantai prototipe. Ada banyak cara untuk mencapai ini, saya akan menjelaskan 2 metode yang umum digunakan.

Contoh:

1. Object.create()

Object.create()adalah fungsi yang mengambil objek sebagai argumen dan membuat objek baru. Objek yang dilewatkan sebagai argumen akan menjadi prototipe objek yang baru dibuat. Sebagai contoh:

// 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. Secara eksplisit mengatur properti prototipe

Saat membuat objek menggunakan fungsi konstruktor, kita dapat mengatur properti tambah ke properti objek prototipe. Objek yang dibuat membentuk fungsi konstruktor saat menggunakan newkata kunci, mengatur prototipe ke prototipe fungsi konstruktor. Sebagai contoh:

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

Willem van der Veen
sumber
0

Anda cukup melakukannya dengan menggunakan:

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

pembaruan: Saya memeriksa this[i] != nullkarena nullmerupakan objek

Kemudian gunakan seperti:

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

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

defaults.extend(options);

Ini juga menghasilkan:

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

TOLONG TAMBAH ALASAN UNTUK DOWNVOTE

  • Tidak perlu menggunakan perpustakaan eksternal untuk memperluas

  • Dalam JavaScript, semuanya adalah objek (kecuali untuk tiga tipe data primitif, dan bahkan mereka secara otomatis dibungkus dengan objek saat diperlukan). Selanjutnya, semua objek bisa berubah.

Orang Kelas dalam 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);

Ubah instance / objek tertentu .

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

Ubah kelas

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

Atau cukup katakan: memperpanjang JSON dan OBJECT keduanya sama

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

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

terima kasih untuk kerusakan ross, dustin diaz

vijay
sumber
-1

Ini akan membuat memperluas properti Anda membuat Objek baru dengan prototipe parameter objek tanpa mengubah objek yang dikirimkan.

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

Tetapi jika Anda ingin memperluas Objek Anda tanpa memodifikasi parameternya, Anda dapat menambahkan extendedProperty ke objek Anda.

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
sumber
-2

Prototyping adalah cara yang baik, tetapi prototipe kadang-kadang cukup berbahaya dan dapat menyebabkan bug. Saya lebih suka merangkum ini menjadi objek dasar, seperti yang dilakukan Ember.js untuk itu Ember.Object.extend dan Ember.Object.reopen. Itu jauh lebih aman untuk digunakan.

Saya membuat inti dengan bagaimana Anda akan mengatur sesuatu yang mirip dengan apa yang digunakan Ember.Object.

Inilah tautannya: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

Vinicius Dallacqua
sumber
9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.Bagaimana apanya? Menggunakan rantai prototipe dalam JavaScript dapat menyebabkan bug? Ini seperti mengatakan bahwa menggunakan kelas di Java dapat menyebabkan bug dan sama sekali tidak masuk akal.
HMR
@HMR dia mengatakan bahwa memperluas prototipe objek yang disediakan lingkungan menghasilkan kode rapuh yang mungkin bertentangan dengan fitur bahasa inti JavaScript di masa depan. Jika Anda menambahkan fungsi utilitas yang berguna untuk semuanya dengan memperluas Objectprototipe, fungsi Anda mungkin memiliki nama yang sama dengan fungsi JavaScript di masa depan dan menyebabkan kode Anda meledak saat dijalankan di masa depan. Misalnya, Anda menambahkan repeat()fungsi ke Objectdan memanggilnya di Stringinstance dan kemudian runtime JavaScript Anda diperbarui ke ES6?
binki
@binki Terima kasih atas masukan Anda. Anda berbicara tentang mengubah prototipe kelas yang tidak Anda "miliki" dan dengan demikian melanggar referensi inkapsulasi: developer.mozilla.org/en/docs/Web/JavaScript/... JS tidak memiliki variabel pribadi sehingga API Anda mengekspos anggota implementasi , yang biasanya diselesaikan dengan konvensi (mulai nama anggota dengan garis bawah). Tidak yakin apakah itu adalah masalah utama yang dimiliki op atau sintaksisnya membingungkan dan banyak orang tidak memahaminya.
HMR
@HMR, saya mungkin salah, tapi saya pikir "tetapi prototipe cukup berbahaya" mengacu pada kerangka prototipe terkenal yang mungkin menyalahgunakan prototypefitur bahasa .
binki
Prototipe berbahaya karena jika Anda menggunakan objek yang tidak Anda buat, Anda tidak selalu tahu apa efek samping dari menggunakannya sebagai prototipe. Lihatlah biola ini misalnya: jsfiddle.net/fo6r20rg
Arkain