沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • javascript 面试题汇总
  • let、var、const的区别

    • let、var、const的区别
  • 值和引用

    • 值和引用
  • 包装类型

    • 包装类型
  • 数据类型的转换

    • 数据类型的转换
  • 运算符

    • 运算符
  • 原型和原型链

    • 原型和原型链
  • 执行栈和执行上下文

    • 执行栈和执行上下文
  • 作用域和作用域链

    • 作用域和作用域链
  • this指向

    • this指向
  • 垃圾回收与内存泄漏

    • 垃圾回收与内存泄漏
  • 闭包

    • 闭包
  • DOM事件的注册和移除

    • DOM 事件的注册和移除
  • DOM事件的传播机制

    • DOM 事件的传播机制
  • 阻止事件的默认行为

    • 阻止事件默认行为
  • 递归

    • 递归
  • 属性描述符

    • 属性描述符
      • 经典真题
      • 属性描述符详解
        • 属性描述符的结构
        • get 和 set 函数
        • 操作属性描述符
        • 控制对象状态
      • 真题解答
  • Class和普通构造器的区别

    • class 和构造函数区别
  • 浮点数精度问题

    • 浮点数精度问题
  • 严格模式

    • 严格模式
  • 函数防抖和节流

    • 函数防抖和节流
  • WeakSet和WeakMap

    • WeakSet 和 WeakMap
  • 深浅拷贝

    • 深浅拷贝
  • 函数柯里化

    • 函数柯里化
  • Node的事件循环

    • Node的事件循环
  • eval

    • eval
  • 尺寸和位置

    • 尺寸和位置
  • 更多知识

    • 更多知识
  • JS面试题汇总
  • 属性描述符
luzhichang
2023-10-14
目录

属性描述符

# 属性描述符

# 经典真题

  • JavaScript 中对象的属性描述符有哪些?分别有什么作用?

# 属性描述符详解

在 JavaScript 中,对象的属性可以分为两种:

  • 数据属性:它的本质就是一个数据

  • 存取器属性:它的本质是一个函数,但是可以将它当作普通属性来使用,当给该属性赋值时,会运行相应的 setter 函数,当获取该属性的值时,会运行相应的 getter 函数。除了存取器,还有一些其他的关键字,用以表示当前属性是否可写、是否有默认值、是否可枚举等,这些关键字就是属性描述符。

属性描述符是 ECMAScript 5 新增的语法,它其实就是一个内部对象,用来描述对象的属性的特性。

# 属性描述符的结构

在定义对象、定义属性时,我们曾经介绍过属性描述符,属性描述符实际上就是一个对象。

属性描述符一共有 6 个,可以选择使用。

  • value:设置属性值,默认值为 undefined。
  • writable:设置属性值是否可写,默认值为 true。
  • enumerable:设置属性是否可枚举,即是否允许使用 for/in 语句或 Object.keys( ) 函数遍历访问,默认为 true。
  • configurable:设置是否可设置属性特性,默认为 true。如果为 false,将无法删除该属性,不能够修改属性值,也不能修改属性的属性描述符。
  • get:取值函数,默认为 undefined。
  • set:存值函数,默认为 undefined。

注意这几个属性不是都可以一起设置,具体如下图:

image-20211021111647398

示例 1

下面示例演示了使用 value 读写属性值的基本用法。

var obj = {};  //定义空对象
Object.defineProperty(obj, 'x', {value : 100});  //添加属性x,值为100
console.log(Object.getOwnPropertyDescriptor(obj, 'x').value);  //返回100

示例 2

下面示例演示了使用 writable 属性禁止修改属性 x。

var obj = {};
Object.defineProperty(obj, 'x', {
    value : 1,  //设置属性默认值为1
    writable : false  //禁止修改属性值
});
obj.x = 2;  //修改属性x的值
console.log(obj.x);  // 1 说明修改失败

在正常模式下,如果 writable 为 false,重写属性值不会报错,但是操作失败,而在严格模式下则会抛出异常。

示例 3

configurable 可以禁止修改属性描述符,当其值为 false 时,value、writable、enumerable 和 configurable 禁止修改,同时禁止删除属性。

在下面示例中,当设置属性 x 禁止修改配置后,下面操作都是不允许的,其中 obj.x=5; 若操作失败,则后面 4 个操作方法都将抛出异常。

var obj = Object.defineProperty({}, 'x', {
    configurable : false  // 禁止配置
});
obj.x = 5;  //试图修改其值
console.log(obj.x);  //修改失败,返回undefined
Object.defineProperty(obj, 'x', {value : 2});  //抛出异常
Object.defineProperty(obj, 'x', {writable: true});  //抛出异常
Object.defineProperty(obj, 'x', {enumerable: true});  //抛出异常
Object.defineProperty(obj, 'x', {configurable: true});  //抛出异常

当 configurable 为 false 时,如果把 writable=true 改为 false 是允许的。只要 writable 或 configurable 有一个为 true,则 value 也允许修改。

# get 和 set 函数

除了使用点语法或中括号语法访问属性的 value 外,还可以使用访问器,包括 set 和 get 两个函数。

其中,set( ) 函数可以设置 value 属性值,而 get( ) 函数可以读取 value 属性值。

借助访问器,可以为属性的 value 设计高级功能,如禁用部分特性、设计访问条件、利用内部变量或属性进行数据处理等。

示例 1

下面示例设计对象 obj 的 x 属性值必须为数字。为属性 x 定义了 get 和 set 特性,obj.x 取值时,就会调用 get;赋值时,就会调用 set。

var obj = Object.create(Object.prototype, {
    _x : {  //数据属性
        value : 1,  //初始值
        writable : true
    },
    x : {  //访问器属性
        get : function () {  //getter
            return this._x;  //返回_x属性值
        },
        set : function (value) {  //setter
            if (typeof value != "number"){
              throw new Error('请输入数字');
            }
            this._x = value;  //赋值
        }
    }
});
console.log(obj.x);  //1
obj.x = "2";  //抛出异常

示例 2

JavaScript 也支持一种简写方法。针对示例 1,通过以下方式可以快速定义属性。

var obj = {
    _x : 1,  // 定义 _x 属性
    get x() { return this._x },  //定义 x 属性的 getter
    set x(value) {  //定义 x 属性的 setter
        if (typeof value != "number"){
          throw new Error('请输入数字');
        }
        this._x = value;  // 赋值
    }
};
console.log(obj.x);  //1
obj.x = 2;
console.log(obj.x);  //2

取值函数 get( ) 不能接收参数,存值函数 set( ) 只能接收一个参数,用于设置属性的值。

# 操作属性描述符

属性描述符是一个内部对象,无法直接读写,可以通过下面几个函数进行操作。

  • Object.getOwnPropertyDescriptor( ):可以读出指定对象私有属性的属性描述符。
  • Object.defineProperty( ):通过定义属性描述符来定义或修改一个属性,然后返回修改后的描述符。
  • Object.defineProperties( ):可以同时定义多个属性描述符。
  • Object.getOwnPropertyNames( ):获取对象的所有私有属性。
  • Object.keys( ):获取对象的所有本地可枚举的属性。
  • propertyIsEnumerable( ):对象实例方法,直接调用,判断指定的属性是否可枚举。

示例 1

在下面示例中,定义 obj 的 x 属性允许配置特性,然后使用 Object.getOwnPropertyDescriptor( ) 函数获取对象 obj 的 x 属性的属性描述符。修改属性描述符的 set 函数,重设检测条件,允许非数值型数字赋值。

var obj = Object.create(Object.prototype, {
    _x: {  //数据属性
        value: 1,  //初始值
        writable: true
    },
    x: {  //访问器属性
        configurable: true,  //允许修改配置
        get: function () {  //getter
            return this._x;  //返回_x属性值
        },
        set: function (value) {
            if (typeof value != "number") {
                throw new Error('请输入数字');
            }
            this._x = value;  //赋值
        }
    }
});
var des = Object.getOwnPropertyDescriptor(obj, "x");  //获取属性x的属性描述符
des.set = function (value) {
    //修改属性x的属性描述符set函数
    //允许非数值型的数字,也可以进行赋值
    if (typeof value != "number" && isNaN(value * 1)) {
        throw new Error('请输入数字');
    }
    this._x = value;
}
obj = Object.defineProperty(obj, "x", des);
console.log(obj.x);  //1
obj.x = "2";  //把一个给数值型数字赋值给属性x
console.log(obj.x);  //2

示例 2

下面示例先定义一个扩展函数,使用它可以把一个对象包含的属性以及丰富的信息复制给另一个对象。

【实现代码】

function extend (toObj, fromObj) {  //扩展对象
    for (var property in fromObj) {  //遍历对象属性
        if (!fromObj.hasOwnProperty(property)) continue;  //过滤掉继承属性
        Object.defineProperty(  //复制完整的属性信息
            toObj,  //目标对象
            property,  //私有属性
            Object.getOwnPropertyDescriptor(fromObj, property)  //获取属性描述符
        );
    }
    return toObj;  //返回目标对象
}

【应用代码】

var obj = {};  //新建对象
obj.x = 1;  //定义对象属性
extend(obj, { get y() { return 2} })  //定义读取器对象
console.log(obj.y);  //2

# 控制对象状态

JavaScript 提供了 3 种方法,用来精确控制一个对象的读写状态,防止对象被改变。

  • Object.preventExtensions:阻止为对象添加新的属性。
  • Object.seal:阻止为对象添加新的属性,同时也无法删除旧属性。等价于属性描述符的 configurable 属性设为 false。注意,该方法不影响修改某个属性的值。
  • Object.freeze:阻止为一个对象添加新属性、删除旧属性、修改属性值。

同时提供了 3 个对应的辅助检查函数,简单说明如下:

  • Object.isExtensible:检查一个对象是否允许添加新的属性。
  • Object.isSealed:检查一个对象是否使用了 Object.seal 方法。
  • Object.isFrozen:检查一个对象是否使用了 Object.freeze 方法。

示例

下面代码分别使用 Object.preventExtensions、Object.seal 和 Object.freeze 函数控制对象的状态,然后再使用 Object.isExtensible、Object.isSealed 和 Object.isFrozen 函数检测对象的状态。

var obj1 = {};
console.log(Object.isExtensible(obj1));  //true
Object.preventExtensions(obj1);
console.log(Object.isExtensible(obj1));  //false
var obj2 = {};
console.log(Object.isSealed(obj2));  //true
Object.seal(obj2);
console.log(Object.isSealed(obj2));  //false
var obj3 = {};
console.log(Object.isFrozen(obj3));  //true
Object.freeze(obj3);
console.log(Object.isFrozen(obj3));  //false

# 真题解答

  • JavaScript 中对象的属性描述符有哪些?分别有什么作用?

参考答案:

属性描述符一共有 6 个,可以选择使用。

  • value:设置属性值,默认值为 undefined。
  • writable:设置属性值是否可写,默认值为 true。
  • enumerable:设置属性是否可枚举,即是否允许使用 for/in 语句或 Object.keys( ) 函数遍历访问,默认为 true。
  • configurable:设置是否可设置属性特性,默认为 true。如果为 false,将无法删除该属性,不能够修改属性值,也不能修改属性的属性描述符。
  • get:取值函数,默认为 undefined。
  • set:存值函数,默认为 undefined。

使用属性描述符的时候,get 和 set 以及 value 和 writable 这两组是互斥的,设置了 get 和 set 就不能设置 value 和 writable,反之设置了 value 和 writable 也就不可以设置 get 和 set。

-EOF-

递归
class 和构造函数区别

← 递归 class 和构造函数区别→

Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式