关于ES模块你必须要知道的一些禁忌(一)

栏目: Node.js · 发布时间: 6年前

内容简介:由于Object.preventExtensions()将对象标记为不再可扩展,因此它将永远不会具有超出它被标记为不可扩展的属性。注意,一般来说,不可扩展对象的属性可能仍然可被删除。尝试将新属性添加到不可扩展对象将静默失败或抛出TypeError(在strict mode下) 当我们在严格模式下,尝试对不可拓展的对象进行属性添加时,就会抛出异常,具体代码如下:

ES ModuleJavaScriptES2015 版本开始提供的语言标准级别的模块化方案,在此之前 JavaScript 一直没有语言级别的模块化体系。没有模块化的支持,使用JavaScript开发大型应用将举步维艰,所以经过大量的实践,社区制定了一些模块加载方案,最主要的有运行于浏览器的 AMD 方案和运行于以Nodejs为代表的服务端的 CommonJS 方案。

由于 WebpackBabel 等打包、转义 工具 的出现,开发者已经可以在开发中使用 ES ModuleAMD 已是明日黄花,使用的人越来越少,不太值得去关注。但 CommonJS 方案由于 Nodejs 在前端构建工具和服务端中的普及度,在Nodejs全面支持 ES Module 、老版本Nodejs消亡之前,我们还是要关注 CommonJS 方案以及它与 ES Module 之间的区别,以免搞混、记忆混淆,酿成bug。为了为后面的禁止点做铺垫,先让我们来了解或回顾两个API: Object.preventExtensionsObject.freeze

Object.preventExtensions

Object.preventExtensions()将对象标记为不再可扩展,因此它将永远不会具有超出它被标记为不可扩展的属性。注意,一般来说,不可扩展对象的属性可能仍然可被删除。尝试将新属性添加到不可扩展对象将静默失败或抛出TypeError(在strict mode下) 当我们在严格模式下,尝试对不可拓展的对象进行属性添加时,就会抛出异常,具体代码如下:

"use strict"
var obj = {
    age: 23,
    name: 'rioli',
    city: ['sz', 'jy']
};
Object.preventExtensions(obj);
obj.province = 'GD';
复制代码

运行结果:

Uncaught TypeError: Cannot add property 'province', object is not extensible 
复制代码

Object.freeze

Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。 当我们在严格模式下,尝试对已冻结的对象进行属性修改时,就会抛出异常,具体代码如下:

"use strict"
var obj = {
    age: 23,
    name: 'rioli',
    city: ['sz', 'jy']
};
Object.freeze(obj);
obj.age = 26;
复制代码

运行结果:

Uncaught TypeError: Cannot assign to read only property 'age' of object '#<Object>'
复制代码

构建不可拓展的冻结对象

我们可以利用 Object.preventExtensionsObject.freeze 这两个API来组合构建一个不可拓展的冻结对象,即:不能对对象的顶级属性对象增、删、改等操作。

"use strict"
var obj = {
    age: 23,
    name: 'rioli',
    city: ['sz', 'jy']
};
Object.freeze(obj);
Object.preventExtensions(obj);
// obj.age = 26; 修改顶级属性将引发报错
// obj.province = 'GD';  新增顶级属性将引发报错
// delete obj.name; 删除顶级属性将引发报错
// 但仍然可以修改对象的子对象的属性,因为修改对象的子对象的属性并不会修改子对象的引用,对于引用类型来说等于没有发生值的改变
obj.city[0] = 'zq';
obj.city.push('st');
复制代码

ES Module 禁忌之不可以修改整体导入模块对象的直接属性

为什么会列出这个禁忌,这是因为在 CommonJS 方案中,你是可以修改整体导入模块对象的直接属性的,长期在 CommonJSES Module 中交叉使用,难免会造成不必要的记忆混淆。但是在 ES Module 中,整体导入的模块对象是一个不可拓展的冻结的常量对象,对其直接属性的修改和新增将引发报错。

假定我们正处于 CommonJs 环境下,例如NodeJS中,我们导入等个模块,然后尝试对模块对象的属性进行修改和新增,具体代码如下:

lib.js

exports.time = Date.now();
exports.getCurrrentYear = function () {
    return new Date().getFullYear();
}
exports.people = {
    age: 26,
    name: 'rioli',
    cities: ['jieyang', 'shenzhen']
};
复制代码

main.js

const lib = require('./lib');
const people = lib.people;

const print = (data) => {
    console.log("===================================");
    console.log(data);
};

print(people);
print(lib);

people.age = 999;
print(people);

people.father = 'baba';
print(people);

lib.people = 23;
print(lib);

lib.people.age = 666;
print(lib);

lib.provices = ['GD', 'FJ'];
print(lib);
复制代码

运行结果通过,控制台输出结果如下:

===================================
{ age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ time: 1545274516494,
  getCurrrentYear: [Function],
  people: { age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] } }
===================================
{ age: 999, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ age: 999,
  name: 'rioli',
  cities: [ 'jieyang', 'shenzhen' ],
  father: 'baba' }
===================================
{ time: 1545274516494, getCurrrentYear: [Function], people: 23 }
===================================
{ time: 1545274516494, getCurrrentYear: [Function], people: 23 }
===================================
{ time: 1545274516494,
  getCurrrentYear: [Function],
  people: 23,
  provices: [ 'GD', 'FJ' ] }
复制代码

ES Module 环境下,整体导入的模块对象,但我们对其进行修改和新增属性的时候,其表现和上述利用 Object.preventExtensionsObject.freeze 这两个API来组合构建一个不可拓展的冻结对象的表现一样,即:这个模块对象是一个不可拓展的冻结的常量对象。演示代码如下:

lib.mjs

export const time = Date.now();

export function getCurrrentYear() {
    return new Date().getFullYear();
}

export const people = {
    age: 26,
    name: 'rioli',
    cities: ['jieyang', 'shenzhen']
};
复制代码

main.mjs

import { people } from './lib.mjs';
import * as lib from './lib.mjs';

// 首先定一个基调,其实但我们用 import * as xx from 'yy' 将一个模块做整体导入时,此时xx会作为作为模块命名空间

const print = (data) => {
    console.log("===================================");
    console.log(data);
};

print(people);
print(lib);

// 允许修改
people.age = 999;
print(people);

// 允许修改
people.father = 'baba';
print(people);

// 不允许修改,因为作为整体导入时,模块对象的直接一级属性是只读属性,修改将引发报错
try {
    lib.people = 23;
    print(lib);
} catch (e) {
    print(e);
    print("不允许修改lib.people,因为作为整体导入时,模块对象的直接一级属性是只读属性,修改将引发报错");
}

// 允许修改,因为作为整体导入时,模块对象的直接一级属性是只读属性,但一级
// 属性引用的对象不是只读对象,可以修改其属性(只要没有被设置为不可写)
lib.people.age = 666;
print(lib);

// 整体导入时,不允许给模块对象新增属性,因为整体导入时的模块对象是一个不可拓展的对象,不可以给模块对象新增任何属性
try {
    lib.provices = ['GD', 'FJ'];
    print(lib);
} catch (e) {
    print(e);
    print("不允许对lib对象新增属性,整体导入时,不允许给模块对象新增属性,因为整体导入时的模块对象是一个不可拓展的对象,不可以给模块对象新增任何属性");
}
复制代码

具体运行结果:

===================================
{ age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ getCurrrentYear: [Function: getCurrrentYear],
  people: { age: 26, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] },
  time: 1545275257126 }
===================================
{ age: 999, name: 'rioli', cities: [ 'jieyang', 'shenzhen' ] }
===================================
{ age: 999,
  name: 'rioli',
  cities: [ 'jieyang', 'shenzhen' ],
  father: 'baba' }
===================================
TypeError: Cannot assign to read only property 'people' of object '[object Module]'
    at file:///Users/chenjt/Documents/playground/ESModule-learning/lesson02/esmodule/main.mjs:28:16
    at ModuleJob.run (internal/modules/esm/ModuleJob.js:106:14)
    at <anonymous>
===================================
不允许修改lib.people,因为作为整体导入时,模块对象的直接一级属性是只读属性,修改将引发报错
===================================
{ getCurrrentYear: [Function: getCurrrentYear],
  people:
   { age: 666,
     name: 'rioli',
     cities: [ 'jieyang', 'shenzhen' ],
     father: 'baba' },
  time: 1545275257126 }
===================================
TypeError: Cannot add property provices, object is not extensible
    at file:///Users/chenjt/Documents/playground/ESModule-learning/lesson02/esmodule/main.mjs:43:18
    at ModuleJob.run (internal/modules/esm/ModuleJob.js:106:14)
    at <anonymous>
===================================
不允许对lib对象新增属性,整体导入时,不允许给模块对象新增属性,因为整体导入时的模块对象是一个不可拓展的对象,不可以给模块对象新增任何属性
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换