目录
创建对象
Object.create()
原型
原型操作
原型污染
对象属性
属性特征
枚举属性
Object.keys()
Object.getOwnPropertyNames()
Object.getOwnPropertyDescriptor()
Object.definePeoperty()
Object.definePeoperties()
访问器属性
getter和setter属性
属性访问错误
检测属性
新增方法
Object.is
Object.assign
创建对象
Object.create()
使用Object.create()方法创建一个新对象
// obj1继承了属性x和y。
let obj1 = Object.create({ x: 1, y: 2 });
//obj2是一个普通的空对象。
let obj2 = Object.create(Object.prototype);
//obj3不继承任何属性和方法。
let obj3 = Object.create(null);
Object.create(新对象的原型,新对象的属性描述符)
const animal = {eat() {console.log("Eating...");},
};
const dog = Object.create(animal, {name: { value: "Doggie" },bark: {value: function () {console.log("Barking...");},},
});
dog.eat();
dog.bark();
//输出
//Eating...
//Barking...
原型
每一个JavaScript对象都和原型对象相关联。(每一个对象都从原型继承属性。)
所有通过对象字面量创建的对象都具有同一个原型对象。
通过new和构造函数创建的对象的原型就是构造函数的prototype属性引用的对象。
new Array()对象的原型就是Array.prototype,又继承Object.prototype。
let obj = { value: 100 };
Object.prototype.flag = "head";
console.log(obj.flag);
let arr = [1, 2, 3, 4];
console.log(arr.flag);
//输出
//head
//head
原型操作
Object.getPrototypeOf(对象):查询对象的原型
Object.setPrototypeOf(对象,新的原型对象):为对象重新指定原型对象
obj1.isPrototypeOf(obj2):检测对象obj2是否是对象obj1的原型(obj1是否在obj2的原型链上)
原型污染
修改JavaScript对象的原型链,从而影响所有基于该原型的对象行为。
防御措施:
使用Object.create(null)
创建无原型对象;
避免使用__proto__
,改用Object.getPrototypeOf()
和Object.setPrototypeOf()。
对象属性
数据属性:对象属性可以是任意JavaScript值。
属性特征
每个数据属性之间还有一些与之相关的值。
- 可写:是否可以设置属性值
- 可枚举:是否可以通过for/in结构返回该属性
- 可配置:是否可以删除或修改该属性
枚举属性
for/in循环可以在循环体中遍历对象中所有可枚举的属性(包括自身属性和继承属性)
let o = Object.create({ m: 10, n: 20 });
o.x = 1;
o.y = 2;
o.z = 3;
for (let p in o) {console.log(p, o[p]);
}
//输出
//x 1
//y 2
//z 3
//m 10
//n 20
Object.keys()
返回一个数组。这个数组由对象中可枚举的自有属性的名称组成。
let o = Object.create({ m: 10, n: 20 });
o.x = 1; o.y = 2; o.z = 3;
console.log(Object.keys(o));
//输出
//[ 'x', 'y', 'z' ]
Object.getOwnPropertyNames()
返回对象的所有自有属性的名称
let o = Object.create({ m: 10, n: 20 });
o.x = 1;
o.y = 2;
o.z = 3;
console.log(Object.getOwnPropertyNames(o));
//输出
//[ 'x', 'y', 'z' ]
Object.getOwnPropertyDescriptor()
可以获得某个对象特定属性的属性描述符。
console.log(Object.getOwnPropertyDescriptor(circle, "r"));
//{value: 9.549296585513721,writable: true,enumerable: true,configurable: true}
Object.definePeoperty()
传入要修改的对象、要床架或修改的属性的名称以及属性描述符对象。
- 第一个参数:传入要修改的对象
- 第二个参数:要创建或修改的属性的名称
- 第三个参数:属性描述符对象
let o = {};
Object.defineProperty(o, "x", {value: 10,writable: true,enumerable: false,configurable: false,
});
console.log(o.x, Object.keys(o));//10 []
value(属性值),writable(可写性),enumerable(可枚举性),configurable(可配置性)
传入Object.defineProperty()的属性描述符对象不必包含所有4个特性。
Object.definePeoperties()
同时修改或创建多个属性。
- 第一个参数:要修改的对象
- 第二个参数:映射表(包含要新建或者修改的属性名称,以及属性的描述)
let p = Object.defineProperties({},{x: { value: 1, writable: true, enumerable: true, configurable: true },y: { value: 1, writable: true, enumerable: true, configurable: true },r: {get: function () {return Math.hypot(this.x, this.y);},enumerable: true,configurable: true,},}
);
console.log(p);//{ x: 1, y: 1, r: [Getter] }
访问器属性
属性可以是一个getter或setter函数。
可写性是由setter方法是否存在决定的。
存取器属性的4个特性是读取(get)、写入(set)、可枚举性和可配置性。
getter和setter属性
getter的返回值就是属性存取表达式的值。
setter负责“设置”属性值。
let circle = {r: 10,get round() {return 2 * this.r * Math.PI;},set round(v) {this.r = v / 2 / Math.PI;},get area() {return Math.PI * this.r ** 2;},
};
console.log(circle.round, circle.area);//62.83185307179586 314.1592653589793
circle.round = 60;
console.log(circle.r, circle.area);//9.549296585513721 286.47889756541167let circle1 = Object.create(circle);
circle1.r = 20;
console.log(circle1.round);//125.66370614359172
circle1.round = 500;
console.log(circle1.r, circle1.area);//79.57747154594767 19894.367886486918
和数据属性一样,存取器属性是可以继承的。
属性访问错误
查询一个不存在的属性并不会报错,返回undefined。
如果对象不存在,查询这个不存在的对象 的属性就会报错。
let one = {};
// let one = { two: { three: 3 } };
console.log(one.two.three);//报错
if (one) {
if (one.two) {
if (one.two.three) console.log(one.two.three);
}
}
console.log(one && one.two && one.two.three);
console.log(one?.two?.three); // Null传导运算符
检测属性
检查属性的方法:
- in字符串
- hasOwnPreperty()
- properlylsEnumerable()
let o = { x: 1 };
console.log("x" in o);//true
console.log("y" in o);//false
console.log("toString" in o);//true
console.log(o.hasOwnProperty("x"));//true
console.log(o.hasOwnProperty("y"));//false
console.log(o.hasOwnProperty("toString"));//false
console.log(o.propertyIsEnumerable("x"));//true
console.log(o.propertyIsEnumerable("y"));//false
console.log(o.propertyIsEnumerable("toString"));//false
console.log(Object.prototype.propertyIsEnumerable("toString"));//false
Object.prototype 包含一个 toString 方法,所以即使对象 o 自身没有定义 toString,in 操作符也会沿着原型链查找到 Object.prototype.toString。
新增方法
Object.is
比较两个值是否相等,返回一个布尔值。
console.log(Object.is(1, 2)); // false
console.log(Object.is(1, "1"), 1 == "1", 1 === "1"); // false true false
console.log(Object.is(NaN, NaN), NaN == NaN, NaN === NaN); // false true false
console.log(Object.is(0, -0), 0 == -0, 0 === -0); // false true true
console.log(Object.is(+0, -0)); // false
console.log(Object.is(+0, 0)); // true
Object.assign
将所有可枚举的自身属性从一个或多个源对象复制到目标对象,返回目标对象。(对象的深层复制)
const symbolTag = Symbol("is object");
const defaults = {color: "red",size: "10px",[symbolTag]: "configuration",
};
const options = {color: "blue",opacity: 0.5,
};
const merged = Object.assign({}, defaults, options);
console.log(defaults);
//{ color: 'red', size: '10px', [Symbol(is object)]: 'configuration' }
console.log(options);
//{ color: 'blue', opacity: 0.5 }
console.log(merged);
//{ color: 'blue', size: '10px', opacity: 0.5, [Symbol(is object)]: 'configuration' }
Object.assign()方法不会直接递归对象,如果对象的属性值是一个对象,则会直接复制该对象的引用,而不会复制该对象的属性。
const symbolTag = Symbol("is object");
const defaults = {color: "red",size: "10px",[symbolTag]: "configuration",
};
const options = {color: "blue",opacity: 0.5,
};
const merged = Object.assign({}, defaults, options);
const options2 = {color: "blue",opacity: 0.5,position: { x: 10, y: 20 },
};
const merged2 = Object.assign({}, defaults, options2);
console.log(merged2);
//{
// color: 'blue',
// size: '10px',
// opacity: 0.5,
// position: { x: 10, y: 20 },
// [Symbol(is object)]: 'configuration'
//}
console.log(merged2.position === options2.position);
//true