js对象属性

前言

相信对于对象属性大家都或多或少的知道一些,那么本文从属性说开去,看看大家对属性的了解是否有遗漏的部分。

属性的定义与使用

也许你觉得定义属性很简单啊,我直接.prop = xxx,就可以定义个对象了啊,从未深入了解,这在大多数情况下没有任何问题。但在某些情况下就不够用了。

我们知道的使用方式是这样的:

let param = {
id:'',
number:13
}
param.query = 'sfwefw'
param['say']= () => {
console.log(111)
}
console.log(param.number)

那么我们先追本溯源看下对象定义属性官方的玩法吧。 官方对属性分为两种,一种是数据属性,另一种访问器属性。(这些属性值为了区别于我们理解的普通属性,我们用两对括号体现)

简单表格统计下他们的特征

属性

内容

特征

数据属性

configurable,enumerable,writable,value

其中123均为布尔型,默认为true,分别代表可删除、可枚举、可修改,第四个为true

访问器属性

configurable,enumerable,getter,setter

后面两个是非必须的

虽然似乎说的很明白,但还是一脸懵逼,感觉对自己没什么影响啊。那么干货来了,我通过几个经典的高频点来延伸的帮助大家理解这部分。

for in 循环遍历的属性

作为经常使用对象的我们,想必对这个语法并不陌生,虽然我们一般情况下很少直接这样用,因为更多业务场景下是属性的精准使用,不会通过循环的方式,原因有以下几个方面。当然你可以跳过这部分。

1 如果默认使用属性循环来展示数据,有很多不必要展示的数据都要过滤筛选掉,比较低效麻烦 2 属性的循环访问不一定符合我们需要展示的顺序,这点才是致命的,导致我们在业务需要的时候更多的时候是固定顺序固定访问对象属性 3 如果对对象属性期望按照顺序,会大大的增加数据改造的成本,增加不可复用的解耦成本

回到正文,重头戏来了,作为常识需要了解到两点。

第一点,for in循环可以访问到对象具有的所有可枚举属性; 第二点 对象具有的属性可能是多来源的,可能是自己新建的,可能是构造函数新建的,可能是来源于构造函数的继承;可能是来源于原型,可能是来源于原型式的继承。其中我们可以通过hasOwnProperty来判断这个属性是否是自有属性(构造函数来的是判断不出的)。

构造函数得到的属性以及基本属性赋值

//正常的构造函数以及对象属性赋值,call .apply构造函数继承方式的属性都可以正常获取,并且属于对象自有属性
let Animal = function (){
  this.bigtype = 'animal'
}
let Person = function () {
  this.name = '人类' 
  this.sex = '男女'
  Animal.call(this)
} 
let zhangsan = new Person('zhangsan','male')
zhangsan.type = 'animal'
for(let p in zhangsan){
 console.log(zhangsan.hasOwnProperty(p),`${p}:${zhangsan[p]}`)
}

特别说明:为什么构造函数之后对象的属性都是自有属性呢? 这个要和new关键字有关了,其关键的四个步骤是创建新的对象,然后构造函数的作用域指向新对象(this指向新对象),执行构造函数中的代码,返回新对象。所以自然通过this赋值的都是新对象的属性了。

原型链方法赋值以及原型链继承方式

无论是通过原型修改属性还是原型链继承的其他原型,其均不属于对象自己,均是向上追溯的原型对象的,所以hasOwnProperty均为false.

需要注意的是 :1 如果你需要继承其他原型,又需要修改原型的某个值,要先继承在修改值,不然你修改的值就丢失了。2 继承原型要在实例化对象之前,写在调用之前是无效的。

let Animal = function (){
  this.bigtype = 'animal'
}
let Person = function () {
  this.name = '人类' 
  this.sex = '男女'
  // Animal.call(this)
} 
Person.prototype = new Animal()
Person.prototype.belong = 'zhang'
let zhangsan = new Person('zhangsan','male')
for(let p in zhangsan){
 console.log(zhangsan.hasOwnProperty(p),`${p}:${zhangsan[p]}`)
}

参考代码

还什么方法可以拿到属性

没错,我们一般情况下使用for,in循环获取属性,但有些属性我们也希望得到。通过上面的for in的例子,你可以通过for in +hasOwnProperty 的方式得到对象可枚举非原型属性以及可枚举原型属性。那么还有其他方法么?肯定有的。下面进行表格说明。

方法

内容

备注

for in

可枚举,自身以及继承属性

对象以及继承,可枚举,不含 Symbol 属性

Object.keys(obj)

返回一个数组,包括对象自身的(不含继承的)所有可枚举属性键名

对象自身可枚举,不含 Symbol 属性

Object.getOwnPropertyNames(obj)

返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名

对象自身,包括不可枚举属性

Object.getOwnPropertySymbols(obj)

返回一个数组,包含对象自身的所有 Symbol 属性的键名

对象自身,symbol

Reflect.ownKeys(obj)

返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

对象自身,全部属性

属性中的this是什么

来源

指向

对象

对象自身

构造函数

返回新对象

原型

原型

纯函数调用

外部环境全局,浏览器或者node

访问器get,set使用

一般我们也用不到这个,但vue的数据双向绑定就是基于这个实现的,其在data属性中定义的数据,全部对其属性的属性定义中追加了虚拟dom的事件,所以能够实现双向绑定。也正因为这个属性的兼容问题,导致了vue不支持ie低版本哦。

参考源码vue框架使用get,set源码地址

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏静晴轩

类数组借用数组方法

于JavaScript如何将对象转化为数组对象,其用法写法已经很常见且完善,比如JQuery中的makeArray函数对此的实现,也是跟大家想的差不多,只是考虑...

3399
来自专栏GIS讲堂

面向对象的三个基本特征

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

1913
来自专栏jessetalks

Javascript基础回顾 之(一) 类型

  本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Jav...

3777
来自专栏前端吧啦吧啦

涨薪必备Javascript,快点放进小口袋!

3137
来自专栏java学习

重要通知!小编出新的Java练习题咯!!

正确答案 3月5号公布 一、选择题和问答题 1、在一个java原文件中,import, class, package语句的顺序是( )。 A. import ...

4425
来自专栏大神带我来搬砖

程序员的职业素养真是完全靠不住的东西

这里面<T extends Comparable<? super T>>有什么用?

491
来自专栏有趣的Python

1-Java面向对象-面向对象

通过前面的学习我们对于java的语法结构有了一定的认识,掌握了分支结构,循环结构等常用的程序逻辑,也能运用这些知识解决一些简单问题。

2861
来自专栏xx_Cc的学习总结专栏

iOS-正则表达式的简单使用

4247
来自专栏趣谈编程

Unicode与UTF-8的区别

要弄清Unicode与UTF-8的关系,我们还得从他们的来源说起,下来我们从刚开始的编码说起,直到Unicode的出现,我们就会感觉到他们之间的关系

1282
来自专栏前端儿

表达式求值(1)

Dr.Kong设计的机器人卡多掌握了加减法运算以后,最近又学会了一些简单的函数求值,比如,它知道函数min(20,23)的值是20 ,add(10,98) 的值...

1862

扫码关注云+社区

领取腾讯云代金券