web-dev-qa-db-ja.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(...);

しかし、私はこのシステムを動かす方法を知りません。それが不可能な場合は、オブジェクトを拡張する別の方法を教えてください。

140
Wituz

編集
コードを使用する前に、単にprototypeに代入することの副作用について報告しているuser2491400からのコメントを確認してください。

元の回答:

あなたは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
188
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 }

もう1レベル深い

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

参考文献

** 10月3日の更新18。ES6の構文とconstname__およびletname__の使用を採用しました。プロパティを不変にする方法を示す例を追加しました。

** 1月22日更新の17日ES6 Object.assign()を追加。

ご覧のとおり、割り当てには複数のステートメントが必要です。 ES6では、#assignメソッドを使用して割り当てを短縮できます。 (古いブラウザでpolyfillを使用するには、 ES6のMDN を参照してください。)

//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()の2番目の引数a.k.a propertiesObjectを使用することもできます。これは少し長すぎます。 #assignでこれを使用する唯一の理由は、値をもっと細かく制御する必要がある場合、つまり書き込み可能性/設定可能性などです。Robotname__がすべて金属製であることに注意してください。

const Robot = Object.create(Person, {
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    powerConsumption: {
        value: "5kWh",
        writable: true,
        configurable: true,
        enumerable: true   
    }
})

そしてRobotname__のすべてのプロトタイプは他のもので作ることはできません。

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

「古典的な訓練を受けた」プログラマーを旅行する可能性が高いこのパターンへの落とし穴があります。それにもかかわらず、私はこのパターンがとても読みやすいと思います。

80
Calvintwr

まだ方法がわからない場合は、JavaScriptオブジェクトのassociativeプロパティを使用して、次に示すようにObject.prototypeにextend関数を追加してください。

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 のドキュメントも確認してください。

28
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()

あなたが必要な場合ES5のためのPolyfill、リンクもそれを提供しています。 :)

13
KrIsHnA

あなたは nderscore.js のようなヘルパーライブラリを使うことを考えたいかもしれません---それは それはextend() のそれ自身の実装です。

そして、それはそのソースコードを見ることによって学ぶための良い方法でもあります。 注釈付きソースコードページ はとても便利です。

8
250R

シンプルでベストなアプローチにまだ苦労している人は、オブジェクトを拡張するために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が入ります。

7
Ali Shahbaz

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) - 2015年3月3日ビルドで利用できます。

6
Niek Vandael

プロジェクトの大部分では、オブジェクト拡張の実装がいくつかあります。アンダースコア、jquery、lodash:extendです。

純粋なJavaScriptの実装もあります。これはECMAscript 6の一部です。Object.assignhttps://developer.mozilla.org/en-US/docs)/Web/JavaScript /リファレンス/ Global_Objects/Object/assign

3
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を更新:

JavascriptがES6からextendsキーワードをサポートするようになったため、2015年の回答は無視してください(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はプロトタイプ継承というメカニズムを使用しています。プロトタイプ継承は、オブジェクトのプロパティを検索するときに使用されます。 JavaScriptでプロパティを拡張するときには、実際のオブジェクトからこれらのプロパティを継承しています。これは次のように機能します。

  1. オブジェクトプロパティが要求されると(例えば、myObj.foomyObj['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プロパティを設定できます。 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));
1

ダウンロードの理由を追加してください

  • 拡張するために外部ライブラリを使用する必要はありません

  • JavaScriptでは、すべてがオブジェクトです(3つのプリミティブデータ型を除き、さらに必要に応じて自動的にオブジェクトでラップされます)。さらに、すべてのオブジェクトは変更可能です。

JavaScriptのクラス人

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    getName: function() {
        return this.name;
    },
    getAge: function() {
        return this.age;
    }
}

/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);

特定のインスタンス/オブジェクトを変更する

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

クラスを修正する

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

あるいは単に言う:拡張JSONとOBJECTは同じである

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

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

ross harmesのおかげで、dustin diaz

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

pdate:nullはオブジェクトなのでthis[i] != 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