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

属性名表达式

定义对象的属性有两种形式
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哟

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理