Symbol
介绍:在ES5中对象的属性名都是字符串,这样容易造成属性名冲突,并且在对象中经常需要用到私有属性私有方法的概念.在ES5中同一使用 "_属性名"形式表示当前属性是一个私有属性或私有方法。但是这种写法并不能真正的确保外部无法调用当前对象私有属性。所以在ES6中引入了Symbol数据类型解决上面的问题。
语法: Symbol对象接受一个字符串(Symbol 描述)作为参数返回Symbol对象
let s = Symbol('aaa')
注意:
- Symbol是独一无二的
let s1 = Symbol('aaa')
let s2 = Symbol('aaa')
console.log(s1 == s2) // false
let obj = {
[s1]: 'Hello'
}
console.log(obj[s1]) // 'Hello'
console.log(obj[s2]) // undefined
- Symbol也可以没有参数
let s1 = Symbol()
let s2 = Symbol()
console.log( s1 == s2) // false
3.创建Symbol时Symbol描述不可以被修改
let s3 = Symbol('我是描述')
s3.description = '我是描述123'
console.log(s3.description) // '我是描述'
- Symbol作为属性时是不可枚举的。for…in 、 for…of 的循环中,Object.keys() 、 Object.getOwnPropertyNames() 无法获取到 Symbol属性的。 如果想要获取Symbol属性需要使用Object.getOwnPropertySymbols() 和 Reflect.ownKeys()
let obj = {
[s1]: 'Hello',
name: '123'
}
for (key in obj) {
console.log(key) // 只能遍历 name属性
}
Symbol 方法:
for(): 和 Symbol() 不同的是,用 Symbol.for() 方法创建的的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
let yellow = Symbol("Yellow");
let yellow1 = Symbol.for("Yellow");
// yellow1之前没有用使用for创建 "yellow" Symbol, 所以 yellow1 是一个新的Symbol
yellow === yellow1; // false
let yellow2 = Symbol.for("Yellow");
// yellow2创建之前,存在一个使用for创建的 yellow Symbol。已经存在则不会重复创建而是直接引用yellow1
yellow1 === yellow2; // true
keyFor(symbol): 返回一个已登记的 Symbol 类型值的 key
let s1 = Symbol('aaa') // 只是一个Symbol数据类型
let s2 = Symbol.for('aaa') // 登记到全局的Symbol数据类型
console.log( Symbol.keyFor(s1)) // undefined 未登记
console.log( Symbol.keyFor(s2)) // 'aaa' 已登记
模块
介绍:在js中一直没有模块的概念,将js拆成一些互相依赖小模块。在ES6之前实现模块化使用的是 RequireJS 或者 seaJS(分别是基于 AMD 规范的模块化库, 和基于 CMD 规范的模块化库)。ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。
注意: ES6的模块化自动采用严格模式。无论你是否在文件头部加上“use strict”。ES6 的模块化分为导出(export) @与导入(import)两个模块。
export
概念:在ES6模块化中任何一个独立的文件都是一个模块。文件内的所有变量外部都无法获取。所以如果要公开一些变量就必须使用export 关键字将变量输出
语法:
// constant.js
export const theme = 'red'
export const language = 'zh'
export const version = '1.0.6'
// tool.js
function rem2px(rem) {
console.log(rem, 'rem2px')
}
const px2Rem = function (px) {
console.log(px, 'px2Rem')
}
const number = 12
// 将变量集中在一个对象中公开出去, 这种写法可以给 变量提供别名
export {rem2px, px2Rem, number as systemIntNumber}
注意:
- 注意export对外公开一个接口,公开的接口必须与模块内的变量建立一个“一一对应”的映射关系。下面两种公开方式是不允许的。
export 12 // Error 不可以直接公开12,这种形式是没有向外部提供接口
const number = 12
export number // Error 等价于 export 12
- export 虽然可以写在文件的任何位置,但是他本质上是设计思想是在编译时就能确定模块的依赖关系的公开接口命令。下面的写法完全不符合设计模式的。因为代码的执行是在编译时之后的运行时中
function exportStart () {
export const a = 12
}
exportStart()
import
概念:在ES6使用export 关键字在模块中对外公开了接口之后,其他模块就可以通过import关键字加载对外公开接口的模块
语法:
- 方法一 可以使用 结构方法加载模块中的指定接口
import {theme, language, version } from './constant'
注意: import 语法中可以使用 as 关键字给加载的模块指定一个别名
import {theme, language, version as v } from './constant'
console.log(theme)
console.log(language)
console.log(v) // 使用 as 关键字将接口 version 设置了别名 v(v 替代 变量version)
- 方法二 模块的整体加载。我们可以理解 export 关键字在公开接口时,其实是创建了一个叫做export的模块对象,所有接口都是该对象的属性。import给开发者提供了 * 星号用来指定 export 模块对象。因为js的命名规范中 * 号不可以用做变量名,所以在模块的整体加载中需要配合 as 关键字给模块整体设置一个别名来使用。
import * as tool from './tool'
console.log(tool)
注意:
- import加载的接口都应该是只读的
// constant.js
// 只读原因与 const 关键字有关
export const theme = "red"
export const language = "zh"
export const version = "1.0.6"
// index.js
import {theme, language, version as v } from './constant'
theme = 1 // error
- import 加载语法是单例模式,多次引入同一个接口等价于只引入一次
// webpack会报错,为了开发规范性请不要尝试这样做!
import {theme, language, version as v } from './constant'
import {theme, language, version as v } from './constant'
import {theme, language, version as v } from './constant'
// 等价于 只引入了一次
export default
概念:默认接口, 在开发中使用import 加载接口时,开发人员必须要知道接口的名称否则无法加载。ES6为了让模块的引入更加的方便提供了 默认接口的概念。即在import中使用任意变量来接收都会的得到的接口对象就被称为是默认接口
语法:
// constant.js
export const theme = 'red'
export const language = 'zh'
export const version = '1.0.6'
// 使用 export default 公开接口
export default '我是默认接口的值,默认接口无需指定变量名'
// 加载默认接口, 无需结构赋值可以设置任意变量
import theme from './constant' // 这里theme 不是接口theme 而是默认接口
console.log(theme) // '我是默认接口的值,默认接口无需指定变量名'
注意:
- export default 公开的接口可以使用任意名称接收
- 一个模块中至多只可以有一个默认接口(即只能有一个 export default)
- export default 后不可以声明变量,而是直接公开接口的值
- 默认接口不可以使用大括号 import 加载方法
- 如果默认接口的值是一个对象,不可以直接在 import中使用解构赋值
// constant.js
export default {
name: 'Max',
age: 27
}
import {name} from './constant.js'
// name的值为undefined
// import 中使用大括号代表的是获取 export 公开的接口,上面的name 获取的是 export const name 值
- 默认接口 不可以使用 as设置别名
import a as test from './constant' // Error
- 模块文件中若存在默认接口,使用 * as 加载的整个export对象时,默认接口的接口属性名为default
import a from './constant'
console.log(a.default)
「课堂练习」
使用webpack实现封装两个模块文件
要求:
- 创建一个tool.js文件。
- tool.js 公开三个接口 rem2px方法, px2Rem方法, number as systemIntNumber 常量。
- 创建一个constant.js文件。
- constant.js 只公开一个对象接口,对象中包含name、age 属性。
- 创建 index.js 引入这两个文件的所有接口,并调用
- 使用webpack将index.js打包输出为main.js文件