对象解析,对象基础详解
对象解析,对象基础详解Object.entries() 返回给定对象自身可枚举属性的 [key value] 数组。Object.defineProperties() 给对象添加多个属性并分别指定它们的配置。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) me.name = 'Matthew'; // "name" is a property set on "
创建对象的方式(1)Object 构造函数方式 Object 构造函数将给定的值包装为一个新对象。
- 如果给定的值是 null 或 undefined 它会创建并返回一个空对象。
- 否则, 它将返回一个和给定的值相对应的类型的对象。
- 如果给定值是一个已经存在的对象, 则会返回这个已经存在的值( 相同地址)
let o = new Object()
o.foo = 42
console.log(o)
(2)对象字面量方式
var obj1 = { foo: 'bar' x: 42 };
(3)Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。
如果该参数被指定且不为 undefined,则该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。这些属性对应于 Object.defineProperties() 的第二个参数。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
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)
me.name = 'Matthew'; // "name" is a property set on "me" but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"
对象的静态方法
Object.assign() 通过复制一个或多个对象来创建一个新的对象。
Object.create() 使用指定的原型对象和属性创建一个新对象。
Object.defineProperty() 给对象添加一个属性并指定该属性的配置。
Object.defineProperties() 给对象添加多个属性并分别指定它们的配置。
Object.entries() 返回给定对象自身可枚举属性的 [key value] 数组。
Object.freeze() 冻结对象:其他代码不能删除或更改任何属性。
Object.getOwnPropertyDescriptor() 返回对象指定的属性配置。
Object.getOwnPropertyNames() 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。
Object.getOwnPropertySymbols() 返回一个数组,它包含了指定对象自身所有的符号属性。 Object.getPrototypeOf() 返回指定对象的原型对象。
Object.is() 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
Object.isExtensible() 判断对象是否可扩展。
Object.isFrozen() 判断对象是否已经冻结。
Object.isSealed() 判断对象是否已经密封。
Object.keys() 返回一个包含所有给定对象自身可枚举属性名称的数组。
Object.preventExtensions() 防止对象的任何扩展。
Object.seal() 防止其他代码删除对象的属性。
Object.setPrototypeOf() 设置对象的原型(即内部 [[Prototype]] 属性)。
Object.values() 返回给定对象自身可枚举值的数组。
对象的实例实例属性- Object.prototype.constructor
- 一个引用值,指向 Object 构造函数
- Object.prototype.__proto__
- 指向一个对象,当一个 object 实例化时,使用该对象作为实例化对象的原型
对象属性也可以是一个函数、getter、setter方法。
var o = {
property: function ([parameters]) {} //or property([parameters]) {}
get property() {}
set property(value) {}
};
属性
对象拥有两种属性:数据属性和访问器属性
数据属性数据属性是键值对,并且每个数据属性拥有下列特性:
configurable :当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认值为false
Value: 包含这个属性的数据值。
Writable:如果该值为 false,则该属性的Value 特性不能被修改。
Enumerable : 如果该值为 true,则该属性可以用 for...in 循环来枚举。
let obj = {
foo: 123
};
console.log(Object.getOwnPropertyDescriptor(obj 'foo'))
访问器属性有一个或两个访问器函数(get 和 set)来存取数值。 自定义 Setters和getter
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this 'temperature' {
get: function() {
console.log('get!');
return temperature;
}
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 } { val: 13 }]
可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象
可枚举属性是指那些内部 “可枚举” 标志设置为 true 的属性,对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true 对于通过 Object.defineProperty 等定义的属性,该标识值默认为 false。
var o = {};
Object.defineProperty(o "a" {
value: 1
enumerable: true
});
Object.defineProperty(o "b" {
value: 2
enumerable: false
});
Object.defineProperty(o "c" {
value: 3
}); // enumerable 默认为 false
console.log(o)
for (var i in o) {
console.log(i)
}
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj 'foo')
// {
// value: 123
// writable: true
// enumerable: true
// configurable: true
// }
for ...in
for...in语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
const user = {};
Object.prototype.authenticated = true;
for (var i in user) {
console.log(i)
}
示例2
var obj = {};
obj.name = 'xkx';
obj.age = 18;
obj.run = function() { //创建一个 run()方法并返回值
return this.name this.age '运行中...';
};
// 给原型添加属性和方法
Object.prototype.gaga = function() {
console.log('gaga')
}
Object.prototype.names = 'names'
// 给原型添加一个可枚举的属性
Object.defineProperty(Object.prototype "ages" {
enumerable: false
configurable: false
writable: false
value: 20
});
var descriptor = Object.create(null); // 没有继承的属性
// descriptor.value = 'static';
// // 默认没有 enumerable,没有 configurable,没有 writable
// Object.defineProperty(obj 'key' descriptor);
// console.log(Object.getOwnPropertyDescriptor(obj 'key'))
//显式
Object.defineProperty(obj "key" {
enumerable: false
configurable: false
writable: false
value: "static"
});
console.log(Object.getOwnPropertyDescriptor(obj 'key'))
console.log(obj)
console.log(Object.getPrototypeOf(obj))
for (var i in obj) {
console.log(i)
}
原型上添加的不可枚举的ages属性,没有被枚举
如果将enumerable 改为true 原型上添加的ages 可枚举属性被遍历
Object.defineProperty(Object.prototype "ages" {
enumerable: true
configurable: false
writable: false
value: 20
});
如果对象中不存在指定的属性,Object.defineProperty() 会创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
var o = {}; // 创建一个新对象
// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o "a" {
value : 37
writable : true
enumerable : true
configurable : true
});
getPrototypeOf方法
getPrototypeOf()是JavaScript中的内置函数,用于检查用户创建的对象的原型。大多数时候,它用于检查两个对象是否具有相同的原型。这里的原型是指用户在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)
me.name = 'Matthew'; // "name" is a property set on "me" but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"
console.log(Object.getPrototypeOf(me))
应用场景: (1)完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。
// 写法一
const clone1 = {
__proto__: Object.getPrototypeOf(obj)
...obj
};
// 写法二
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj))
obj
);
// 写法三
const clone3 = Object.create(
Object.getPrototypeOf(obj)
Object.getOwnPropertyDescriptors(obj)
)
getOwnPropertyDescriptor 方法
Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj 'foo')
// {
// value: 123
// writable: true
// enumerable: true
// configurable: true
// }
console.log(Object.getOwnPropertyDescriptor(Object.prototype 'toString').enumerable)
console.log(Object.getOwnPropertyDescriptor(Object.prototype 'ages').enumerable)
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
Object.keys(obj)Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
var obj = {};
obj.name = 'xkx';
obj.age = 18;
obj.run = function() { //创建一个 run()方法并返回值
return this.name this.age '运行中...';
};
// 给原型添加属性和方法
Object.prototype.gaga = function() {
console.log('gaga')
}
Object.prototype.names = 'names'
// 给原型添加一个可枚举的属性
Object.defineProperty(Object.prototype "ages" {
enumerable: true
configurable: false
writable: false
value: 20
});
var descriptor = Object.create(null); // 没有继承的属性
// descriptor.value = 'static';
// // 默认没有 enumerable,没有 configurable,没有 writable
// Object.defineProperty(obj 'key' descriptor);
// console.log(Object.getOwnPropertyDescriptor(obj 'key'))
//显式
Object.defineProperty(obj "key" {
enumerable: true
configurable: false
writable: false
value: "static"
});
// console.log(Object.getOwnPropertyDescriptor(obj 'key'))
// console.log(obj)
// console.log(Object.getPrototypeOf(obj))
// console.log(Object.getOwnPropertyDescriptor(Object.prototype 'toString').enumerable)
// console.log(Object.getOwnPropertyDescriptor(Object.prototype 'ages').enumerable)
// 查看对象原型上toString
console.log(Object.getOwnPropertyDescriptor(Object.prototype 'toString'))
// 修改前
console.log(obj.toString())
// 原型链方式修改
Object.prototype.toString = function() {
return '修改了toString方法'
}
// defineProperty方式修改
// Object.defineProperty(Object.prototype 'toString' {
// value: '.........'
// })
// 修改后
console.log(obj.toString())
// 修改 重写 对象原型上的toString 方法
// console.log(Object.getOwnPropertyDescriptor(Object.prototype 'toString').enumerable)
for (var i in obj) {
console.log(i)
}
console.log(Object.keys(obj))
可以发现原型上的属性并没有被枚举出来
常用方法(1) 怎样判断某个对象是否为另一个对象的原型对象 使用Object.prototype.constructor.prototype进行比较
var obj1 = {name: "李雷"};
var obj2 = {age: 23};
obj1.constructor.prototype === Object.prototype; // true
(2)使用: Object.prototype.isPrototypeOf()进行比较
var obj1 = {name: "Lilei"};
var obj2 = Object.create(obj1);
obj1.isPrototypeOf(obj2); // true
(3)扩展属性 ECMAScript 提案(第 3 阶段)的剩余/扩展属性将扩展属性添加到对象字面量。它将自己提供的对象的枚举属性复制到一个新的对象上。
使用比Object.assign()更短的语法,可以轻松克隆(不包括原型)或合并对象。
var obj1 = { foo: 'bar' x: 42 };
var obj2 = { foo: 'baz' y: 13 };
var clonedObj = { ...obj1 };
// Object { foo: "bar" x: 42 }
var mergedObj = { ...obj1 ...obj2 };
// Object { foo: "baz" x: 42 y: 13 }
(4)hasOwnProperty 继承的属性不显示
var triangle = {a: 1 b: 2 c: 3};
function ColoredTriangle() {
this.color = 'red';
}
ColoredTriangle.prototype = triangle;
var obj = new ColoredTriangle();
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
}
// Output:
// "obj.color = red"
(4)Object.create(null)生生的对象里面没有任何属性,非常“空”,我们称它为字典,这种字典对象适合存放数据,不必担心原型带来的副作用。
bject.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
关于 _proto和 prototype
而构造函数的prototype是什么,它的原型链最终又指向了哪里呢?这个问题的答案是:函数的prototype是一个在函数声明阶段就会产生的对象(prototype只有函数才会有),这个对象只有两个属性constructor和__proto__,其中__proto__指向了我们原型链的顶点Object.prototype。constructor指向函数本身,里面包括了函数一些基本描述信息比如函数名称,参数个数等。
有意思的是constructor里面即有__proto__又有prototype,他们之间有什么关系和差别呢?首先prototype描述的是原型对象,它是一个实实在在的对象,__proto__是用来描述对象间的关联关系的。最终会指向一个prototype原型。函数由Function衍生而来,所以函数的__proto__指向的是Function.prototype。Function是由Object衍生而来,有意思的事情又发生了,Function的__proto__却并不指向Object.prototype 而是指向Function.prototype这个标准的内置对象。Function.prototype.__proto__才是指向我们的原型链顶点Object.prototype
Function.proto === Function.prototype // true