Object.create()、new Object()、{} の違い

通常、オブジェクトは必ずコード内で使用され、最も直接的なリテラル メソッドで作成されることが多いですが、最近ではJS の継承メソッドをvar obj = {}整理する、オブジェクトも作成できるようになりましたこれら3つの方法に違いはありますか?Object.create()new Object()

直接リテラルの作成

var objA = {};
objA.name = 'a';
objA.sayName = function() {
    console.log(`My name is ${this.name} !`);
}
// var objA = {
//     name: 'a',
//     sayName: function() {
//         console.log(`My name is ${this.name} !`);
//     }
// }
objA.sayName();
console.log(objA.__proto__ === Object.prototype); // true
console.log(objA instanceof Object); // true
复制代码

新しいキーワードの作成

var objB = new Object();
// var objB = Object();
objB.name = 'b';
objB.sayName = function() {
    console.log(`My name is ${this.name} !`);
}
objB.sayName();
console.log(objB.__proto__ === Object.prototype); // true
console.log(objB instanceof Object); // true
复制代码

JS のポインティング問題で、 new bindingについて話すときnew、オペレーターは実際に次の 4 つの手順を実行しました。

var obj = new Object(); // 创建一个空对象
obj.__proto__ = Object.prototype; // obj的__proto__指向构造函数Object的prototype
var result = Object.call(obj); // 把构造函数Object的this指向obj,并执行构造函数Object把结果赋值给result
if (typeof(result) === 'object') {
    objB = result; // 构造函数Object的执行结果是引用类型,就把这个引用类型的对象返回给objB
} else {
    objB = obj; // 构造函数Object的执行结果是值类型,就返回obj这个空对象给objB
}
复制代码

このような比較では、実際にはリテラルの作成と新しいキーワードの作成の間に違いはありません.作成された新しいオブジェクトはすべて__proto__それを指しますObject.prototypeが、リテラルの作成はより効率的であり、__proto__ポインターの割り当てと合計が少なくなりますthis.

Object.create()

Object.create()メソッドは、既存のオブジェクトを使用して新しいオブジェクトを作成し、新しく作成されたオブジェクトを提供します__proto__。 MDN

const person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};
const me = Object.create(person); // me.__proto__ === person
me.name = "Matthew"; // name属性被设置在新对象me上,而不是现有对象person上
me.isHuman = true; // 继承的属性可以被重写
me.printIntroduction(); // My name is Matthew. Am I human? true
复制代码

Object.create(proto[, propertiesObject])

  • proto必須パラメーターは、上記のコードの新しいオブジェクトのポインターなど、新しいオブジェクトmeのプロトタイプ オブジェクトですこのパラメーターが の場合、新しいオブジェクトは完全に空のオブジェクトであり、継承されたプロパティやメソッドなどがないことに注意してください__proto__personnullObject.prototypehasOwnProperty()、toString()
var a = Object.create(null);
console.dir(a); // {}
console.log(a.__proto__); // undefined
console.log(a.__proto__ === Object.prototype); // false
console.log(a instanceof Object); // false 没有继承`Object.prototype`上的任何属性和方法,所以原型链上不会出现Object
复制代码
  • propertiesObjectこれは、新しい object に追加する列挙可能なプロパティ (つまり、プロトタイプ オブジェクトではなく取得できるカスタム プロパティとメソッド) の記述子と対応hasOwnProperty()するプロパティ名を指定するオプションのパラメーターです。
var bb = Object.create(null, {
    a: {
        value: 2,
        writable: true,
        configurable: true
    }
});
console.dir(bb); // {a: 2}
console.log(bb.__proto__); // undefined
console.log(bb.__proto__ === Object.prototype); // false
console.log(bb instanceof Object); // false 没有继承`Object.prototype`上的任何属性和方法,所以原型链上不会出现Object

// ----------------------------------------------------------

var cc = Object.create({b: 1}, {
    a: {
        value: 3,
        writable: true,
        configurable: true
    }
});
console.log(cc); // {a: 3}
console.log(cc.hasOwnProperty('a'), cc.hasOwnProperty('b')); // true false 说明第二个参数设置的是新对象自身可枚举的属性
console.log(cc.__proto__); // {b: 1} 新对象cc的__proto__指向{b: 1}
console.log(cc.__proto__ === Object.protorype); // false
console.log(cc instanceof Object); // true cc是对象,原型链上肯定会出现Object
复制代码

Object.create()作成されたオブジェクトのプロトタイプは、渡されたオブジェクトを指します。リテラルやキーワードの作成とはnew異なります。

  • Object.create() を自分で実装する
Object.mycreate = function(proto, properties) {
    function F() {};
    F.prototype = proto;
    if(properties) {
        Object.defineProperties(F, properties);
    }
    return new F();
}
var hh = Object.mycreate({a: 11}, {mm: {value: 10}});
console.dir(hh);
复制代码

要約する

  • リテラルとキーワードnewによって作成されたオブジェクトはObjectインスタンスであり、プロトタイプは を指しObject.prototype、組み込みオブジェクトを継承しますObject
  • Object.create(arg, pro)作成されたオブジェクトのプロトタイプは、 に依存しますarg新しいオブジェクトは空のオブジェクトであり、プロトタイプを持たず、どのオブジェクトも継承しません。指定されたオブジェクトの場合、新しいオブジェクトのプロトタイプは指定されたオブジェクトを指し、指定されたオブジェクトargnullarg

復刻 2

数日前、プロトタイプで問題が発生しました。プロトタイプについてはまだ何か知っていると思っていましたが、よく調べてみると、プロトタイプについての理解がまだ幼すぎることがわかりました。

Object.create と new で
オブジェクトを作成する方法について、私が遭遇した 2 つの作成方法、Object.create と new で説明します。

var Base = function () {}
var o1 = new Base();
var o2 = Object.create(Base);
では、何が違うのでしょうか?
まず Object.create の実装に取り​​掛かりましょう

Object.create = function (o) {     var F = function () {};     F.prototype = o;     return new F(); };が見られます。Object.create は内部でオブジェクトを定義し、インポートされたオブジェクト/関数 o に F.prototype オブジェクトを割り当て、新しいオブジェクトを返します。




var o1 = new Base() のときの new の動作を見てください。

JavaScript が実際に実行するのは:
var o1 = new Object();
o1.[[Prototype]] = Base.prototype;
Base.call(o1);
新しいアプローチは、新しい obj オブジェクト o1 を作成し、__proto__ をo1 Base.prototype オブジェクトを指します。そして call を使用して環境を強制します。したがって、インスタンスの作成を実現します。

2 つのオブジェクトの印刷を見てみましょう。

同じようです。

元のコードを改善しましょう。

var Base = function () {     this.a = 2 } var o1 = new Base(); var o2 = Object.create(Base); console.log(o1.a); console.log(o2.a) ; 参照その Object.create は、元のオブジェクトのプロパティにアクセスできなくなります。では、プロトタイプを見てください。(prototo と __proto__ の関係を最初は理解していませんでした。この 2 つのメソッドの作成を理解するのに非常に苦労しました)。コードをもう一度改善します。








var Base = function () {     this.a = 2 } Base.prototype.a = 3; var o1 = new Base(); var o2 = Object.create(Base); console.log(o1.a); console. log(o2.a);最初は出力値が 2,3 だと思っていました。. . プロトタイプはまだ存在していると思いました。. それは本当に間違っていたことが判明しました。操作の結果を見てみましょう。







今でもそうです。

それでは写真でお話します。


(Fは作成後破棄)

上の図を読むと、Object.create によって構築された Base プロトタイプのプロパティでさえアクセスできない理由が理解できます。なぜなら、それはそのプロトタイプをまったく指していないからです。これは、__proto__ とプロトタイプの違いも説明しています。したがって、上記のプロトタイプで定義された a は、Base のプロトタイプ オブジェクトの単なる属性です。

もう一度見てください:

new キーワードは function で定義する必要があります。
Object.create は、関数とオブジェクトの両方を構築できることを意味します。
まとめ

new Object.create
コンストラクターを比較する 元のコンストラクター プロパティを保持する 元のコンストラクター プロパティを失う 元のコンストラクター プロパティを失う プロトタイプ
チェーン 元のコンストラクター プロトタイプ プロパティ 元のコンストラクター/(オブジェクト) 自体が
オブジェクト関数関数とオブジェクト
instanceof および isPrototypeOf
に作用し、オブジェクト インスタンスを作成して言うこれらのオブジェクトはプロトタイプ チェーンを介して接続されています。そのため、判断メカニズムが必要です。

function Foo(){     //... } Foo.prototype.ff = 2; var a = new Foo(); a instanceof Foo; //真のinstanceof は、a の [[Prototype]] 全体に Foo.prototype が含まれているかどうかを意味します物体。ただし、[[Prototype]] チェーンを介して 2 つのオブジェクト (a と b) が関連付けられているかどうかを判断したい場合、このメソッドはオブジェクト (a) と関数 (.prototype 参照を持つ Foo) しか実装できません。instanceof だけでは実現できません。





ここでは isPrototypeOf を使用します。

var a = {};
var b = Object.ceate(a);
1
2
b.isPrototypeOf(a);// a の [[Prototype]] に b が出現しているかどうかを判断します。

isPrototypeOf の実装を見てみましょう。

function isRelatedTo(o1,o2){     function F(){}     F.prototype = o2;     return o1 instanceof F; }上記の関数は、補助関数 F を構築することによってプロトタイプ オブジェクトを構築します。instanceof 比較の条件を達成するように。console.log(a.isPrototypeOf(b) === isRelatedTo(b,a));//真





constructor
たとえば、.constructor は、関数が宣言されたときのデフォルトの属性です。
まずは下のコードを見てみましょう。

function Foo(){ } console.log(Foo.prototype.constructor === Foo);//true var a = new Foo(); console.log(a.constructor === Foo);//trueは a .constructor === Foo は true です。これは、a が Foo の .constructor プロパティを指す .constructor を持っていることを意味します。しかし、それは無知または多くの誤操作が原因である可能性があり、.constructor ポイントが失われる可能性があります。次のように:





function Foo(){ } Foo.prototype = {} var a1 = new Foo(); console.log(a1.constructor === Foo);//false console.log(a1.constructor === Object);/ /true は、a1 に .constructor 属性がないことを確認できます。それが理由です。? a1 には .constructor プロパティがないため、[[prototype]] チェーンの Foo.prototype に委譲します。しかし、新しく作成された Foo.prototype には .constructor がないため、最上部の Object.prototype に到達するまで検索を続けます。次に、私のコードが信頼できるものであることを確実にするために、間違った操作や私たちの実行の影響を受けないようにします。






function Foo(){ } Foo.prototype = {} var a1 = new Foo(); Object.defineProperty(Foo.prototype, "constructor", {     enumerable: false,     writeable:true,     configureable: true,     value: Foo // .constructor が Foo を指すようにします})私が説明したいのは、.constructor を完全に信頼することはできないということです. 注意しないと、間違いを犯したり、原理を理解していないと、オブジェクトを変更してしまいます. ミスポイントは壊滅的に発生する可能性があるため、コンストラクターが「によって構築された」ことを意味すると考えるのは、コストのかかる誤解です。









したがって、.constructor は非常に信頼性が低く、安全でない参照であることがわかります。開発ではこれらの参照を使用しないようにしてください。使用する場合は、.constructor の欠落を避けるために、必ずプロトタイプを確認してください。
 

おすすめ

転載: blog.csdn.net/hmily43/article/details/124591760