JS之理解对象

过完中秋就变懒了,这几天看了看图解算法有点小收获。又赶上去去上海听泽野弘之的演奏会,所以这边的更新就慢了下来,这几天把他补上。

理解对象

创建自定义对象的最简单的方式就是创建一个Object实例

1
2
3
4
5
6
7
let person = {
name: 'xnnnnn',
age: 22,
sayName: function() {
console.log(this.name)
}
}

对象有两种属性:数据属性和访问器属性

数据属性

数据属性包含一个数据值的位置(Value)。在这个位置能读取和写入值。有四个描述其行为的特性。

Configurable

表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。

Enumerable

表示能否通过for-in 循环属性的特性。

Writable

表示能否修改属性的值。

Value

包含这个属性的数据值。读取属性值的时候,把新值保存在这个位置。这个特性默认为undefined。


对于上面那个的那个定义对象的方式,Configurable、Enumerable 都被设置成了 true,Value被设置成了指定的值。


要修改属性的特性必须使用Object.defineProperty()。

Object.defineProperty()

这个方法接受三个参数:属性所在的对象、属性的名字、和一个描述对象。其中,描述符对象属性必须是:configurable、enumberable、writable和value。设置其中的一个或者多个,可以修改队形的特性值。

1
2
3
4
5
6
7
8
let person = {};
Object.defineProperty(person, 'name',{
writable: false,
value: 'xnnnnn'
})
console.log(person.name) // xnnnnn
person.name = 'boy'
console.log(person.name) // xnnnnn ,因为通过Object.defineProperty把 writable 设置成了fasle所以这个不能修改

这两天复习ES6又补充了点新知识,本想开个ES6笔记的坑然后看见之前有关于对象的笔记,索性就写在这里。

Object.is()

用途基本上和 ‘===’相同,但是在 +0与-0、NaN与Nan的判断上有些出入

1
2
3
4
console.log(+0 === -0) // true
console.log(Object.is(+0,-0)) // false
console.log(NaN === NaN) // false
console.log(Object.is(NaN, NaN)) // true

Object.assign(target,…source)

用途:深拷贝,拷贝可枚举属性给目标对象。
注意点:属性限定简单类型。同名的属性会被覆盖(调用target的set和source的get)。

ES6里Object的属性顺序规则

具体规则: 数字key > 其他key(按照设置的先后顺序排列)
1
2
3
4
5
6
7
8
let obj = {
v: '111',
a: '222',
1: 'aaa',
b: '233',
0: '999'
}
console.log(obj) // {0: "999", 1: "aaa", v: "111", a: "222", b: "233"}

可枚举性和遍历

对象的每个属性都有一个描述对象。用来控制该属性的行为。Object.getOwnPropertyDescriptor(object, ‘attributes’) 能获取到行为的描述对象。

1
2
3
4
5
6
7
8
9
10
let temp = {
name: 'xnnnnn'
}
console.log(Object.getOwnPropertyDescriptor(temp, 'name'))
// {
// value: "xnnnnn", //属性对应的value
// writable: true, // 是否可被赋值运算符改变
// enumerable: true, // 是否可枚举
// configurable: true // 此描述对象是否能修改
// }

可遍历对象可枚举的方法有(忽略enumberable为 false的):

  • for…in 遍历继承和自身的可枚举属性。

  • JSON.Stringfy() 字符串化可枚举的属性

  • Object.keys() 返回自身可枚举的键名

  • Object.assign() 只能拷贝自身的可枚举属性
    其中for…in会遍历继承过来的属性,而其他三个不会

    属性的遍历

    • for…in
      遍历继承和自身的可枚举属性不包括symbol
    • Object.keys()
      遍历自身可枚举属性的键值,返回一个数组。
    • Object.getOwnPropertyNames()
      遍历自身所有的属性(不包括symbol属性,包括不可枚举属性),返回一个数组。
    • Object.getOwnPropertySymbol()
      遍历自身的所有symbol属性的键名,返回一个数组。
    • Reflect.ownKeys()
      遍历自身的所有属性(包括symbol属性和不可枚举属性)的键名,返回一个数组。

对象的解构

1
2
let { b, a, ...c } = { a: 1, b: 2, c: 3, d: 4 }
console.log(a, b, c) // 1 2 {c: 3, d: 4}
  • 备注:在上面的例子 b、a 属于解构赋值,能赋值继承过来的属性。…c属于扩展运算符的解构赋值不能复制继承过来的属性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const proto = {
    foo: 'hello',
    xx: 'xnnnnn'
    };

    const obj = {
    foo: 'world',
    find() {
    return super.foo;
    }
    };

    Object.setPrototypeOf(obj, proto);
    for(let item in obj){console.log(item)}

    let {a, xx}= obj //解构赋值
    console.log(xx) //"xnnnnn"
    let {a,...xx} = obj // 扩展运算符解构赋值
    console.log(xx) // {foo: "world", find: ƒ}
  • 解释:左右侧得有相同的属性名才会成功赋值,’…c’这种形式的会赋值右侧对象里可枚举的属性,但尚未读取的属性。

  • 注意:解构赋值要求等号右面是个对象,还是浅拷贝。 右侧是null或者undefined会报错。 且 …c ,也要放在参数的最后。不然会报语法错误。

super

指向当前对象的原型对象。
注意:super表示原型对象时,只能用在对象的方法里。用在其他地方会报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let superObj = {
name: 'xnnnn',
getName(){
console.log(this.name)
}
}

let obj = {
name: 'who?',
getName(){
console.log(super.name)
}
}
Object.setPrototypeOf(obj, superObj) // 设置原型对象
obj.getName() // xnnnnn

链判断运算符

直接上代码好理解

1
2
3
4
5
let name = request?.data?.name ?? 'xnnnn' //attr
let getFunction = person?.getName() // function
function a () {
return 'xnnnnnnnnn'
}

以上两个是从顶部判断属性是否存在,request?代表request是否存在,?? 是||的代替符,||在值是false或者0的时候会返回右侧值。而??(null判断运算符)只对null和undefined返回右侧值。

  • 注意: 1. ??和其他运算符(|| &&)是必须用括号圈起来表示优先级,否则会报错。
    2. 关于?的语法问题: new a?.(),  a?.`{b}`,  super?.(),  a?.b = c,   构造函数,右侧有模板字符串,左侧是 super,用于赋值运算符左侧都会报错

感谢您的阅读。 🙏