• 浅谈在ES5环境下实现const


    最近看到一个面试题——用ES5实现const。作为JS初学者的笔者知道在ES6中有const命令,可以用来声明常量,一旦声明,常量的值就不可改变。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const Pi = 3.1415;
    Pi
    Pi = 3;
    // TypeError: Assignment to constant variable.

    const foo = {};
    // 为 foo 添加一个属性,可以成功
    foo.prop = 123;
    foo.prop // 123
    // 将 foo 指向另一个对象,就会报错
    foo = {}; // TypeError: "foo" is read-only

    但是让我困惑的是,怎么才能使用ES5来实现const呢?说到这里我就想起了下半年···中美合拍···两开花···啊不对!!是想起了最近在学习Vue框架,而Vue在实现响应式原理时使用到了Object.defineProperty()方法,该方法可以定义对象属性的数据描述符,比如configurable、writable、enumerable等等,通过这些描述符就可以设置对象属性是否可读可写可配置可枚举,进而就可以实现类似定义常量的功能。

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。语法如下:

    Object.defineProperty(obj, prop, descriptor)

    其中descriptor代表将被定义或修改的属性描述符。属性描述符有两种主要形式:数据描述符存取描述符。本文只讨论数据描述符,数据描述符有以下选项:

    • configurable

      当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false

    • enumerable

      当且仅当该属性的enumerabletrue时,该属性才能够出现在对象的枚举属性中。默认为 false

    • value

      该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined

    • writable

      当且仅当该属性的writabletrue时,value才能被赋值运算符改变。默认为 false

    此时我们设想,当我们讲对象属性中的writable设为false的时候,该属性是只读的,就能满足我们对常量的要求了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var _const = {};
    Object.defineProperty(_const, "A", {
    value: 1,
    writable: false, //设置属性只读
    configurable: true,
    enumerable: true
    });
    console.log(_const.A); //1
    _const.A = 2; //在严格模式下会抛错,在非严格模式下静默失败,修改无效。

    但此时,我们只要修改属性的数据描述符来修改属性值,依然可以对属性值进行修改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var _const = {};
    Object.defineProperty(_const, "A", {
    value: 1,
    writable: false,
    configurable: true,
    enumerable: true
    });

    Object.defineProperty(_const, "A", {
    value: 2,
    writable: true,
    configurable: true,
    enumerable: true
    });
    console.log(_const.A); < 大专栏  浅谈在ES5环境下实现constspan class="comment">//2
    _const.A = 3;
    console.log(_const.A); //3

    如此我们就需要将configurable设置为false,这样属性就不可配置了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var _const = {};
    Object.defineProperty(_const, "A", {
    value: 1,
    writable: false,
    configurable: false,
    enumerable: true
    });
    console.log(_const.A) //1
    _const.A = 2; //Cannot redefine property: A
    Object.defineProperty(_const, "A", {
    value: 2,
    writable: true,
    configurable: true,
    enumerable: true
    }); //报错!属性不可配置

    但是configurable特性表示对象的属性是否可以被删除,以及除writable特性外的其他特性是否可以被修改。所以writable特性依旧可以修改,仅限于由true改为false,不能由false改为true。并且value值的设置也不会应此受到影响,则会出现下述情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var _const = {};
    Object.defineProperty(_const, "A", {
    value: 1,
    writable: true,
    configurable: false,
    enumerable: true
    });
    console.log(_const.A); //1
    Object.defineProperty(_const, "A", {
    value: 2, //该属性不受configurable的影响
    writable: false,
    configurable: false,
    enumerable: true
    });
    console.log(_const.A); //2
    _const.A = 3;
    console.log(_const.A); //2 修改无效

    因此,通过Object.defineProperty() 方法,使用属性的数据描述符,可以定义一个命名空间,将常量封装在命名空间里面。由于属性描述符默认为false,所以可以这样定义:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var _const = {};
    Object.defineProperty(_const, "A", {
    value: 1,
    enumerable: true
    });
    Object.defineProperty(_const, "B", {
    value: 2,
    enumerable: true
    });

    参考链接:

    1.JavaScript 常量定义

    2.Object.defineProperty()

    3.ECMAScript 6 入门-阮一峰

  • 相关阅读:
    java基础16 捕获、抛出以、自定义异常和 finally 块(以及关键字:throw 、throws)
    java基础15 内部类(成员内部类、局部内部类)和匿名内部类
    java基础14 多态(及关键字:instanceof)
    java基础13 接口(及关键字:interface、implements)
    Java 线程控制
    Java 多线程创建和线程状态
    Java New IO
    Java IO流
    Java 集合和泛型
    Java 动态代理
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12230949.html
Copyright © 2020-2023  润新知