文章目录
- 一、对象创建的四种方式以及区别
- 二、访问对象属性
- 三、删除对象属性
- 四、枚举对象的属性
- 五、Object常用的API
- 5.1、Object.assign()
- 5.2、Object.keys()
- 5.3、Object.values()
- 5.4、Object.entries(obj)
- 5.5. Object.fromEntries()
- 5.6、Object.prototype.hasOwnProperty
- 5.6、isPrototypeOf
- 5.7、Object.getOwnPropertyNames()
- 5.8、defineProperty定义对象属性
- 5.9、getPrototypeOf: 获取指定对象的原型(内部[[Prototype]]属性的值)
- 5.10、setPrototypeOf 设置一个指定的对象的原型
- 5.11、Object.is :它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致
- 5.12、Object.freeze()和Object.isFrozen()
一、对象创建的四种方式以及区别
1.1、对象字面量
var dog1 = {
name: "大黄",
age: 2,
speak: function () {
console.log("汪汪");
},
};
1.2、使用Object构造函数
var dog2 = new Object();
dog2.name = "大黄";
dog2.age = 2;
dog2.speak = function () {
console.log("汪汪");
};
1.3、使用自定义构造函数
// 使用构造函数
function Dog(name, age) {
this.name = name;
this.age = age;
}
Dog.prototype.speak = function () {
console.log("汪汪");
};
var dog3 = new Dog("大黄", 2);
1.4、 使用Object.create
Object.create
用于创建一个新对象,使用现有的对象来提供新创建对象的原型对象。
- proto - 必须,新创建对象的原型对象。
- prop - 可选,是一个对象,设置属性及属性值,默认值:undefined,(属性默认不能修改,不能枚举)。
语法:
Object.create(proto,prop)
创建一个原型为null的空对象
var o = Object.create(null);
console.log( o.__proto__ === undefined ); // true
创建一个原型为 { m: 1 } 的空对象
var a = { m: 1 };
var b = Object.create(a);
console.log( b.__proto__ === a ); // true
创建一个以空对象为原型对象,且拥有一个属性p的对象
var o = Object.create({}, { p: { value: 42 } });
console.log(o); // { p: 42 }
以字面量方式创建的空对象就相当于: Object.create(Object.prototype)
var o = {};
//相当于 var o = Object.create(Object.prototype)
console.log( o.__proto__ === Object.prototype ); //true
二、访问对象属性
2.1、以.
的方式访问
const obj = {
info: "wakaka",
inner: {
a: 10,
b: 20,
},
arr: [1, 2],
sayHi: (name) => {
console.log(`hi,${name}`);
},
};
// 用 dot(点 .) 的方式访问
console.log(obj.info); // wakaka
console.log(obj.inner); // {"a":10,"b":20}
console.log(obj.arr); // [1,2]
obj.sayHi("dengke"); // hi,dengke
2.2、以[]
的方式访问
// 用 [] 的方式访问
console.log(obj["info"]); // wakaka
console.log(obj["inner"]); // {"a":10,"b":20}
console.log(obj["arr"]); // [1,2]
obj["sayHi"]("dengke"); // hi,dengke
区别:
[]
中括号法:可以用变量作为属性名或访问,而点语法不可以;
var obj = {};
obj.name = "张三";
var myName = "name";
console.log(obj.myName); //undefined,访问不到对应的属性
console.log(obj[myName]); //张三
var person = {
name: "gogo",
};
console.log(person["name"]); //gogo
console.log(person.name); //gogo
// 优点:1,可以通过变量来访问属性
var propertyName = "name";
console.log(person[propertyName]); //gogo
var propertyName2 = "name2";
console.log(person[propertyName2]); //undefined
[]
中括号法:可以用数字作为属性名,而点语法不可以;
var obj1 = {};
// obj1.1=1;//Unexpected number
obj1[2] = 2;
// console.log(obj1.1)
console.log(obj1[2]); //2
// console.log(obj1.2)
console.log(obj1); //{2: 2}
[]
中括号法:可以动态设置和获取属性名,点操作符就不行;
// ( 即 []--可以动态设置和获取)
var customer = {};
var addr = ["北京", "上海", "广州", "深圳"];
for (i = 0; i < 4; i++) {
customer["address" + i] = addr[i];
}
console.log(addr);
console.log(customer);
- 如果属性名中包含会导致语法错误的字符,或者属性名是关键字或者保留字,也可以使用中括号表示法
person["first name"] = "gogo2"; //first name包含一个空格
console.log(person["first name"]);
// console.log(person.first name)//书写都通不过
person["for"] = "gogo_for"; //first name包含一个空格
person.if = "gogo_if"; //first name包含一个空格
console.log(person["for"]); //gogo_for
console.log(person.for); //gogo_for
console.log(person["if"]); //gogo_if
console.log(person.if); //gogo_if
补充
如果要访问的对象不存在,可以使用 逻辑运算符 || 指定默认值
只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。
可选链式操作符(?.) (es11)
这是当对象上没有这个键的时候,不会报错,而是赋值
undefined
const foo = { name: "zengbo" };
let a = foo.name?.toUpperCase(); // "ZENGBO"
let b = foo.name?.firstName?.toUpperCase(); // "undefined"
三、删除对象属性
利用关键字 delete
const o = {
p: 10,
m: 20,
};
delete o.p;
console.log(o); // { m: 20 }
// 删除对象的属性后,在访问返回 undefined
console.log(o.p); // undefined
四、枚举对象的属性
for in
: 会遍历对象中所有的可枚举属性(包括自有属性和继承属性)
Object.keys()
: 会返回一个包括所有的可枚举的自有属性的名称组成的数组
Object.getOwnPropertyNames()
: 会返回自有属性的名称 (不管是不是可枚举的)
4.1、for…in…
会遍历对象中所有的可枚举属性(包括自有属性和继承属性)
const obj = {
itemA: "itemA",
itemB: "itemB",
};
// 使用Object.create创建一个原型为obj的对象 (模拟继承来的属性)
var newObj = Object.create(obj);
newObj.newItemA = "newItemA";
newObj.newItemB = "newItemB";
for (i in newObj) {
console.log(i);
}
// newItemA
// newItemB
// itemA
// itemB
// 现在我们将其中的一个属性变为不可枚举属性
Object.defineProperty(newObj, "newItemA", {
enumerable: false,
});
for (i in newObj) {
console.log(i);
}
// newItemB
// itemA
// itemB
4.2、Object.keys():
会返回一个包括所有的可枚举的自有属性的名称组成的数组
// 接上例
const result = Object.keys(newObj)
console.log(result) // ["newItemB"]
Object.keys()该方法在下文有更具体的介绍
4.3、Object.getOwnPropertyNames()
会返回自有属性的名称 (不管是不是可枚举的)
// 接上例
const result = Object.getOwnPropertyNames(newObj)
console.log(result) // ['newItemA','newItemB']
Object.getOwnPropertyNames()该方法在下文有更具体的介绍
五、Object常用的API
5.1、Object.assign()
语法
Object.assign(target, ...sources)
// 参数:target 目标参数,sources源对象 返回值:目标对象
Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。常用来合并对象。
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 4, c: 5 };
const obj3 = Object.assign(obj1, obj2);
const obj4 = Object.assign({}, obj1); // 克隆了obj1对象
console.log(obj1); // { a: 1, b: 4, c: 5 } 对同名属性b进行了替换 obj1发生改变是因为obj2赋给了obj1
console.log(obj2); // { b: 4, c: 5 }
console.log(obj3); // { a: 1, b: 4, c: 5 }
console.log(obj4); // { a: 1, b: 4, c: 5 }
注意:
-
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。 -
assign
其实是浅拷贝而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。同名属性会替换。
const obj5 = {
name: "dengke",
a: 10,
fn: {
sum: 10,
},
};
const obj6 = Object.assign(obj1, obj5);
console.log(obj6); // { a: 10, b: 2, name: 'dengke', fn: {…}}
console.log(obj1); // {a: 10, b: 2, name: 'dengke', fn: {…}} 对同名属性a进行了替换
Object.assign
不会在那些source对象值为null
或undefined
的时候抛出错误。
5.2、Object.keys()
语法:
Object.keys(obj)
-
参数:obj要返回其枚举自身属性的对象。
-
返回值:一个表示给定对象的所有可枚举属性的字符串数组。
Object.keys()
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。
与
Object.values()
相似,区别在于这个返回的是数据的属性就是key
。接下来就会介绍Object.values()
。
const arr = ["a", "b", "c"];
console.log(Object.keys(arr)); // ['0', '1', '2']
const obj = { 0: "a", 1: "b", 2: "c" };
console.log(Object.keys(obj)); // ['0', '1', '2']
const obj2 = { 100: "a", 2: "b", 7: "c" };
console.log(Object.keys(obj2)); // ['2', '7', '100']
注意
在
ES5
里,如果此方法的参数不是对象(而是一个原始值),那么它会抛出TypeError
。在ES2015中,非对象的参数将被强制转换为一个对象。
5.3、Object.values()
语法:
Object.values(obj)
-
参数:obj被返回可枚举属性值的对象。
-
返回值:一个包含对象自身的所有可枚举属性值的数组。
Object.values()
方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in
循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。与Object.keys()
相似,区别在于这个返回的是数据的值也就是value
const obj1 = { foo: "bar", baz: 42 };
console.log(Object.values(obj1)); // ['bar', 42]
const obj2 = { 0: "a", 1: "b", 2: "c" };
console.log(Object.values(obj2)); // ['a', 'b', 'c']
注意
对象key
为number
的话,会从升序枚举返回。
const obj3 = { 100: 'a', 2: 'b', 7: 'c' }
console.log(Object.values(obj3)) // ['b', 'c', 'a']
5.4、Object.entries(obj)
语法:
Object.entries(obj)
- 参数:obj可以返回其可枚举属性的键值对的对象。
- 返回值:给定对象自身可枚举属性的键值对数组。
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组。可使用Object.fromEntries()
方法,相当于反转了Object.entries()
方法返回的数据结构。接下来也会介绍Object.fromEntries()
const obj = { foo: "bar", baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// array like object 像数组的对象
const obj = { 0: "a", 1: "b", 2: "c" };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// array like object with random key ordering
const anObj = { 100: "a", 2: "b", 7: "c" };
// 返回值会按照key升序排列
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
// getFoo is property which isn't enumerable getFoo是不可枚举的属性
const myObj = Object.create(
{},
{
getFoo: {
value() {
return this.foo;
},
},
}
);
myObj.foo = "bar";
console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ] // 只会返回对象可枚举属性键值对组成的数组
// non-object argument will be coerced to an object //ES2015新增 会将非对象参数强转成对象
console.log(Object.entries("foo")); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]
// iterate through key-value gracefully 优雅地遍历键值对
const obj = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
}
// Or, using array extras 使用数组的额外功能
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});
补充
将
Object
转换为Map
对象
new Map()
构造函数接受一个可迭代的entries
。借助Object.entries
方法你可以很容易的将Object
转换为Map
:
const obj = { foo: "bar", baz: 42 };
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
5.5. Object.fromEntries()
语法:
Object.fromEntries(iterable)
-
参数:iterable类似Array、Map或者其它实现了可迭代协议的可迭代对象。
-
返回值:一个由该迭代对象条目提供对应属性的新对象。
Object.fromEntries()
方法把键值对列表转换为一个对象。与Object.entries()
相反。相当于反转了Object.entries()
方法返回的数据结构。
const entries = new Map([
["foo", "bar"],
["baz", 42],
]);
const obj = Object.fromEntries(entries);
console.log(obj);
// Object { foo: "bar", baz: 42 }
补充
Map
对象 转化为Object
通过 Object.fromEntries
, 可以将Map转换为Object
:
const map = new Map([
["foo", "bar"],
["baz", 42],
]);
const obj = Object.fromEntries(map);
console.log(obj);
// { foo: "bar", baz: 42 }
Array
转化为 Object
const arr = [
["0", "a"],
["1", "b"],
["2", "c"],
];
const obj = Object.fromEntries(arr);
console.log(obj);
// { 0: "a", 1: "b", 2: "c" }
Object.fromEntries
是与Object.entries()
相反的方法
可以像下面这样转换对象:
const object1 = { a: 1, b: 2, c: 3 };
const object2 = Object.fromEntries(
Object.entries(object1).map(([key, val]) => [key, val * 2])
);
// Object.entries(object1) >>> [["a",1],["b",2],["c",3]]
console.log(object2); // { a: 2, b: 4, c: 6 }
5.6、Object.prototype.hasOwnProperty
上边枚举对象属性时为了避免for..in
遍历继承来的属性,给大家补充了可以借助Object.prototype.hasOwnProperty()
方法进行判断,在这里也具体为大家介绍一下它。
语法:
obj.hasOwnProperty(prop)
-
参数:prop 要检测的属性的String字符串形式表示的名称,或者Symbol。
-
返回值:用来判断某个对象是否含有指定的属性的布尔值Boolean。
hasOwnProperty()
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
注意:
只会对自身属性进行判断,继承来的一律返回false。
配合for...in
使用,可以避免其遍历继承来的属性。
const obj1 = new Object();
obj1.property1 = 42;
Object.prototype.property2 = 111;
console.log(obj1.hasOwnProperty("property1")); // true
console.log(obj1.hasOwnProperty("property2")); // false
console.log(obj1.hasOwnProperty("toString")); // false
console.log(obj1.hasOwnProperty("hasOwnProperty")); // false
即使属性的值是 null
或 undefined
,只要属性存在,hasOwnProperty
依旧会返回 true
。
const o = new Object();
o.propOne = null;
o.propTwo = undefined;
console.log(o.hasOwnProperty("propOne")); // true
console.log(o.hasOwnProperty("propTwo")); // true
5.6、isPrototypeOf
isPrototypeOf
方法用于测试一个对象是否存在于另一个对象的原型链上
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
5.7、Object.getOwnPropertyNames()
Object.getOwnPropertyNames()
返回一个数组,该数组对元素是obj
自身拥有的枚举或不可枚举属性名称字符串。
数组中枚举属性的顺序与通过
for...in
循环和Object.keys
迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。
语法:
obj.getOwnPropertyNames(obj)
- 参数:obj一个对象,其自身的可枚举和不可枚举属性的名称被返回。
- 返回值:在给定对象上找到的自身属性对应的字符串数组。
const arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
// 类数组对象
const obj = { 0: "a", 1: "b", 2: "c" };
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
// 使用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function (val, idx, array) {
console.log(val + " -> " + obj[val]);
});
// 0 -> a
// 1 -> b
// 2 -> c
// 不可枚举属性
const my_obj = Object.create(
{},
{
getFoo: {
value: function () {
return this.foo;
},
enumerable: false,
},
}
);
my_obj.foo = 1;
// 不可枚举属性也会一并输出
console.log(Object.getOwnPropertyNames(my_obj).sort());
// ["foo", "getFoo"]
补充
Object.getOwnPropertyNames和Object.keys的区别:
- Object.keys只适用于可枚举的属性
- Object.getOwnPropertyNames返回对象的全部属性名称(包括不可枚举的)。
"use strict"
(function () {
// 人类的构造函数
const person = function (name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sing = () => {
console.log("sing");
};
};
// new 一个ladygaga
const gaga = new person("ladygaga", 26, "girl");
// 给嘎嘎发放一个不可枚举的身份证
Object.defineProperty(gaga, "id", {
value: "1234567890",
enumerable: false,
});
//查看gaga的个人信息
const arr = Object.getOwnPropertyNames(gaga);
console.log(arr); // name, age, sex, sing, id
// 注意和getOwnPropertyNames的区别,不可枚举的id没有输出
const arr1 = Object.keys(gaga);
console.log(arr1); // name, age, sex, sing
})();
- 如果你只要获取到可枚举属性,可以用Object.keys或用for…in循环(for…in会获取到原型链上的可枚举属性,可以使用hasOwnProperty()方法过滤掉)。
5.8、defineProperty定义对象属性
添加数据属性;
var obj = {};
// 1.添加一个数据属性
Object.defineProperty(obj, "newDataProperty", {
value: 101,
writable: true, // 是否允许修改
enumerable: true, // 是否允许枚举
configurable: true, // 是否允许删除
});
obj.newDataProperty; // 101
// 2.修改数据属性
Object.defineProperty(obj, "newDataProperty", {
writable: false,
});
//添加访问器属性
var obj = {};
Object.defineProperty(obj, "newAccessorProperty", {
set: function (x) {
this.otherProperty = x;
},
get: function () {
return this.otherProperty;
},
enumerable: true,
configurable: true,
});
注意: 1.第一个参数必须为对象
2.descriptor 不能同时具有 (value 或 writable 特性)(get 或 set 特性)。
3.configurable 为false 时,不能重新修改装饰器
5.9、getPrototypeOf: 获取指定对象的原型(内部[[Prototype]]属性的值)
const prototype1 = {};
const object1 = Object.create(prototype1);
console.log(Object.getPrototypeOf(object1) === prototype1); // true
注意:Object.getPrototypeOf(Object) 不是 Object.prototype
Object.getPrototypeOf( Object ) === Function.prototype; // true
5.10、setPrototypeOf 设置一个指定的对象的原型
const obj = { a: 1 },
proto = { b: 2 };
Object.setPrototypeOf(obj, proto);
obj.__proto__ === proto; //true
5.11、Object.is :它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致
Object.is('foo', 'foo') // true
Object.is({}, {}) // false
不同于 === 之处
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
5.12、Object.freeze()和Object.isFrozen()
冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。
let o3 = { a: 1 };
o3.b = 2; //添加属性b成功
Object.freeze(o3);
Object.isFrozen(o3); //true 对象已被冻结
o3.a = 2; //修改属性a值失败
o3.c = 5; //添加属性c失败
delete o3.b; //删除属性b失败
浅冻结与深冻结:
(function () {
obj = {
internal: {},
};
Object.freeze(obj); //浅冻结
obj.internal.a = "aValue";
console.log(obj.internal.a); //"aValue"
//想让一个对象变得完全冻结,冻结所有对象中的对象,可以使用下面的函数.
function deepFreeze(o) {
var prop, propKey;
Object.freeze(o); //首先冻结第一层对象
for (propKey in o) {
prop = o[propKey];
if (
!o.hasOwnProperty(propKey) ||
!(typeof prop === "object") ||
Object.isFrozen(prop)
) {
continue;
}
deepFreeze(prop); //递归
}
}
deepFreeze(obj);
obj.internal.b = "bValue"; //静默失败
console.log(obj.internal.b); //undefined
})();