The difference between Object.create(), new Object() and {}

Normally, objects are definitely used in the code, and are usually created by the most direct literal method . Recently, when var obj = {}sorting out JS inheritance methodsObject.create() , objects can also be created. In addition, they can also be new Object()created with keywords. Is there any difference between these three methods?

direct literal creation

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
复制代码

new keyword creation

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
复制代码

In the pointing problem of JS, when talking about new bindingnew , the operator actually did the following four steps:

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
}
复制代码

In such a comparison, there is actually no difference between literal creation and new keyword creation. The new objects created all __proto__point to it Object.prototype, but literal creation is more efficient, and there are fewer __proto__pointer assignments and sums this.

Object.create()

Object.create()method creates a new object, using an existing object to supply the newly created object __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])

  • protoThe required parameter is the prototype object of the new object, such as the pointer meof the new object in the above code . Note that if this parameter is , then the new object is completely an empty object, without any inherited properties and methods, such as etc.__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
复制代码
  • propertiesObjecthasOwnProperty()It is an optional parameter that specifies the descriptor and corresponding property name of the enumerable property (that is, its custom properties and methods, which can be obtained, not on the prototype object) to be added to the new object.
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()The prototype of the created object points to the passed in object. newIt is different from literal and keyword creation.

  • Implement an Object.create() yourself
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);
复制代码

Summarize

  • newObjects created by literals and keywords are Objectinstances, prototypes point to Object.prototype, and inherit built-in objectsObject
  • Object.create(arg, pro)The prototype of the created object depends on arg, argfor null, the new object is an empty object, has no prototype, and does not inherit any object; argfor the specified object, the prototype of the new object points to the specified object, and inherits the specified object

reprint 2

A few days ago, I encountered a problem with the prototype. I used to think that I still knew something about prototypes, but after careful study, I found that my understanding of prototypes was still too young.

The way Object.create and new
create objects, I will illustrate with the two creation methods I encountered, Object.create and new

var Base = function () {}
var o1 = new Base();
var o2 = Object.create(Base);
So what's the difference?
Let me first come to the implementation of Object.create

Object.create = function (o) {     var F = function () {};     F.prototype = o;     return new F(); }; can be seen. Object.create defines an object internally, assigns the F.prototype object to the imported object/function o, and returns a new object.




Look at what new does when var o1 = new Base().

What JavaScript actually executes is:
var o1 = new Object();
o1.[[Prototype]] = Base.prototype;
Base.call(o1);
The new approach is to create a new obj object o1, and let the __proto__ of o1 Points to the Base.prototype object. And use call to force the environment. Thus realizing the creation of the instance.

Let's take a look at the printing of two objects.

Seems to be the same.

Let's improve the original code.

var Base = function () {     this.a = 2 } var o1 = new Base(); var o2 = Object.create(Base); console.log(o1.a); console.log(o2.a) ; See that Object.create loses access to the properties of the original object. Then look at the prototype? (I didn't understand the relationship between prototype and __proto__ at the beginning. It made it very difficult to understand the creation of these two methods). Improve the code again.








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); I initially thought that the output value is 2,3. . . Thought the prototype still exists. . Turns out it was really wrong. Let's see the results of the operation.







It is still the case.

Then we will speak with pictures.


(F is destroyed after creation)

After reading the above picture, we can understand why even the properties on the Base prototype constructed by Object.create cannot be accessed, because it does not point to its prototype at all. This also explains the difference between __proto__ and prototype. So the a defined in the prototype above is just an attribute on the prototype object of Base.

Look at it again:

The new keyword must be defined with function.
Object.create means that both function and object can be constructed.
summary

Compare new Object.create
constructor retain original constructor properties lost original constructor properties prototype
chain original constructor prototype properties original constructor/(object) itself
act on object function function and object
instanceof and isPrototypeOf
write to create an object instance and say In order to complete the connection between these objects through the prototype chain, but how do you know that it must contain it? So we need a judgment mechanism.

function Foo(){     //... } Foo.prototype.ff = 2; var a = new Foo(); a instanceof Foo; //true instanceof means whether the entire [[Prototype]] of a contains Foo.prototype object. But this method can only implement objects (a) and functions (Foo with .prototype reference), if you want to judge whether two objects (a and b) are associated through the [[Prototype]] chain. It cannot be achieved with only instanceof.





So isPrototypeOf is used here.

var a = {};
var b = Object.ceate(a);
1
2
b.isPrototypeOf(a);//Judge whether b has appeared in [[Prototype]] of a.

Let's take a look at the implementation of isPrototypeOf.

function isRelatedTo(o1,o2){     function F(){}     F.prototype = o2;     return o1 instanceof F; } The above function constructs a prototype object by constructing an auxiliary function F. So as to achieve the condition of instanceof comparison. console.log(a.isPrototypeOf(b) === isRelatedTo(b,a));//true





constructor
For example, .constructor is the default attribute when a function is declared.
Let's take a look at the code below first.

function Foo(){ } console.log(Foo.prototype.constructor === Foo);//true var a = new Foo(); console.log(a.constructor === Foo);//true looks a.constructor === Foo is true, meaning that a does have a .constructor pointing to Foo's .constructor property. But it may be due to ignorance, or a lot of misoperations, which will lead to the loss of our .constructor point. as follows:





function Foo(){ } Foo.prototype = {} var a1 = new Foo(); console.log(a1.constructor === Foo);//false console.log(a1.constructor === Object);/ /true can see that a1 does not have the .constructor attribute. That's why. ? Since a1 does not have a .constructor property, it will delegate to Foo.prototype on the [[prototype]] chain. But the newly created Foo.prototype does not have a .constructor, so continue to search until you reach the Object.prototype at the top. Next, in order to absolutely ensure that my code is reliable, it will not be affected by some wrong operations and our execution.






function Foo(){ } Foo.prototype = {} var a1 = new Foo(); Object.defineProperty(Foo.prototype, "constructor", {     enumerable: false,     writeable:true,     configureable: true,     value: Foo // Let .constructor point to Foo }) What I want to explain is that we can't fully trust .constructor. If we are not careful, we will change the object if we make a mistake or don't understand the principle. Mispointing can happen catastrophically, so thinking that constructor means "constructed by" is a costly misunderstanding.









So it can be seen that .constructor is a very unreliable and unsafe reference. Try to avoid using these references in development. If used, please remember to check your prototype to avoid missing .constructor.
 

Guess you like

Origin blog.csdn.net/hmily43/article/details/124591760