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

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


trueを返します。しかし、それが私が質問している理由です:)
Wituz

2
私はMDNにこの美しいtuutorial通過することをお勧め: - developer.mozilla.org/en/...
Pranav

これらの素敵なドキュメントを読んだ後もextend関数に興味があるなら、ここに例を設定しました:jsfiddle.net/k9LRd
Codrin Eugeniu

2
また、厳密に「JavaからJavaScriptに変換する」と考えるのではなく、「Javaに類似した構文を持つ新しい言語、Javascriptを学ぶ」と考えることもお勧めします
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
質問が1つあります。実行すると、Person()コンストラクターはどのように呼び出されますかnew Robot()?コンストラクタで行うのthis.name = name;ではなく、その基本クラスコンストラクタを呼び出す必要があるように思われますRobot()...
Alexis Wilke 14

21
@AlexisWilke:はい、あなたはを呼ぶべきPerson.apply(this, arguments);です また、のRobot.prototype = Object.create(Person.prototype);代わりに使用することをお勧めしますnew Person();
Felix Kling 2014

18
Felixが述べたように、「Robot.prototype = Person.prototype;」誰かが「ロボット」タイプに独自のプロトタイプインスタンスを持たせたい場合、これは悪い考えです。新しいロボット固有の機能を追加すると、それも人に追加されます。
James Wilkins

20
この例は完全に間違っています。そうすることで、Personのプロトタイプを変更します。それは継承ではなく、Personクラスに大きな混乱をもたらすリスクがあります。Object.create()の使用を推奨する回答を参照してください。それが正しい方法です。
nicolas-van 2014

6
@osahyounこの答えはグーグルの検索で高いランキングを持っています。ここで他のコメントで提案されているように、コードを修正してプロトタイプチェーンを修正することをお勧めします。
raphaëλ

102

「新しい」キーワードのない世界。

Object.create()を使用した、より単純な「proseのような」構文。

*この例は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

を作成する「デフォルト」の方法を提供する1つの方法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()の2番目の引数、つまり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を使用)-Anakin Skywalker

これがどこに向かっているのかを感じることができます...?

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はさらに短縮できます(古いブラウザーでポリフィルを使用するには、ES6のMDNを参照してください)。

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

8
コンストラクター関数を使用しないことへの賛成票があります。
nsmarks 2015年

1
「古典的な訓練を受けた」プログラマー、それはどういう意味ですか?
ペトラ

1
私は古典的なOOPの考え方から来ており、この答えは私に大いに役立ちました。コードに関する2つの質問:1)今日のES2015 Object.assign(Robot, {a:1}はあなたのextend()方法の良い代替案ですか?2)greet()メソッドをオーバーライドして同じテキストを返すが、「あいさつオーバーライド」を追加する方法は?
Barry Staes 16年

2
1)#Object.assign良い代替品のように見えます。しかし、ブラウザのサポートは低い気圧です。2)__proto__オブジェクトのプロパティを使用して、プロトタイプのgreet関数にアクセスします。その後、渡された呼び出し先のスコープを使用してプロトタイプgreet関数を呼び出します。この場合、関数はコンソールログなので、「追加」することはできません。しかし、この例では、ドリフトが発生すると思います。skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr 2016

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 2014年

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ああ、ありがとう。その変更を反映するように回答を編集しました
Garet Claborn 2016年

1
@xPheRe、私がこのソリューションを追加したとき、私はポイントを証明することにもっと焦点を合わせていたと思います。ありがとう。
Lior Elrom 2016年

1
ニースの答え+1は、あなたがECMAScriptの6キーワードクラスに見てみると拡張することができます提供されています:developer.mozilla.org/en-US/docs/Web/JavaScript/...
ベンジャミン・感動

26

ES6では、次のようなスプレッド演算子を使用できます。

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

Object.assign()はセッターをトリガーしますが、spread構文はトリガーしません。

詳細については、リンク、MDN-スプレッド構文を参照してください


古い答え:

ES6では、Object.assignプロパティ値をコピーするためのものがあります。{}ターゲットオブジェクト(最初に渡されるパラメーター)を変更しない場合は、最初のパラメーターとして使用します。

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

詳細については、リンク、MDN-Object.assign()を参照してください

ES5のポリフィルが必要な場合は、リンクからも提供されます。:)


18

そしてもう1年後、もう1つ良い答えがあると言えます。

オブジェクト/クラスを拡張するためにプロトタイピングが機能する方法が気に入らない場合は、これを見てください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がリリースされます:)
Harold

1
3年後にそれを作る。

興味深い概念ですが、構文は見苦しく見えます。ES6クラスが安定するのを待つほうがいいでしょう
スリーピーカル2015

@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は、が右側にあるため、その中にRobonewObjという名前が付けられます。



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)-2015年3月のナイトリービルドで利用できます。


4

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

ECMAscript 6の一部である純粋なjavascript実装もありますObject.assignhttps : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


「純粋なJavaScript実装」とは、ネイティブに実装される可能性のある環境提供の関数ではなく、JavaScriptのみで実装されたものを指しませんか?
binki 2015

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

2017年1月更新:

JavaScriptがサポートされるようになったので、2015年の私の回答は無視してください。 extendsES6キーワードを(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では、すべてがオブジェクトです(3つのプリミティブデータ型を除き、必要に応じて自動的にオブジェクトでラップされます)。さらに、すべてのオブジェクトは変更可能です。

JavaScriptのクラスPerson

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

ただし、パラメーターを変更せずにオブジェクトを拡張する場合は、extendPropertyをオブジェクトに追加できます。

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 2014

@HMR氏は、環境が提供するオブジェクトプロトタイプを拡張すると、脆弱なコードが生成され、将来のコアJavaScript言語機能と競合する可能性があると述べています。Objectのプロトタイプを拡張して有用なユーティリティ関数をすべてに追加すると、その関数の名前が将来のJavaScript関数と同じになる可能性があり、将来の実行時にコードが爆発する可能性があります。たとえば、インスタンスにrepeat()関数を追加しObjectて呼び出しString、JavaScriptランタイムをES6に更新したとします。
binki 2015

@binkiご協力ありがとうございます。「所有」していないクラスのプロトタイプを変更し、それによってカプセル化の参照を破壊することについて話している:developer.mozilla.org/en/docs/Web/JavaScript/…JSにはプライベート変数がないため、APIは実装メンバーを公開します、それは通常慣例によって解決されます(メンバー名をアンダースコアで始めます)。それがオペレーションの主な問題であるのか、構文が混乱し、多くの人がそれを理解していないのかはわかりません。
HMR 2015

@HMR、私は間違っているかもしれませんが、「しかしプロトタイプはかなり危険です」とは言語機能を悪用する可能性がある悪名高いプロトタイプフレームワークを指しますprototype
binki 2015

自分で作成していないオブジェクトを使用している場合、それらをプロトタイプとして使用することの副作用が常にわからないため、プロトタイピングは危険です。たとえば、このフィドルを見てください:jsfiddle.net/fo6r20rg
Arkain
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.