目录
1. 理解对象
1.1 属性的类型
ESMA-262 使用一些内部特性来描述属性的特征。 这些特性是由为JavaScript实现引擎的规范定义的, 因此, 开发者不能再JavaScript 中直接访问这些特性。
为了将某个特性标识为内部特性,规范会用两个中括号把特性的名称括起来, 比如 [[Enumerable]]
。
ECMAScript 中将属性分为了两种:
- 数据属性
- 访问器属性
1.1.1 数据属性 CEWV
数据属性包含了一个保存数据值的位置。 值会从这个位置读取,也会写入到这个位置。 数据属性有四个特性描述它们的行为。
[[Configurable]]
:- 属性是否可以通过
delete
删除并重新定义; - 是否可以修改它的特性;
- 是否可以把它改为 访问器属性
- 默认值为
true
- 属性是否可以通过
[[Enumerable]]
:- 属性是否可以通过
for-in
循环返回。 - 默认值为
true
- 属性是否可以通过
[[Writable]]
:- 属性的值是否可以被修改;
- 默认值为
true
[[Value]]
:- 属性实际的值
- 默认值为
undefined
当我们创建一个对象时,如:
let person = {
name: "Nicholas"
};
属性name
的数据属性 [[Configurable]]
、[[Enumerable]]
、[[Writable]]
都会被设置为 true
, 而 [[Value]]
特性会被设置为指定的值,即 "Nicholas"
。
1.1.1.2 修改与访问 数据属性
1.1.1.2.1 修改属性的默认特性
Object
有两个静态方法用于修改 数据属性:
Object.defineProperty()
Object.defineProperties()
Object.defineProperty()
该方法用于修改对象单个值的数据属性,其语法格式如下:
Object.defineProperty(属性的对象,属性的名称,描述符对象({CEWV}))
示例:
let person = {};
Object.defineProperty(person, "name", {
Writable: false,
value: "Nicholas"
});
console.log(person.name); // "Nicholas"
person.name = "Greg";
console.log(person.name); // "Nicholas"
⚠️ 严格模式下,尝试修改只读属性的值会抛出错误。
let person = {};
Object.defineProperty(person, "name", {
configurable: false,
value: "Nicholas"
});
console.log(person.name); // "Nicholas"
delete person.name;
console.log(person.name); // "Nicholas"
⚠️ 尝试删除
[[Configurable]]
为false
的值在严格模式下会抛出错误
一旦某个属性被设定了 [[Configurable]]
值为false
以后, 该值将会被定义为不可配置, 也不能在变回可配置了。 也就是说,此时,如果再次调用Object.defineProperty()
并修改任何非 writable 属性还会导致错误。也无法被改变了。
⚠️此外,在调用Object.defineProperty()
时, 如果不指定configurable
, enumerable
和 writable
值,则全部默认为 false
。
let obj = { };
Object.defineProperty(obj, "name",{value:'jayce'});
let a = Object.getOwnPropertyDescriptors(obj)
console.log(a);//{ name: { value: 'jayce',writable: false,enumerable: false,configurable: false } }
注意: 如果已经有初始化值,则初始化时,数据属性已经被设定了默认值,都为true
// 注意: 如果已经有初始化值,则初始化时,数据属性已经被设定了默认值,都为true
let obj = { name:'frank' };
Object.defineProperty(obj, "name",{value:'jayce'});
let a = Object.getOwnPropertyDescriptors(obj)
console.log(a);// { name: { value: 'jayce',writable: true,enumerable: true,configurable: true } }
Object.defineProperties()
Object.defineProperties()
用于批量修改默认数据属性,其语法格式如下:
Object.defineProperties(obj,props)
示例:
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
});
1.1.1.2.2 访问数据属性
Object
提供了两个数据属性的访问方法,分别是:
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptor()
用于获取单个对象值数据属性, 而Object.getOwnPropertyDescriptors()
则用于获取对象中所有值的数据属性。
示例:
let obj = { name:'frank',age:18,height:'175cm' };
Object.defineProperty(obj, "name",{value:'jayce'});
let res1 = Object.getOwnPropertyDescriptor(obj,'name')
let res2 = Object.getOwnPropertyDescriptors(obj)
console.log(res1);
/*
{ value: 'jayce',
writable: true,
enumerable: true,
configurable: true }
*/
console.log(res2);
/* { name:
{ value: 'jayce',
writable: true,
enumerable: true,
configurable: true },
age:
{ value: 18,
writable: true,
enumerable: true,
configurable: true },
height:
{ value: '175cm',
writable: true,
enumerable: true,
configurable: true } }
*/
1.1.2 访问器属性
访问器属性不包含数据值。
访问器属性有4个特性描述它们的行为:
[[Configurable]]
: 表示属性是否可以通过delete
删除并重新定义, 是否可以修改它的特性, 以及是否可以把它改为数据属性。 默认值为true
[[Enumerable]]
: 表示属性是否可以通过fot-in
循环返回。 默认值为true
[[Get]]
:获取函数, 在读取属性时调用。 默认值为undefined
[[Set]]
: 设置函数, 在写入属性时调用。默认值为undefined
访问器属性是不能直接定义的, 必须使用Object.defineProperty()
。
// 定义一个对象, 包含伪私有成员 year_ 和公共成员 edition
let book = {
year_: 2017,
edition: 1
};
Object.defineProperty(book,"year",{
get(){
return this.year_;
},
set(newValue){
if(newValue > 2017) {
this.year_ = newValue;
this.edition += newValue - 2017;
}
}
});
book.year = 2018;
console.log(book.edition); // 2
这个例子中 对象 book 有两个默认属性 : year_
和 edition
。 year_
中的下划线常用来表示该属性并不希望在对象方法的外部被访问。 另一个属性 year
被定义为一个访问器属性, 其中获取函数简单地返回year_
的值, 而设置函数会做一些计算以决定正确的版本(edition)。 因此,把year
属性修改为 2018 会导致 year_
变成 2018, edition 变成2。 这是访问器属性的典型使用场景, 即设置一个属性值会导致一些其他变化发生。
获取函数 和 设置函数 不一定都要定义。只定义获取函数 —— 属性只读。只定义设置函数——不可读取
1.1.3 合并对象 —— Object.assign()
ES6 提供了 Object.assign()
方法用于对象合并, 这个方法接收一个目标对象,和一个或者多个源对象作为参数, 然后对每个源对象执行浅复制, 如果多个源对象有相同的属性, 则使用最后一个复制的值。用例:
let dest = { id: 'dest' };
let result = Object.assign(dest,{ id: 'src1', a:'foo'}, { id :'src2',b:'bar'});
console.log(result);//{id: 'src2', a: 'foo', b: 'bar'}
注意:实际的逻辑实现是,将每个源对象中可枚举(
Object.propertyIsEnumerable()
返回true
) 和 自有(Object.hasOwnProperty()
返回true
) 的属性复制到目标对象。 以字符串和符号为键的属性会被复制。 对每个符合条件的属性,这个方法会使用源对象上的 [[Get]] 取得属性的值,然后使用目标对象上的 [[Set]] 设置属性的值。
1.1.4 对象标识与相等判定 —— Object.is()
ES6 之前,===
对有一些结果的判定在不同的js引擎中表现不一样, ES6 中, 规范新增了一个统一方法, 考虑了一些边界情形,输出正常判定:
如:
console.log(+0 === -0);// true
console.log(+0 === 0);// true
console.log(-0 === 0);// true
console.log(Object.is(+0,-0));// false
console.log(Object.is(+0,0));// true
console.log(Object.is(0,0));// false
1.1.5 增强的对象语法
-
属性值简写
给对象添加变量是,属性名和以变量作为属性值的变量名如果是一样的,可以直接简写:
let name = 'Matt'; let person = { name: name } // 可以简写为: let name = 'Matt'; let person = { name };
-
可计算属性
ES6 之前,对象的key 只能是字符串形式,现在可以使用变量,动态的访问和设定
const nameKey = 'name'; const ageKey = 'age'; const jobKey = 'job'; let person = { [nameKey]:'Matt'; [ageKey]:27; [jobKey]:'Software Engineer' }
标签:console,log,对象,理解,原型,构造函数,name From: https://www.cnblogs.com/jaycethanks/p/17365963.html