乐趣区

关于前端:对象定义解构枚举属性遍历以及对象内函数

属性名表达式

定义对象的属性有两种形式
1、间接应用标识符作为属性名 obj.name
2、以表达式作为属性名 obj['a'+'b'] = 10

let obj = {}
obj.name = '孙悟空'  // 孙悟空
obj['a' + 'b'] = 10  // 10
console.log(obj); // {name: '孙悟空', ab: 10}

es5中字面量定义对象只能应用一种办法

var obj2 = {name:'西方',age:10}

es6容许应用表达式属性名,将表达式放入 方括号 内即可

let key = 'address'
let obj3 = {
     name:'不败',
     [key] : '武汉',
     ['a'+'ge'] : 100
   }
console.log(obj3);  // {name: '不败', address: '武汉', age: 100}
console.log(obj3.address);  // 武汉
console.log(obj3[key]);  // 武汉

表达式还能够定义方法名

let obj4 = {['f'+'n'](){console.log('hello');
         },
     fn2 : function(){ console.log('word') }
   }
obj4.fn() // hello
obj4.fn2()  // word

留神:解构与属性名表达式不能同时应用

// 报错
let fan = 'name'
let tion = {[fan] }

属性名表达式如果是 对象,会被转换成字符串[object object]

let o = {a : 1}
let o2 = {b : 2}

let obj5 = {[o] : '东方不败',
      [o2] : '东方求败'
   }
console.log(obj5);   // {[object Object]: '东方求败'}

因为属性名表达式都被转换为[object Object],同键名的会被笼罩,所以这里只输入最初一个{[object Object]: '东方求败'}


name 属性

函数的 name 属性返回函数名,对象办法也是函数,因而也有 name 属性

let n = {sayHi(){console.log('hello');}
   }
console.log(n.sayHi.name);   // sayHi

如果对象的办法应用了取值函数:getter或存值函数 setter,那么的属性在形容对象的getset身上,须要在办法名前假 getset

let n2 = {get fn(){},
      set fn(x){}}
let desc = Object.getOwnPropertyDescriptor(n2,'fn')
console.log(desc.get.name);  // get fn
console.log(desc.set.name);  // set fn
console.log(n2.fn.name);  // 报错 Cannot read properties of undefined (reading 'name')

如果对象的办法是一个 Symbol 值,name属性返回的是 Symbol 值的形容

let key1 = Symbol('desc')
let key2 = Symbol()
let kobj = {[key1](){},
     [key2](){}
  }
console.log(kobj[key1].name);  // [desc]
console.log(kobj[key2].name);  // ""

key1有形容,返回形容 [desc]key2 没有值,返回空


属性的可枚举性和遍历

对象的每个属性都存在一个形容对象,用来管制该属性的行为
获取属性形容对象的办法:Object.getOwnPropertyDescriptor()

let d = {a : 123}
console.log(Object.getOwnPropertyDescriptor(d,'a'));
//{value: 123, writable: true, enumerable: true, configurable: true}
我的项目 value
enumerable true为可枚举,false为不可枚举
configurable true为则此个性可被删除也可被批改,false 则 不能够
writable true为能够被批改,false为只可读
留神 用“罕用的形式”创立一个属性时,它们默认都为true

上面四个操作会疏忽 enumerablefalse属性
1、for...in 循环:只遍历对象本身的和继承的可枚举属性
2、Object.keys():返回对象本身的所有可枚举的属性的键名
3、JSON.stringify():只串行化对象本身的可枚举属性
4、Object.assign():疏忽enumerablefalse的属性,只拷贝对象本身的可枚举属性。

其中 for...in 会返回继承的属性,其它的几个都会疏忽继承的属性
如果枚举属性为 false,这四个办法遍历时会疏忽为false 的属性


对象遍历办法

办法 阐明
for…in 循环遍历对象本身和继承的可枚举属性(不含 Symbol)
Object.keys 返回一个数组,该数组为对象本身的所有可枚举属性(不含继承属性和 Symbol 属性)
Object.values() 返回一个数组,蕴含对象键值的数组(不含继承属性和 Symbol 属性)
Object.entries() 返回一个数组,蕴含对象键名和键值的数组(不含继承属性和 Symbol 属性)
Object.getOwnPropertyNames 返回一个数组,蕴含对象本身的所有(蕴含不可枚举)属性(不含 Symbol 属性)
Object.getOwnPropertySymbols 返回一个数组,只蕴含对象本身的所有 Symbol 属性的键名
Reflect.ownKeys 返回一个数组,蕴含对象本身的(不含继承)所有键名,(含 Symbol、字符串、不可枚举属性)

上面是这些遍历办法的演示
定义对象

 let s = Symbol('sym')  // Symbol 类型
 let f = {a:1, b:2, c:3, d:4, e:5, [s]:6}

for…in

for (k in f) {
    // 键名
    console.log(k);  // a b c d e
    // 属性
    console.log(f[k]); // 1 2 3 4 5
}

Object.keys 返回对象键名数组

console.log(Object.keys(f));  // ['a', 'b', 'c', 'd', 'e']
Object.keys(f).forEach(el => console.log(el))  // a b c d e

Object.values 返回对象键值的数组

console.log(Object.values(f));  // [1 , 2 , 3 , 4 , 5]
Object.values(f).forEach(el => console.log(el))  // 1 2 3 4 5

Object.entries 返回对象键名和键值的数组

console.log(Object.entries(f));  // [['a',[1]] , ['b',[2]] , ['c',[3]] , ['d',[4]] , ['a',[5]] ]
Object.entries(f).forEach(el => console.log(el))  // ['a',[1]] ['b',[2]] ['c',[3]] ['d',[4]] ['a',[5]]

Object.getOwnPropertyNames

console.log(Object.getOwnPropertyNames(f));  // ['a', 'b', 'c', 'd', 'e']

Object.getOwnPropertySymbols

console.log(Object.getOwnPropertySymbols(f));  // [Symbol(sym)]

Reflect.ownKeys

console.log(Reflect.ownKeys(f));  // ['a', 'b', 'c', 'd', 'e', Symbol(sym)]

留神:Symbol 是不可枚举的

 let desc2 = Object.getOwnPropertyDescriptor(f,s)
 console.log(desc2); // {value: 6, writable: true, enumerable: true, configurable: true}
 // 在这里返回的是 enumerable:true,返回的是对象的枚举属性,并不是 Symbol
 // Symbol 是不可枚举的,所以 keys 遍历中没有 Symbol

解构赋值和残余运算符

解构:能够依据对象的键名间接获取到键值,十分不便

let {a,b,...z} = {a:1, b:2, c:3, d:4, e:5}
console.log(a,b,z);  // 1 2 {c: 3, d: 4, e: 5}
let info = {
    id:1,
    name:'东方不败'
 }
let {id ,name} = info
console.log(id,name);  // 1 '东方不败'

// 重命名
let {id ,name : user} = info
console.log(id,user);  // 1 '东方不败'

解构赋值能够嵌套

  • 单层嵌套

    let infos = {
      vals : 1,
      users: {names : '东方不败'}
    }
    let {vals ,users:{names} } = infos
    console.log(names);  // 东方不败
  • 多层嵌套

    let info2 = {
      val:1,
      user:{
          id2:100,
          name2:'东方不败',
          address:{
              city:'武汉',
              district : '世界城广场'
          }
      }
    }
    let {val,user:{id2,name2,address:{city,district}} } = info2
    console.log(val,id2,name2,city,district);  // 1 100 '东方不败' '武汉' '世界城广场'

    对象的残余运算符能够将字符串转换成 键值对 的对象,键名默认从数字 0 开始,顺次排列

console.log({...'world'});  // {0: 'w', 1: 'o', 2: 'r', 3: 'l', 4: 'd'}

对象的残余运算符相当于是 Object.assign(),但这两个是 不相等

let r = {id : 1, name:'西方', text:'不败'}
let res = {...r}
let res2 = Object.assign({},r)
console.log(res);  // {id: 1, name: '西方', text: '不败'}
console.log(res2); // {id: 1, name: '西方', text: '不败'}
console.log(res == res2);  // false

残余运算符拼接,反复的键名会被笼罩

let r2 = {a:1 , b:2 , c:3 , d:4}
let r3 = {c:6,d:7,e:8,f:9}
console.log({...r2,...r3});  // {a: 1, b: 2, c: 6, d: 7, e: 8,f: 9}

对象内函数

对象内不仅能够定义一般的数据类型如:字符串、数字、数组,还能够 定义函数 ,对象内函数的行为跟一般函数雷同,一般函数和箭头函数在对象内都能够定义,函数的调用形式: 对象名. 办法

let fn = {
   title:'东方不败',
   sayHi(){console.log('hello')},
   getSum(x){return x % 2 == 0 ? true : false},
   getNum : s = (x) => x + 1
}

console.log(fn.title); // 东方不败
fn.sayHi()  // hello
console.log(fn.getSum(3)); // false
console.log(fn.getSum(4)); // true
console.log(fn.getNum(1)); // 2

Object.keys()能够遍历对象键名数组,对象内的函数会返回函数名

Object.keys(fn).forEach(el=> console.log(el))  // title sayHi getSum getNum

对象内函数的 this

对象内函数的 this 指向问题跟一般函数有一些不同

对象内函数:
一般函数:this指向的是对象自身,也就是以后对象内的所有属性和办法。
箭头函数:this指向为window,因为对象不形成独自的作用域,导致箭头函数定义时的作用域是全局作用域。

window.val = '东方求败'
let fn2 = {
    name : '艺术概论',
    inThis(){ console.log(this.val)},  // 一般函数
    inThis2(){console.log(this.name)
        console.log(this);
     },  // 一般函数
     inThis3 : t = () => {console.log(this.val)
        console.log(this);
        const t2 = () => {console.log(this);
        }
    }  // 箭头函数
}

// 一般函数
function getThis2(){console.log(this.val);
 }
 getThis2()  // 东方求败
 fn2.inThis()  // undefined
 fn2.inThis2() // 艺术概论  // {name: '艺术概论', inThis: ƒ, inThis2: ƒ}
 fn2.inThis3() // 东方求败  // Window {window: Window, self: Window, document: document, name: '', location: Location, …}

这里别离在对象内定义了 一般函数 箭头函数
inThis() 输入的是 undefined,因为对象内并没有val 这个属性,this.val没有找到,返回 undefined
inThis2() 输入的是 艺术概论 this.name 就是以后对象内的 name,对象内的一般函数this 指向的是以后对象
inThis3() 为箭头函数,输入 东方求败 ,对象内的箭头函数this 指向的是window


案例源码:https://gitee.com/wang_fan_w/es6-science-institute

如果感觉这篇文章对你有帮忙,欢送点亮一下 star 哟

退出移动版