object.is() ===
方法用来判断两个值是否相等,它接收两个参数,分别是需要比较的两个值。Object.is中的NaN与NaN是相等的。 同时Object.is也不会强制转换两边的值的类型,Object.is与===的区别主要体现在+0和-0以及对NaN的比较上。
javascript
console.log(+0 === -0); //true
console.log(NaN === NaN) //false
console.log(NaN == NaN); //false
console.log(Object.is(+0, -0)); //false
console.log(Object.is(NaN, NaN)) //true
== 比较两个值是否相等,如果两边的值不是同一个类型的话,会将他们转为同一个类型后再进行比较。
123 == '123'; // true
'' == false; // true
false == 0; // true
NaN == NaN; // false
=== 不会对类型进行转换,两边的值必须相等且类型相同才会等到 true 。
123 === 123; // true
123 === '123'; // false
'' === false; // false
false === 0; // false
NaN === NaN; // false
需要特殊注意的是,对于 0 和 NaN 的比较。无论 0 的正负,他们都是相等的,而 NaN 是与任何值都不相等的,包括他本身。
+ 0 === -0; // true
0 === -0; // true
+0 === 0; // true
NaN === NaN; // false
Object.assign()
Object.assign()方法用于将一个或多个源对象的可枚举属性复制到目标对象中,并返回目标对象。它基于浅复制原则,只复制对象自身的属性,不复制继承自原型链上的属性。如果目标对象已经存在相同属性,则源对象的属性将覆盖目标对象的属性。
语法:
Object.assign(target, ...sources)
`target`:目标对象,要将属性复制到的对象。
`sources`:一个或多个源对象,从中复制属性的对象。
情况一:如果后面对象的属性,比如source中存在属性b,而目标对象(第一个参数)中也存在属性b,则source里的属性b值,会覆盖前面的属性b值 复制对象,存在相同key,则后面覆盖前面的
javascript
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const result = Object.assign(target, source);
console.log(result); //{a:1,b:4,c:5}
情况二:Object.assign() 会改变第一个对象的值,后面对象的值不会改变,遇到相同key,后面的值会覆盖前面的
javascript
const target1 = { a: 1, b: 2 };
const source1 = { b: 4, c: 5, d: 6 };
Object.assign(target1, source1);
console.log(target1); //{a:1,b:4,c:5,d:6}
console.log(source1); // { b: 4, c: 5, d: 6 }
情况三:如果想合并几个对象生成新的对象,并对原来的对象内容无影响,可以将Object.assign()的第一个参数设为空对象
javascript
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 4, c: 5 };
const obj3 = { d: 6 };
const merged = Object.assign({}, obj1, obj2, obj3);
console.log(merged); // { a: 1, b: 4, c: 5, d: 6 }
注意事项
Object.assign()方法不会拷贝对象的不可枚举属性、原型链属性以及方法。
当源对象含有getter时,会触发getter的执行。
Object.assign()是浅复制,所以在处理嵌套对象时需要小心。
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组。其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
当参数为对象时
javascript
const obj = { name: 'xiaoming', age: 'seven', sex: 'man', grade: 'four' };
const res = Object.entries(obj)
console.log(res);
//[
// ['name', 'xiaoming'],
// ['age', 'seven'],
// ['sex', 'man'],
// ['grade', 'four']
// ]
当参数为数组时
javascript
const obj = [1, 2, 3, 4, 5, 6]
const res = Object.entries(obj)
console.log(res);
// [
// ['0', 1],
// ['1', 2],
// ['2', 3],
// ['3', 4],
// ['4', 5],
// ['5', 6]
// ]
参数为数组(数组中包含对象)
javascript
const obj = [1, 2, 3, 4, 5, 6, { a: 'a' }, { b: 'b' }, { c: 'c' }]
const res = Object.entries(obj)
console.log(res);
参数为数组(数组中元素为对象)
javascript
const obj = [{ a: 'a' }, { b: 'b' }, { c: 'c' }]
const res = Object.entries(obj)
console.log(res);
Object转换为Map
javascript
const obj = { name: 'xiaoming', age: 'seven', sex: 'man', grade: 'four' };
console.log(Object.entries(obj));
const map = new Map(Object.entries(obj));
console.log(map);
Object.values()
官方定义 返回一个给定对象的自有可枚举字符串键属性值组成的数组
javascript
const object1 = {
a: 'somestring',
b: 42,
c: false,
};
console.log(Object.values(object1));// ['somestring', 42, false]
var obj2 = {
gtq: {name: '光头强',age: '18',height: '177'},
xd: {name: '熊大',age: '12',height: '190'},
xe: {name: '熊二',age: '10',height: '188'}
}
const list2 = Object.values(obj2);
console.log(list2)
// 得到:
/**
* [
* {name: '光头强', age: '18', height: '177'},
* {name: '熊大', age: '12', height: '190'},
* {name: '熊二', age: '10', height: '188'}
* ]
*
*/
Object.defineProperty()
该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...in 或 Object.keys 方法), 这些属性的值可以被改变,也可以被删除。方法Object.defineProperty()允许修改默认的属性元数据配置。我们可以认为Object.defineProperty()定义的属性在使用上更加严格。
语法:Object.defineProperty(obj, prop, descriptor)
obj 要在其上定义属性的对象。
prop String|Symbol,Required,要定义或修改的属性的名称。
descriptor Object,Required,将被定义或修改的属性描述符。
参数descriptor就是属性描述符,就是定义属性行为的元数据信息。属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个Boolean类型的元数据属性,值为true或false,用于定义对属性的某种操作行为是允许还是禁止。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一,即descriptor要么是数据描述符,要么是存取描述符,不能同时包含数据描述符和存取描述符。
configurable
当且仅当该属性的 configurable 为 true 时,才能够再次修改该属性的属性描述符,同时该属性也能从对应的对象上被删除。默认为 false。
enumerable
当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为 false。数据描述符除了具有configurable和enumerable这两个元数据键值外,还具有以下可选键值:
value
该属性的初始值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
writable
当且仅当该属性的writable为true时,该属性才能被写入值。默认为 false。
存取描述符除了具有configurable和enumerable这两个元数据键值外,还具有以下可选键值:
get
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。默认为 undefined。
set
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。默认为 undefined。
|-------|--------------|------------|-------|----------|-----|-----|
| | configurable | enumerable | value | writable | get | set |
| 数据描述符 | Yes | yes | yes | yes | no | no |
| 存取描述符 | yes | yes | no | no | yes | yes |
javascript
// 如果一个描述符不具有value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。
// 向对象中添加一个属性并设置数据描述符
const obj1 = {};
Object.defineProperty(obj1, 'a', {
value: 1,
writable: true,
enumerable: true,
configurable: true
})
console.log(obj1.a)
//向对象中添加一个属性并设置存取描述符
const obj1={};
var bValue;
Object.defineProperty(obj1,'b',{
get:function(){
return bValue;
},
set:function (newValue){
bValue=newValue;
},
enumerable:true,
configurable:true
})
obj1.b=2;
console.log(obj1.b) 输出: 2,表示属性b的getter和setter均生效
//数据描述符和存取描述符不能混合使用
const obj1={};
抛出异常: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
Object.defineProperty(obj1, "c", {
value: 1,
get: function () {
return 2;
}
});
//当writable设置为false时(默认值即是false),该属性被定义为只读属性,即只能读取该属性值,不能给该属性写入值。
const obj1 = {};
Object.defineProperty(obj1, 'a', {
value: 1,
writable: true,
})
Object.defineProperty(obj1, 'b', {
value: 2,
writable: false,
})
obj1.a = 100; // 向属性a中写入值
console.log(obj1.a); // 输出: 100,表示属性a的【writable: true】已生效
// 严格模式下抛出异常 TypeError: Cannot assign to read only property 'b' of object '#<Object>'
// 非严格模式不抛出异常,但是不生效
obj1.b = 200; // 向属性b中写入值
console.log(obj1.b); // 输出: 1
//enumerable定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
const obj1={};
Object.defineProperty(obj1,'a',{
value:1,
enumerable:true, // 用于定义属性a可以被枚举
})
Object.defineProperty('obj1','b',{
value:2,
enumerable:false // 用于定义属性b不可以被枚举
})
for (let key in obj1){
console.log(key); //'a'
}
console.log(Object.keys(obj1)); //['a'];
console.log('a' in obj1); //true
console.log('b' in obj1) //true
//get 和set
//设置getter 和setter 的普通示例
const obj = {};
let v = null;
Object.defineProperty(obj1, 'a', {
get: function () {
return v
},
set: function (newValue) {
v = newValue
}
})
obj1.a=1;
console.log(obj1.a) // 输出: 1,表示属性a的getter和setter均生效
//继承属性
function Person() {
// 在Person的原型上定义属性name,并设置getter以及setter,这样Person类的示例均能访问name属性,且实例的name属性互相隔离
Object.defineProperty(Person, 'name', {
get: function () {
return this._name;
},
set: function (newValue) {
this._name = newValue;
}
})
}
const a = new Person();
const b = new Person();
a.name = '张三';
b.name = 'lisi';
console.log(a.name); //张三
console.log(b.name); //lisi
//configurable用于表示对象的属性是否可以被删除的示例
'use strict'; //严格模式
const obj1 = {};
Object.defineProperty(obj1, 'a', {
value: 1,
configurable: true
})
Object.defineProperty(obj1, 'b', {
value: 2,
configurable: false
});
delete obj1.a // 从对象obj1中删除属性a
console.log(obj1.a)
// 严格模式下抛出异常 TypeError: Cannot delete property 'b' of #<Object>
// 非严格模式下不会抛出异常,但是不生效
delete obj1.b; // 从对象obj2中删除属性b
console.log(obj1.b); // 输出: 2,表示删除属性b失败
//configurable值为false表示属性描述符不能被再次修改的示例
'use strict'; //严格模式
const obj1 = {};
Object.defineProperty(obj1, 'a', {
value: 1, // 用于定义a的默认值为1
configurable: false,
writable: false, // 将属性a定义为只读不可写
enumerable: false // 将属性a定义为不可枚举
})
// 严格模式会抛出异常
// 非严格模式不会抛出异常,但不生效
obj1.a = 100;
console.log(obj1.a); // 输出: 1
console.log(Object.keys(obj1)); // 输出: []
// 抛出异常TypeError: Cannot redefine property: a
// 说明当上次对属性a调用Object.defineProperty()设置configurable为false后,a的属性描述符不能被再次修改,即不能再次对属性a调用Object.defineProperty()方法
Object.defineProperty(obj1, 'a', {
value: 2, // 用于定义a的默认值为1
configurable: true,
writable: true, // 重新将属性a定义为可写
enumerable: true // 重新将属性a定义为可枚举
});
//由于上面抛出异常,以下代码均无法执行
console.log(obj1.a);
obj1.a = 200;
console.log(obj1.a);
console.log(Object.keys(obj1));
// configurable值为true表示属性描述符可以被再次修改的示例
'use strict';
const obj1 = {};
Object.defineProperty(obj1, 'a', {
value: 1, // 用于定义a的默认值为1
configurable: true, // 表示可以对属性a再次调用Object.defineProperty()方法
writable: false, // 将属性a定义为只读不可写
enumerable: false // 将属性a定义为不可枚举
});
obj1.a = 100;
console.log(obj1.a); // 输出: 1
console.log(Object.keys(obj1)); // 输出: []
Object.defineProperty(obj1, 'a', {
value: 2, // 用于定义a的默认值为2
configurable: true,
writable: true, // 重新将属性a定义为可写
enumerable: true // 重新将属性a定义为可枚举
});
console.log(obj1.a); // 输出: 2,表示【writable: true】生效
obj1.a = 200;
console.log(obj1.a); // 输出: 200,表示【writable: true】生效
console.log(Object.keys(obj1)); // 输出: ['a'],表示【enumerable: true】生效
let bValue = null;
Object.defineProperty(obj1, 'b', {
configurable: true, // 表示可以对属性a再次调用Object.defineProperty()方法
get() {
return bValue;
},
set(newValue) {
bValue = newValue;
}
});
obj1.b = 'abcd';
console.log(obj1.b); // 输出: 'abcd'
Object.defineProperty(obj1, 'b', {
configurable: true, // 表示可以对属性a再次调用Object.defineProperty()方法
get() {
return bValue.toString().toUpperCase();
},
set(newValue) {
bValue = newValue + '_' + newValue;
}
});
obj1.b = 'efgh';
console.log(obj1.b); // 输出: 'EFGH_EFGH',表示新的setter和getter已经生效
Object.create()
创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
语法: Object.create(proto[, propertiesObject])
javascript
const person = {
isHuman: false,
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
console.log(me);
const person = {
isHuman: false,
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = 'Matthew'; // name是me的属性不是person的
me.isHuman = true; // isHuman也是属性上
me.printIntroduction();
// "My name is Matthew. Am I human? true"
console.log(me);
// proto
// 新创建对象的原型对象。
// propertiesObject
// 可选。如果没有指定为 undefind, 则是要添加到新创建对象的不可枚举
// (默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)
// 对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()
// 的第二个参数。(可以点击去了解也是我写的)
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function () {
return this.name
}
Person.prototype.getAge = function () {
return this.age;
}
function Student(name, age, grade) {
// 构造函数继承
Person.call(this, name, age);
this.grade = grade;
}
// 原型继承
Student.prototype = Object.create(Person.prototype, {
// 不要忘了重新指定构造函数 这个是必须的
constructor: {
value: Student
},
foo: {
writable: true,
configurable: true,
value: "hello"
},
getGrade: {
value: function () {
return this.grade
}
}
})
var s1 = new Student('ming', 22, 5);
console.log(s1.getName()); // ming
console.log(s1.getAge()); // 22
console.log(s1.getGrade()); // 5
console.log(s1.foo); // hello
// Student 继承自Person,Person继承自Object
console.log(s1 instanceof Student);
console.log(s1 instanceof Person);
console.log(s1 instanceof Object);
// 结果 true true true
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function () {
// do a thing
};
// Object.assign 会把 OtherSuperClass原型上的函数拷贝到 MyClass原型上,
// 使 MyClass 的所有实例都可用 OtherSuperClass 的方法
var o;
// 创建一个原型为null的空对象
o = Object.create(null);
o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable: true,
configurable: true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function () { return 10 },
set: function (value) {
console.log("Setting `o.bar` to", value);
}
}
});
function Constructor() { }
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42
o.q = 12
for (var prop in o) {
console.log(prop)
}
//"q"
delete o.p
//false
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});