前端如何定义一个常量
栏目: JavaScript · 发布时间: 5年前
内容简介:很多编程语言提供了为什么会这样?实际上,
很多编程语言提供了 const
关键词声明一个常量,在ES6中也是提供了 const
,但是在前端的 const
与其他编程语言不同,其并不意味着声明的变量就是一个常量。使用 const b = {}
声明了一个常量b,但是通过使用 b.a = 1
去修改对象b却并没有报错,我们修改了一个原本以为是常量实际上是变量的对象。
为什么会这样?
实际上, const
定义的变量保存的是指向实际数据的指针,对于基本数据类型 String、Boolean、Number、undefined、null、Symbol
而言,
其值保存在栈内存中的简单数据段,按值访问,就是等同于常量。但是相对于引用数据类型而言, const
只能保证指向保存在堆内存中的对象的指针保持不变,换句话说 const
能够保证变量始终指向同一个对象,至于对象的修改无能为力。
所以,在前端中到底如何实现一个常量!
Object.freeze
Object.freeze
可以冻结对象,不能新增和删除属性,同时对象已有属性都是不可枚举、不可配置、不可写。需要注意的是使用该方法只能让对象浅冻结,其内部属性为对象时
依然能够被篡改,要想实现完全冻结,那么就需要进行如下操作。
function deepConst(data){ Object.freeze(data); for(let key in data){ let prop = data[key]; if(!data.hasOwnProperty(key) || !(typeof prop === "object") || Object.isFrozen(prop)){ continue; } deepConst(prop); } } 复制代码
Object.defineProperty、Object.preventExtensions、Object.seal
Object.preventExtensions
该方法可以将对象变为不可扩展即对象即不能添加新的属性,但是对象的原有属性依然可以被删除或修改,同时如果属性的值为对象,尽管设置了 不能被添加属性,但是其属性值为对象的属性依旧可以添加属性。
举个例子:
let obj = {a:1,b:2,c:{d:3}}; Object.preventExtensions(obj); obj.d = 1; obj.a = 2; delete obj.b; obj.c.e = 10; //输出{a:1,c:{d:3,e:10} console.log(obj); 复制代码
Object.seal
与 Object.preventExtensions
相比,该方法同样能够将对象变为不能添加新属性,并且该方法禁止删除对象的属性。同样如果属性的值为对象,
属性值依旧可以添加新属性或删除属性。
举个例子
let obj = {a:1,b:2,c:{d:3}}; Object.seal(obj); obj.e = 10; delete obj.a; delete obj.c.d; obj.c.f = 10; //输出{a:1,b:2,c:{f:10} console.log(obj); 复制代码
Object.defineProperty
Object.defineProperty(obj, prop, descriptor)
在MVVM中大放异彩,使用其也能够将将对象完整冻结。在写代码之前我们
先了解下 writable、Configurable
需要知道都内容,这才是此次冻结的关键。
writable
对象属性的值是否能够被重写,为true表示允许,为false即被禁止,默认为false。如果属性的值为对象, 尽管设置了不能被重写,其属性为对象的值依旧能够被重写。
举个例子:
let obj = {a:1,b:2,c:{d:3}}; Object.defineProperty(obj,"a",{writable:true}); Object.defineProperty(obj,"b",{writable:false}); Object.defineProperty(obj,"c",{writable:false}); Object.defineProperty(obj,"e",{writable:false}); obj.a = 2; obj.b = 3; obj.c.d = 4; //输出为2,即a属性的值被重写了 console.log(obj.a); //输出依然为2,即b属性的值没有被重写 console.log(obj.b); //输出依然为{d:4},如果属性的值为对象,尽管设置了不能被重写,其属性为对象的值依旧能够被重写。 console.log(obj.c); 复制代码
Configurable
configurable
特性表示对象的属性是否可以被删除,以及除 writable
特性外的其他特性是否可以被修改。为true表示允许被修改
false表示禁止修改,默认为false,如果属性的值为对象,尽管设置了属性不能被修改,其属性为对象的属性依旧能够被修改。
举个例子
let obj = {a:1,b:2,c:{d:3}}; Object.defineProperty(obj,"a",{configurable:true}); Object.defineProperty(obj,"b",{configurable:false}); Object.defineProperty(obj,"c",{configurable:false}); delete obj.a; delete obj.b; delete obj.c; //输出 {b:2,c:{}},如果属性的值为对象,尽管设置了属性不能被修改,其属性为对象的属性依旧能够被修改。 console.log(obj); 复制代码
上面这三个方法单独拿出来并不能够完美的将对象变为一个常量,但是我们组合一下就可以生成一个常量。
function deepConst(data){ if (!data || typeof data !== 'object') { return; } //Object.preventExtensions(data);也可以实现 Object.seal(data); Object.keys(data).forEach(function(key) { unWriteConfig(data, key, data[key]); }); } function unWriteConfig(data, key, val) { deepConst(val); Object.defineProperty(data, key, { writable:false, configurable:false }); } 复制代码
Proxy
Proxy
在目标对象之前进行了一层拦截,外界对对象的访问和修改都需要通过这层拦截,所以我们可以操控拦截来控制对对象对访问和修改。 Proxy
支持的拦截操作众多,下面只列举与文章相关的操作,如果想更深入了解 Proxy
, 请看这篇文章
。
function createDeepProxy(target) { function makeHandler() { return { set(target, key, value, receiver) { return false; }, deleteProperty(target, key) { return false; } } } function proxify(obj, path) { for(let key of Object.keys(obj)) { if(typeof obj[key] === 'object') { obj[key] = proxify(obj[key], [...path, key]); } } let p = new Proxy(obj, makeHandler()); return p; } return proxify(target, []); } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
编程珠玑(英文版・第2版)
[美] Jon Bentley / 人民邮电出版社 / 2010-8 / 39.00元
多年以来,当程序员们推选出最心爱的计算机图书时,《编程珠玑》总是位列前列。正如自然界里珍珠出自细沙对牡蛎的磨砺,计算机科学大师Jon Bentley以其独有的洞察力和创造力,从磨砺程序员的实际问题中凝结出一篇篇不朽的编程“珠玑”。这些文章是《ACM通讯》最受欢迎的专栏文章,最终结集为两部书出版。本书为第一卷,主要讨论计算机科学中最本质的问题:如何正确选择和高效地实现算法。 在书中,作者选取许......一起来看看 《编程珠玑(英文版・第2版)》 这本书的介绍吧!