Related methods of Object object
JavaScript Object
provides many related methods on objects to deal with related operations of object-oriented programming. This chapter describes these methods.
Object.getPrototypeOf()
Object.getPrototypeOf
The method returns the prototype of the parameter object. This is the standard way of getting a prototype object.
var F = function () {}; var f = new F(); Object.getPrototypeOf(f) === F.prototype // true
In the above code, f
the prototype of the instance object is F.prototype
.
The following are prototypes for several special objects.
// The prototype of an empty object is Object.prototype Object.getPrototypeOf({}) === Object.prototype // true // The prototype of Object.prototype is null Object.getPrototypeOf(Object.prototype) === null // true // The prototype of the function is Function.prototype function f() {} Object.getPrototypeOf(f) === Function.prototype // true
Object.setPrototypeOf()
Object.setPrototypeOf
The method sets the prototype for the parameter object and returns the parameter object. It takes two parameters, the first is the existing object and the second is the prototype object.
var a = {}; var b = {x: 1}; Object.setPrototypeOf(a, b); Object.getPrototypeOf(a) === b // true a.x // 1
In the above code, Object.setPrototypeOf
the method sets a
the prototype of the object as an object b
, so a
it can share b
properties.
new
Commands can be Object.setPrototypeOf
mocked using methods.
var F = function () { this.foo = 'bar'; }; var f = new F(); // Equivalent to var f = Object.setPrototypeOf({}, F.prototype); F.call(f);
In the above code, new
the command to create a new instance object can actually be divided into two steps. The first step is to set the prototype of an empty object as a property of the constructor prototype
(in the above example F.prototype
); the second step is to bind the empty object inside the constructor this
, and then execute the constructor so that this
the methods and properties defined above (The above example is this.foo
), are transferred to this empty object.
Object.create()
A common way to generate an instance object is to use new
a command to have the constructor return an instance. But in many cases, only one instance object can be obtained, which may not be generated by the constructor at all, so can another instance object be generated from one instance object?
JavaScript provides Object.create()
methods to meet this need. This method accepts an object as a parameter, and then uses it as a prototype to return an instance object. The instance fully inherits the properties of the prototype object.
// prototype object var A = { print: function () { console.log('hello'); } }; // instance object var B = Object.create(A); Object.getPrototypeOf(B) === A // true B.print() // hello B.print === A.print // true
In the above code, Object.create()
the method takes A
the object as the prototype and generates B
the object. All properties and methods B
are inherited .A
Actually, Object.create()
the method can be replaced with the code below.
if (typeof Object.create !== 'function') { Object.create = function (obj) { function F() {} F.prototype = obj; return new F(); }; }
The above code shows that Object.create()
the essence of the method is to create an empty constructor F
, then let F.prototype
the attribute point to the parameter object obj
, and finally return an F
instance, so as to realize obj
the attribute that the instance inherits.
The new objects generated by the following three methods are equivalent.
var obj1 = Object.create({}); var obj2 = Object.create(Object.prototype); var obj3 = new Object();
If you want to generate an object that does not inherit any properties (such as no toString()
and methods), you can set the parameter to .valueOf()
Object.create()
null
var obj = Object.create(null); obj.valueOf() // TypeError: Object [object Object] has no method 'valueOf'
In the above code, obj
the prototype of the object is null
that it does not have some Object.prototype
properties defined on the object, such as valueOf()
methods.
When using Object.create()
a method, the object prototype must be provided, that is, the parameter cannot be empty or not an object, otherwise an error will be reported.
Object.create() // TypeError: Object prototype may only be an Object or null Object.create(123) // TypeError: Object prototype may only be an Object or null
Object.create()
The new object generated by the method dynamically inherits the prototype. Adding or modifying any method on the prototype will be immediately reflected on the new object.
var obj1 = { p: 1 }; var obj2 = Object.create(obj1); obj1.p = 2; obj2.p // 2
In the above code, modifying the object prototype obj1
will affect the instance object obj2
.
In addition to the prototype of the object, Object.create()
the method can also accept a second parameter. This parameter is an attribute description object, and the object attribute it describes will be added to the instance object as the object's own attribute.
var obj = Object.create({}, { p1: { value: 123, enumerable: true, configurable: true, writable: true, }, p2: { value: 'abc', enumerable: true, configurable: true, writable: true, } }); // Equivalent to var obj = Object.create({}); obj.p1 = 123; obj.p2 = 'abc';
Object.create()
The object generated by the method inherits the constructor of its prototype object.
function A() {} var a = new A(); var b = Object.create(a); b.constructor === A // true b instanceof A // true
In the above code, b
the prototype of the object is a
the object, so it inherits a
the constructor of the object A
.
Object.prototype.isPrototypeOf()
The method of the instance object isPrototypeOf
is used to determine whether the object is the prototype of the parameter object.
var o1 = {}; var o2 = Object.create(o1); var o3 = Object.create(o2); o2.isPrototypeOf(o3) // true o1.isPrototypeOf(o3) // true
In the above code, o1
and o2
are o3
the prototypes of . This means that as long as the instance object is on the prototype chain of the parameter object, isPrototypeOf
the method returns true
.
Object.prototype.isPrototypeOf({}) // true Object.prototype.isPrototypeOf([]) // true Object.prototype.isPrototypeOf(/xyz/) // true Object.prototype.isPrototypeOf(Object.create(null)) // false
In the above code, since Object.prototype
it is at the top of the prototype chain, all kinds of instances are returned true
, except for the objects directly inherited null
from.
Object.prototype.__proto__
Attributes of the instance object __proto__
(two underscores before and after), return the prototype of the object. This property is readable and writable.
var obj = {}; var p = {}; obj.__proto__ = p; Object.getPrototypeOf(obj) === p // true
The above code sets the object as the prototype of the object through __proto__
attributes .p
obj
According to the language standard, __proto__
the attribute only needs to be deployed by the browser, and other environments may not have this attribute. The two underscores before and after it indicate that it is essentially an internal attribute and should not be exposed to users. Therefore, you should use this attribute as little as possible, but use Object.getPrototypeOf()
and Object.setPrototypeOf()
to perform read and write operations on prototype objects.
The prototype chain can be __proto__
represented very intuitively.
var A = { name: 'Zhang San' }; var B = { name: 'Li Si' }; var proto = { print: function () { console.log(this.name); } }; A.__proto__ = proto; B.__proto__ = proto; A.print() // Zhang San B.print() // Li Si A.print === B.print // true A.print === proto.print // true B.print === proto.print // true
In the above code, A
both the object and B
the prototype of the object are proto
objects, and they all share the methods proto
of the object print
. That is to say, the method of A
and is calling the method of the object .B
print
proto
print
Get a comparison of prototype object methods
As mentioned earlier, __proto__
the property points to the prototype object of the current object, which is prototype
the property of the constructor function.
var obj = new Object(); obj.__proto__ === Object.prototype // true obj.__proto__ === obj.constructor.prototype // true
The above code first creates a new object obj
, and its __proto__
properties point to the properties of the constructor ( Object
or obj.constructor
) prototype
.
Therefore, obj
there are three ways to obtain the prototype object of the instance object.
-
obj.__proto__
-
obj.constructor.prototype
-
Object.getPrototypeOf(obj)
Of the above three methods, the first two are not very reliable. __proto__
Attributes only need to be deployed in browsers, and need not be deployed in other environments. When obj.constructor.prototype
manually changing the prototype object, it may fail.
var P = function () {}; var p = new P(); var C = function () {}; C.prototype = p; var c = new C(); c.constructor.prototype === p // false
In the above code, the prototype object of the constructor C
is changed p
, but the instance object c.constructor.prototype
does not point to it p
. Therefore, when changing the prototype object, it is generally necessary to set constructor
properties at the same time.
C.prototype = p; C.prototype.constructor = C; var c = new C(); c.constructor.prototype === p // true
Therefore, it is recommended to use the third Object.getPrototypeOf
method to obtain the prototype object.
Object.getOwnPropertyNames()
Object.getOwnPropertyNames
The method returns an array whose members are the keys of all properties of the parameter object itself, excluding inherited property keys.
Object.getOwnPropertyNames(Date) // ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]
In the code above, Object.getOwnPropertyNames
the method returns Date
all its own property names.
Among the properties of the object itself, some are enumerable and some are not. Object.getOwnPropertyNames
The method returns all key names, whether they can be traversed or not. To get only those attributes that can be traversed, use Object.keys
the method.
Object.keys(Date) // []
The above code shows that Date
all the properties of the object itself cannot be traversed.
Object.prototype.hasOwnProperty()
The method of the object instance hasOwnProperty
returns a Boolean value, which is used to determine whether a property is defined on the object itself or on the prototype chain.
Date.hasOwnProperty('length') // true Date.hasOwnProperty('toString') // false
The above code shows that ( how many parameters Date.length
the constructor can accept) is its own property and an inherited property.Date
Date
Date.toString
In addition, hasOwnProperty
methods are the only methods in JavaScript that do not traverse the prototype chain when dealing with object properties.
in operator and for...in loop
in
The operator returns a Boolean value indicating whether an object has a certain property. It does not distinguish whether the property is an object's own property or an inherited property.
'length' in Date // true 'toString' in Date // true
in
Operators are often used to check for the existence of a property.
To get all traversable properties of an object (whether self or inherited), you can use for...in
a loop.
var o1 = { p1: 123 }; var o2 = Object.create(o1, { p2: { value: "abc", enumerable: true } }); for (p in o2) { console.info(p); } // p2 // p1
In the above code, the properties o2
of the object p2
are its own and p1
the properties are inherited. Both properties will be for...in
looped over.
In order to for...in
obtain the properties of the object itself in the loop, you can use hasOwnProperty
the method to judge.
for ( var name in object ) { if ( object.hasOwnProperty(name) ) { /* loop code */ } }
To get all properties of an object (whether self or inherited, and whether enumerable or not), you can use the following function.
function inheritedPropertyNames(obj) { var props = {}; while(obj) { Object.getOwnPropertyNames(obj).forEach(function(p) { props[p] = true; }); obj = Object.getPrototypeOf(obj); } return Object.getOwnPropertyNames(props); }
The above code sequentially obtains obj
the "self" attributes of each level of the object's prototype object, thereby obtaining obj
the "all" attributes of the object, regardless of whether it is traversable or not.
Below is an example that lists Date
all properties of an object.
inheritedPropertyNames(Date) // [ // "caller", // "constructor", // "toString", // "UTC", // ... // ]
copy of object
If you want to copy an object, you need to do the following two things.
-
Make sure that the copied object has the same prototype as the original object.
-
Make sure that the copied object has the same instance attributes as the original object.
The following is the object copy function implemented based on the above two points.
function copyObject(orig) { var copy = Object.create(Object.getPrototypeOf(orig)); copyOwnPropertiesFrom(copy, orig); return copy; } function copyOwnPropertiesFrom(target, source) { Object .getOwnPropertyNames(source) .forEach(function (propKey) { var desc = Object.getOwnPropertyDescriptor(source, propKey); Object.defineProperty(target, propKey, desc); }); return target; }
Another simpler way of writing is to use ES2017 to introduce the standard Object.getOwnPropertyDescriptors
method.
function copyObject(orig) { return Object.create( Object.getPrototypeOf(orig), Object.getOwnPropertyDescriptors(orig) ); }
reference link
-
Dr. Axel Rauschmayer, JavaScript properties: inheritance and enumerability