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 条评论
登录 后参与评论

相关文章

  • 行为型模式之策略模式

    在讲解策略模式之前,我们了解下行为型设计模式。那么行为型是什么意思呢?主要场景是什么呢?

    RobinsonZhang
  • 前端面试题分享001

    解释 :要注意的是函数中的this与运行环境强相关,与定义环境不相关。所以下面的代码段中,当直接通过对象属性方法中去调用时,其都可以访问到对象的属性,但是当其变...

    RobinsonZhang
  • react进阶之render props

    Render props作为共享组件逻辑的一种有效模式,此模式借助state和辅助参数,可以提供ui的更好的灵活性。

    RobinsonZhang
  • 【Rust每周一知】 Attribute 属性

    Rust 中的属性数量非常多。而且具有可扩展性(可自定义属性)。Rust 的属性语法遵从 C# 定义并标准化了的属性规范ECMA-334。

    MikeLoveRust
  • Workbook工作簿对象属性

    Activeworkbook.name表示当前活动工作簿的name属性,即当前excel文件的名称为vba.xlsm。

    无言之月
  • 前端入门10-JavaScript语法之对象声明正文-对象

    作为一个前端小白,入门跟着这几个来源学习,感谢作者的分享,在其基础上,通过自己的理解,梳理出的知识点,或许有遗漏,或许有些理解是错误的,如有发现,欢迎指点下。

    请叫我大苏
  • 前端基础-CSS属性选择器

    cwl_java
  • [UWP]依赖属性1:概述

    依赖属性(DependencyProperty)是UWP的核心概念,它是有DependencyObject提供的一种特殊的属性。由于UWP的几乎所有UI元素都是...

    dino.c
  • 18.Swift学习之属性与方法

    YungFan
  • 达观数据前端分享:理解 JavaScript 中的对象的属性

    在达观数据的前端工作中,对象的属性是经常接触和使用的,正好最近重温了一下《JavaScript 高级程序设计》,把书中理解对象属性的部分整理一下与大家分享。 ...

    达观数据

扫码关注云+社区

领取腾讯云代金券