1.Object.is()
ES5 compare two values are equal, only two operators: equality operator ( ==
) and strict equality operator ( ===
). They have disadvantages, the former will be automatically converted to data type, which is NaN
not equal to its own, and +0
is equal to -0
. JavaScript lack of a calculation, in all circumstances, as long as the two values are the same, they should be equal.
ES6 proposed "Same-value equality" (equal to the same value) algorithm is used to solve this problem. Object.is
The new method of this algorithm is deployed. It is used to compare two values are exactly equal, consistent with strict comparison operator (===) behavior.
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
The difference is only two: one is +0
not equal to -0
the second is NaN
equal to itself.
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
ES5 by the following code deployment Object.is
.
Object.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
// 针对+0 不等于 -0的情况
return x !== 0 || 1 / x === 1 / y;
}
// 针对NaN的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true
});
2.Object.assign()
Basic Usage
Object.assign
A method for merging the object, the source object (source) of all enumerated attribute, copied to the target object (target).
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
Object.assign
The first parameter is the target object's method, the source object parameters are behind.
Note that if the source object and the target object has attributes with the same name, or a plurality of source objects of the same name attribute, after the attribute overwrite the previous attribute .
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
If only one parameter, Object.assign
will return directly to the parameter.
const obj = {a: 1};
Object.assign(obj) === obj // true
If this parameter is not an object, it will turn into the first object and then returns.
typeof Object.assign(2) // "object"
Because undefined
, and null
not turn into an object, so if they are used as parameters, the error is reported.
Object.assign(undefined) // 报错
Object.assign(null) // 报错
If the non-object appears in a position of the source object (ie non-first parameter), then the processing rules are different. First, these parameters will turn into an object, if you can not turn into an object, will be skipped. This means that if undefined
and null
not in the first parameter, the error will not.
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
Values (i.e., values, and Boolean string) of other types is not the first parameter is not given. However, in addition to an array of strings, copied into the target object, other values will not be effective.
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
In the above code, v1
, v2
, v3
respectively, strings, Boolean values, and results only for strings into the target object (in the form of an array of characters), the numerical and Boolean values are ignored. This is because only the string wrapped object, will produce enumerable property.
Object(true) // {[[PrimitiveValue]]: true}
Object(10) // {[[PrimitiveValue]]: 10}
Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
In the above code, boolean, numeric, string, and transfected into a corresponding object to be wrapped, to their original values can be seen in the properties inside the package object [[PrimitiveValue]]
above, this property will not be Object.assign
copied. Wrapper object only strings, will have real meaning enumerable properties, those properties will be copied.
Object.assign
Copies of property is limited, only a copy of their own property of the source object (not copy inherited attributes), nor copy can not be enumerated attributes ( enumerable: false
).
Object.assign({b: 'c'},
Object.defineProperty({}, 'invisible', {
enumerable: false,
value: 'hello'
})
)
// { b: 'c' }
In the above code, Object.assign
the object to copy only a non-enumerated attribute invisible
, this property has not been copied into.
Properties named Symbol values, will be Object.assign
a copy.
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })
// { a: 'b', Symbol(c): 'd' }
important point
(1) shallow copy
Object.assign
The method is practiced shallow copy, rather than a deep copy. That is, the value of a property if the source object is an object, then get a copy of the target object is a reference to the object.
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
(2) replacement of the same name attribute
For this nested object, the event attribute of the same name, Object.assign
the processing method is to replace, rather than adding.
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
The above code, target
object a
attributes are source
object a
properties throughout the replaced , and will not get { a: { b: 'hello', d: 'e' } }
the results. This is usually not the developers want, need special care.
Some libraries offer Object.assign
customized versions (such as Lodash of the _.defaultsDeep
method) can be obtained with deep copies.
(3) processing array
Object.assign
It can be used to handle an array, but would arrays as objects .
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
In the above code, Object.assign
the array as an object property named 0,1,2, the source array property 0 4
covered 0 properties of the target array 1
.
Process (4) the value of the function
Object.assign
Copy only values, if the value is a value to be copied function, then evaluated and then copy .
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
The above code, source
object foo
attribute value is a function that Object.assign
does not copy the values of the function, only later to get the value, copy this value in the past.
Common uses
Object.assign
There are many ways useful.
(1) was added for objects
class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
By the above process Object.assign
method, the x
properties and y
add attributes to Point
the object class instance.
(2) a method of adding an object
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
}
});
// 等同于下面的写法
SomeClass.prototype.someMethod = function (arg1, arg2) {
···
};
SomeClass.prototype.anotherMethod = function () {
···
};
The above code uses a simple representation of object properties, the two functions directly in braces, then use the assign
method to the SomeClass.prototype
being.
(3) Cloning of the object
function clone(origin) {
return Object.assign({}, origin);
}
The above object is copied to the original code is an empty object, get a clone of the original object.
However, this method clones, only clone of the original object values itself, it can not be cloned inherited value . If you want to keep the inheritance chain, the following code can be used.
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);//Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
}
(4) combining a plurality of objects
Combine multiple objects to an object.
const merge =
(target, ...sources) => Object.assign(target, ...sources);
If you want to consolidate to return a new object, you can rewrite the above function, an empty object to the merger.
const merge =
(...sources) => Object.assign({}, ...sources);
(5) specified for the attribute default values
const DEFAULTS = {
logLevel: 0,
outputFormat: 'html'//输出格式
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
console.log(options);
// ...
}
The above code, DEFAULTS
the object is the default options
object is a user-supplied parameters. Object.assign
The methods DEFAULTS
and options
combined into a new object if both have the same name attribute, options
attribute value overrides the DEFAULTS
attribute values.
Note that, due to the presence of shallow copy problems, DEFAULTS
objects and options
all attributes of objects, preferably type are simple, do not point to another object. Otherwise, DEFAULTS
the properties of the object is likely to be ineffective.
const DEFAULTS = {
url: {
host: 'example.com',
port: 7070
},
};
processContent({ url: {port: 8000} })
// {
// url: {port: 8000}
// }
The original intent of the code above is url.port
changed to 8000, url.host
remain unchanged. The actual result is options.url
overwritten DEFAULTS.url
, it url.host
does not exist.
3.Object.getOwnPropertyDescriptors()
ES5 The Object.getOwnPropertyDescriptor()
method returns an object attributes that describe the object (descriptor). ES2017 introduced Object.getOwnPropertyDescriptors()
method, all the specified object attribute describes the object itself (non-inherited attributes).
const obj = {
foo: 123,
get bar() { return 'abc' }
};
Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
The above code, the Object.getOwnPropertyDescriptors()
method returns an object, attribute names are all the original object's property name, property value corresponding to the object is to describe the property.
Implementation of this method is very easy.
function getOwnPropertyDescriptors(obj) {
const result = {};
for (let key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
}
The purpose of this method is introduced, mainly to solve Object.assign()
not copy the correct get
attributes and set
problem properties.
const source = {
set foo(value) {
console.log(value);
}
};
const target1 = {};
Object.assign(target1, source);
Object.getOwnPropertyDescriptor(target1, 'foo')
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }
The above code, source
object foo
value of the property is an assignment function, Object.assign
method attribute copy to this target1
object, the result becomes a value of the property undefined
. This is because the Object.assign
method always copy the value of a property, and will not copy assignment method or accessor methods behind it.
In this case, Object.getOwnPropertyDescriptors()
the method with the Object.defineProperties()
method, it is possible to achieve the correct copy.
const source = {
set foo(value) {
console.log(value);
}
};
const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')
// { get: undefined,
// set: [Function: set foo],
// enumerable: true,
// configurable: true }
The above code, the two combined objects can be written a logic function.
const shallowMerge = (target, source) => Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
);
Object.getOwnPropertyDescriptors()
Another method of use, is in line with Object.create()
the method, object attributes cloned into a new object. It belongs to a shallow copy.
const clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
// 或者
const shallowClone = (obj) => Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
The above code clone obj
.
Further, the Object.getOwnPropertyDescriptors()
method may be implemented if an object inherits another object. Previously, another object inheritance, often written as follows.
const obj = {
__proto__: prot,
foo: 123,
};
ES6 provisions __proto__
only browser to deploy, do not deploy in other environments. If removed __proto__
, the code above would end up with the following.
const obj = Object.create(prot);
obj.foo = 123;
// 或者
const obj = Object.assign(
Object.create(prot),
{
foo: 123,
}
);
With Object.getOwnPropertyDescriptors()
, we have another way.
const obj = Object.create(
prot,
Object.getOwnPropertyDescriptors({
foo: 123,
})
);
Object.getOwnPropertyDescriptors()
It can also be used to implement Mixin (mixed) mode.
let mix = (object) => ({
with: (...mixins) => mixins.reduce(
(c, mixin) => Object.create(
c, Object.getOwnPropertyDescriptors(mixin)
), object)
});
// multiple mixins example
let a = {a: 'a'};
let b = {b: 'b'};
let c = {c: 'c'};
let d = mix(c).with(a, b);
d.c // "c"
d.b // "b"
d.a // "a"
The above code returns a new object d
, representing objects a
and b
is mixed object c
operation.
For completeness, Object.getOwnPropertyDescriptors()
after the entry criteria, the future will add Reflect.getOwnPropertyDescriptors()
method.
4.__proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
Object JavaScript language inheritance is achieved through the prototype chain. ES6 provided a method of operating more prototype object.
__proto__
Attributes
__proto__
Properties (before and after two underscores), provided for reading the current object or prototype
objects. Currently, all browsers (including IE11) has deployed this property.
// es5 的写法
const obj = {
method: function() { ... }
};
obj.__proto__ = someOtherObj;
// es6 的写法
var obj = Object.create(someOtherObj);
obj.method = function() { ... };
This property is not ES6 written text, but written appendix, because the __proto__
double underline before and after, indicating that it is essentially an internal property, rather than a formal external API, but due to the widespread browser support, was He joined the ES6. Clearly defined standards, only browser must deploy this property, other operating environments do not necessarily need to be deployed, and the new code should think that this property does not exist. Therefore, both from the semantic point of view, or from a compatibility point of view, do not use this property, but the use of the following Object.setPrototypeOf()
(a write operation), Object.getPrototypeOf()
(read), (generatingObject.create()
operation) instead.
The realization, __proto__
the call is Object.prototype.__proto__
specific implementation is as follows.
Object.defineProperty(Object.prototype, '__proto__', {
get() {
let _thisObj = Object(this);
return Object.getPrototypeOf(_thisObj);
},
set(proto) {
if (this === undefined || this === null) {
throw new TypeError();
}
if (!isObject(this)) {
return undefined;
}
if (!isObject(proto)) {
return undefined;
}
let status = Reflect.setPrototypeOf(this, proto);
if (!status) {
throw new TypeError();
}
},
});
function isObject(value) {
return Object(value) === value;
}
If an object itself deployed __proto__
property, the value of the prototype is the object of the property.
Object.getPrototypeOf({ __proto__: null })
// null
Object.setPrototypeOf()
Object.setPrototypeOf
The method of action of the __proto__
same, used to set a target prototype
object, and returns the parameter object itself. It is recommended setting ES6 official prototype object.
// 格式
Object.setPrototypeOf(object, prototype)
// 用法
const o = Object.setPrototypeOf({}, null);
This method is equivalent to the following function.
function setPrototypeOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}
Below is an example.
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
obj.x // 10
obj.y // 20
obj.z // 40
The above code proto
objects to obj
the prototype object, so that the obj
can read the object proto
properties of the object.
If the first argument is not an object, it will automatically be converted to objects. However, because the first parameter is returned, so the operation will not have any effect.
Object.setPrototypeOf(1, {}) === 1 // true
Object.setPrototypeOf('foo', {}) === 'foo' // true
Object.setPrototypeOf(true, {}) === true // true
Because undefined
, and null
not into the object, so if the first argument is undefined
or null
will an error.
Object.setPrototypeOf(undefined, {})
// TypeError: Object.setPrototypeOf called on null or undefined
Object.setPrototypeOf(null, {})
// TypeError: Object.setPrototypeOf called on null or undefined
Object.getPrototypeOf()
The method and Object.setPrototypeOf
method supporting an object for reading a prototype object.
Object.getPrototypeOf(obj);
Below is an example.
function Rectangle() { //rectangle矩形
// ...
}
const rec = new Rectangle();
Object.getPrototypeOf(rec) === Rectangle.prototype
// true
Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype
// false
If the parameter is not an object, the object will be automatically converted.
// 等同于 Object.getPrototypeOf(Number(1))
Object.getPrototypeOf(1)
// Number {[[PrimitiveValue]]: 0}
// 等同于 Object.getPrototypeOf(String('foo'))
Object.getPrototypeOf('foo')
// String {length: 0, [[PrimitiveValue]]: ""}
// 等同于 Object.getPrototypeOf(Boolean(true))
Object.getPrototypeOf(true)
// Boolean {[[PrimitiveValue]]: false}
Object.getPrototypeOf(1) === Number.prototype // true
Object.getPrototypeOf('foo') === String.prototype // true
Object.getPrototypeOf(true) === Boolean.prototype // true
If the parameter is undefined
or null
, they can not be converted to an object, it will be an error.
Object.getPrototypeOf(null)
// TypeError: Cannot convert undefined or null to object
Object.getPrototypeOf(undefined)
// TypeError: Cannot convert undefined or null to object
5.Object.keys(),Object.values(),Object.entries()
Object.keys()
ES5 introduced Object.keys
method returns an array, the members of the object itself is a parameter (not inherited) all traverse (Enumerable) attribute keys.
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
ES2017 introduced the now Object.keys
supporting Object.values
and Object.entries
, as a supplementary means of traversing an object, for for...of
recycling.
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Object.values()
Object.values
The method returns an array, the members of the object itself is a parameter (not inherited) all traverse (Enumerable) key attribute.
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
Consistent with the rules described in section returns an array arrangement order of members, and "traversal attribute" chapter.
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
In the above code, called Attribute value is the value in accordance with the size, from small to large traversed, so that the sequence returns b
, c
, a
.
Object.values
Only returns the object itself can traverse the property.
const obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []
In the above code, Object.create
the object attribute (add a second parameter method p
), if not explicitly declared, a default is not traversable, because p
the properties of the object described enumerable
by default false
, Object.values
will not return to this property. As long as the enumerable
change true
, Object.values
it will return property p
values.
const obj = Object.create({}, {p:
{
value: 42,
enumerable: true
}
});
Object.values(obj) // [42]
Object.values
Symbol will filter attribute named property value.
Object.values({ [Symbol()]: 123, foo: 'abc' });
// ['abc']
If the Object.values
method parameter is a string, it returns an array of individual characters.
Object.values('foo')
// ['f', 'o', 'o']
In the above code, we will first turn into a string-like object array. Each character in the string is a property of the object. Therefore, the Object.values
return key values for each attribute is an array of individual characters.
If the parameter is not an object, Object.values
it will first turn its objects. Since the value of the object and packaging Boolean value, will not be added as an example of non-inherited properties. Therefore, Object.values
it returns an empty array.
Object.values(42) // []
Object.values(true) // []
Object.entries()
Object.entries()
The method returns an array, the members of the object itself is a parameter (not inherited) all traverse (Enumerable) key attribute array.
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
In addition to the return value is not the same, and the behavior of this method Object.values
are basically the same.
If the property name of the original object is a Symbol value, the property will be ignored.
Object.entries({ [Symbol()]: 123, foo: 'abc' });
// [ [ 'foo', 'abc' ] ]
In the above code, there are two original object attributes, Object.entries
only the output of the non-Symbol Attribute name value. There may be a future Reflect.ownEntries()
method that returns the object of all their property.
Object.entries
The basic purpose is to traverse the object attributes.
let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {
console.log(
`${JSON.stringify(k)}: ${JSON.stringify(v)}`
);
}
// "one": 1
// "two": 2
Object.entries
Another useful method is that an object into a real Map
structure.
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }
Realize his Object.entries
method is very simple.
// Generator函数的版本
function* entries(obj) {
for (let key of Object.keys(obj)) {
yield [key, obj[key]];
}
}
// 非Generator函数的版本
function entries(obj) {
let arr = [];
for (let key of Object.keys(obj)) {
arr.push([key, obj[key]]);
}
return arr;
}
6.Object.fromEntries()
Object.fromEntries()
It is Object.entries()
the inverse operation, for an array of key-value pair into the object .
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
The main purpose of this method, is to restore the data structure of the key-value for the object, it is particularly suitable structure into the Map objects.
// 例一
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
Object.fromEntries(entries)
// { foo: "bar", baz: 42 }
// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }
One use of this method is in line with URLSearchParams
the object, the query string to object.
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }