👨‍💻
Hong's 前端笔记
  • 🌈About
  • JavaScript
    • 作用域
    • 闭包
    • this
      • bind()
    • 原型
      • Object.create()
      • 模拟“类”
      • ES6 Class
      • Function
    • 对象
    • 类型 & 值
      • 原生函数
      • 数组
      • 字符串
    • 异步
    • JavaScript 相关概念
      • Event Loop 事件循环
      • Prototype 原型
      • Context 执行上下文
      • this
      • Promise
    • JavaScript 常见问题
      • 手写实现
      • 看代码输出
  • React
    • 核心概念
    • 深入理解
      • State
      • 如何管理 State
      • React 渲染过程
      • 处理 DOM 事件
      • Pure 组件
      • Context
      • Key 属性
      • React.lazy()
      • Render Props
    • Hooks
      • useState
      • useRef
      • useEffect
        • Some details
      • 相关概念
      • 自定义 Hook
      • useEffect vs useLayoutEffect
    • React 相关问题
      • Class vs Function
  • React Libraries
    • Redux
      • Quick Start
      • 如何持久化 Redux 数据
      • 异步操作
      • 性能优化
      • Dive into immutability
    • Route v6
      • Quick Start
  • Reactivity
    • Immer
  • Vue
    • 深入理解
      • Composition vs Options
      • Reactivity
  • Network
    • Cookies
    • HTTP
    • HTTPS
    • CORS 跨域资源共享
    • 认证手段
    • 安全相关
    • 网络相关知识
  • Browser
    • DOM 操作
    • Events 事件
    • XHR & Fetch
    • 性能优化
    • HTML 相关概念
    • 浏览器相关概念
  • CSS
    • 盒模型
    • Layout 布局
    • Styles 样式
    • CSS 相关概念
    • CSS 相关技巧
      • 移动端适配
      • Flex
      • 动画
  • TypeScript
    • Quick Peek
    • Types in TypeScript
    • Narrowing
    • Functions in TypeScript
  • Workflow
    • Webpack
      • Webpack 概念
      • 资源管理
      • 管理输出
      • 开发环境配置
      • 生产环境配置
      • 优化代码运行性能
  • Others
    • 小程序与原生 Web 的区别
  • SSO
    • About
    • API Doc
    • 接入指南
Powered by GitBook
On this page
  • 属性描述符
  • writable
  • enumerable
  • configurable
  • 不可变性质
  • [[Gget]] & [[Put]]
  • getter && setter
  • 存在性
  • 遍历
  • for ... in
Edit on GitHub
  1. JavaScript

对象

属性描述符

通过 Object.getOwnPropertyDescriptor() 可以查看对象的某一属性的属性描述符

var obj = {
    a: 0
}

Object.getOwnPropertyDescriptor(obj, 'a')

可以查看到 obj.a 的属性描述符:

{
    value: 0,
    writable: true,
    enumerable: true,
    configurable: true
}

相应的,我们也可以使用 Object.defineProperty() 来设置对象的属性

writable

决定是否可以修改属性的值。如果设置为 false ,在非严格模式下修改会被静默处理;而在严格模式下会抛出 TypeError 异常

var obj = {}

Object.defineProperty(obj, 'a', {
    value: 0,
    writable: false
})

obj.a = 1 // 非严格模式下被静默处理

obj.a     // 0

enumerable

决定属性能否出现在对象的属性枚举中,如 for ... in 循环。如果设置为 false 你仍然可以访问到该属性,只是它不会出现在枚举中。

configurable

如果为 true ,那么就可以使用 Object.defineProperty() 来修改(重新覆盖)对象的属性,不管是否处于严格模式下。

也就是说,先用 Object.defineProperty() 将某一个属性的 configurable 设置为 false 后,再次对该属性使用 Object.defineProperty() 来尝试修改则会抛出 TypeError 异常。

也就是说,这是一次单向操作

如果一个属性的 configurable 为 false ,那么你也不能用 delete 来删除该属性(不过修改他的值还是可以的):

var obj = {}

Object.defineProperty(obj, 'a', {
    value: 0,
    configurable: false
})

// 非严格模式下静默,严格模式下抛出 TypeError 异常
delete obj.a

obj.a   // 0

不可变性质

如果想要对象中的某个属性或者对象自己是不可变的,可以通过以下方式实现:

  1. 将 writable 和 configuable 设为 false

  2. 使用 Object.preventExtenstions() 可以禁止一个对象扩展(不能添加新属性)

  3. 使用 Object.seal() 可以使对象不可扩展,并且所有属性的 configuable 都设为 false(但是仍然可以修改值)

  4. 使用 Object.freeze() 相当于在 Object.seal() 的基础上再把所有的属性的 writable 也设为 false ,这样对象不可扩展、不可配置、不可写。

所有的不可变性修改,都是浅不可变性;对于引用类型,并不能真正的冻结住他们。

[[Gget]] & [[Put]]

对一个对象的属性访问时,其实会在该对象上实现了 [[Get]] 操作;相应的,设置一个对象时,也会对该对象实现 [[Put]] 操作

需要注意的是,和 RHS 不同的是,对一个对象中不存在的属性访问时,并不会抛出 ReferrenceError ,而是返回 undefined

var obj = {}

a        // ReferenceError,RHS 错误

obj.a    // undefined

getter && setter

可以使用字面量或者 Object.defineProperty() 来设置属性的 getter

var obj = {
    get a() {
        return 0
    }
}

Object.defineProperty(obj, 'b', {
    get: function() {
        return 1
    }
})

obj.a	// 0
obj.b	// 1

如果一个属性只有 getter,那么尝试修改该属性时会被忽略(严格模式下抛出 TypeError )

var obj = {
    get a() {
        return 0
    }
}

// 属性设置会被忽略
obj.a = 1

obj.a   // 0

进一步说,即使给属性 a 设置了正确的 setter 再次读取他的时候,仍然返回 0。

这是因为 getter 只会返回 0,因此正确的做法如下:

var obj = {
    get a() {
        return this._a_
    },
    set a(val) {
        this._a_ = val
    }
}

obj.a = 0

obj.a   // 0

仔细思考上述代码 this 的指向,这里应用的是隐式绑定规则

obj.a 其实调用的是函数。在这个函数内部,this 绑定在对象 obj 上

// 查看 obj 对象内,this 指向的就是 obj
obj    // { _a_: 0 }

存在性

前面提到过,不同于 RHS 错误。对于不存在的属性进行访问会返回 undefined ,但是如果该属性虽然存在,但是他的值是 undefined 也会返回相同的结果。

因此可以使用 in 关键字或者 hasOwnProperty() 来判断一个对象是否存在某一属性,然而他们的区别是:

  • in 会向上寻找原型链

  • hasOwnProperty() 只会检查属性是否在该对象上

hasOwnProperty() 是 Object.prototype 上的一个函数。通常情况下,对任意对象 obj ,都可以直接调用 obj.hasOwnProperty()

然而,如果一个对象是通过 Object.create(null) 创建的,那这个对象就不能通过委托在原型链上寻找到 hasOwnProperty() 这一函数。一种解决方法是:

var obj = Object.create(null)

obj.a = 0

Object.prototype.hasOwnProperty.call(obj, 'a') // true

注意 in 操作符并不会检查容器内是否存在某一个值;他只是检测该属性是否存在于对象或原型链上

比如 3 in [1, 2, 3] 并不会返回 true ,因为该数组只有 0, 1, 2 三个属性

遍历

for ... in

使用 for ... in 可以遍历 enumerable 为 true 的属性:

var obj = {
    a: 0,
    b: 1
}

// a 0
// b 1
for (var k in obj) {
    console.log(k, obj[k])
}

Last updated 2 years ago