JavaScript高级ES6常见新特性:词法环境letconst模板字符串函数增强SymbolSetMap
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级ES6常见新特性:词法环境letconst模板字符串函数增强SymbolSetMap相关的知识,希望对你有一定的参考价值。
文章目录
词法环境
可以看这里:1. 彻底搞懂javascript-词法环境(Lexical Environments)、词法环境是什么?、js 图解变量环境、词法环境、执行上下文,作用域链查找过程
- 一个词法环境由环境记录(Environment Record)和一个外部词法环境(outer Lexical Environment)组成
- 用于关联一个函数声明、代码块语句、try-catch语句,当它们的代码被执行时,词法环境被创建出来
执行上下文一般会关联两个词法环境:
- 词法环境组件:用于处理
let
、const
声明的标识符 - 变量环境组件:用于处理
var
、function
声明的标识符
两种环境记录值:声明式环境记录和对象环境记录。
let、const
基本使用
let:用于声明一个变量。
const:
- 保存的数据一旦被赋值,不能修改
-若赋值的是引用类型,可以通过引用找到对应对象,修改对象内容
let、const在同一个作用域里面, 不允许重复声明变量。
作用域提升
var声明的变量会作用域提升:在声明之前可以访问, 只不过值是undefined
console.log(foo); // undefined
var foo = "foo";
而let、const声明的变量,在声明之前访问会报错:let、const定义的变量不是当代码执行到那一行才创建出来的, 在这之前就已经创建出来, 只是不能访问。
省流:let、const没有作用域提升,但是会在解析阶段被创建出来。只是创建出来后、代码执行到那一行之前不能访问。
暂时性死区
已知在let、const定义的标识符在执行到声明代码前是不能被访问的。
从块作用域的顶部一直到变量声明完成之前,这个变量处在的区域就是暂时性死区(TDZ,temporal dead zone)。
暂时性死区与定义的位置无关, 与代码的执行顺序有关:若与定义的位置有关,则这里应该是undefined。
function foo()
console.log(address);
let address="address"
foo()//address
暂时性死区形成后, 在该区域内这个标识符不能访问:
如下面代码中, foo作用域下会优先访问自己作用域下的address, 而foo作用域中, 执行到第7行代码之前, 已经形成暂时性死区, 所以不能访问, 就会报错。
let address="window address"
function foo()
console.log(address);
let address="foo address"
foo()
不添加到window
已知:在全局通过var来声明一个变量,事实上会在window上添加一个属性。
但是:let、const是不会给window上添加任何属性的。
let message="message"
const address="address"
console.log(window.message);//undefined
console.log(window.address);//undefined
块级作用域
ES6之前,javascript只会形成两个作用域: 全局作用域和函数作用域。在ES6中新增了块级作用域,并且通过let
、const
、function
、class
声明的标识符是具备块级作用域的限制的:
let
let message="let"
console.log(message);//Uncaught ReferenceError: message is not defined
const
const message="const"
console.log(message);//Uncaught ReferenceError: message is not defined
class
class Person
var p=new Person()//Uncaught ReferenceError: Person is not defined
但是:函数拥有块级作用域,外面依然可以访问的——JS引擎会对函数的声明进行特殊的处理,允许像var那样进行提升
function foo()
console.log("foo");
foo()//foo
var/let/const用哪个
var:
- 省流:别用
- var很多特殊性如:作用域提升、window全局对象、没有块级作用域等,是历史遗留问题,是语言缺陷
- 工作中用最新的规范来写,别用var
let vs const:
- 优先推荐const,可以保证数据的安全性不会被随意的篡改
- 用let:当我们明确知道一个变量后续会需要被重新赋值时
模板字符串
ES6允许我们使用字符串模板来嵌入JS的变量或者表达式来进行拼接:
- 用 `` 符号来编写字符串,称之为模板字符串
- 通过 $expression 来嵌入动态的内容
动态嵌入内容:
const name="kaisa"
const age=18
console.log(`name is $name,age is $age`);//name is kaisa,age is 18
拼接表达式:
const age=18
console.log(`我是成年人吗?$age>=18?'是':'不是'`);//我是成年人吗?是
接收函数的返回值:
function foo()
return "foo";
console.log(`$foo()`); //foo
标签模板字符串
如果我们使用标签模板字符串调用函数 ,并且在调用的时候插入其他的变量:
- 模板字符串被拆分了
- 第一个元素是数组,是被模块字符串拆分的字符串组合
- 后面的元素是一个个模块字符串传入的内容变量
const name="kaisa"
const age=18
function foo(...args)
console.log(args);
foo`name is $name,age is $age`
//[Array(3), 'kaisa', 18]
//Array(3):['name is ', ',age is ', '']
ES6函数增强
函数的默认参数
// x的默认值为20 y的默认值为30
function foo(x = 20, y = 30)
console.log(x, y);
foo(); // 20 30
foo(10, 50); // 10 50
注意:
- 有默认值的参数, 我们通常将其放到参数最后(JS中可以不放最后,但很多其他语言不放最后会报错)
- 若有剩余参数,默认参数要放到剩余参数前
- 默认值会改变函数的length的个数:有默认值的参数, 以及后面的参数都不计算在length之内
- 可以和解构一起使用:
function foo(name,age=name:"kaisa",age:18)
console.log(name,age);
foo()//kaisa 18
function foo(name="kaisa",age=18=)
console.log(name,age);
foo()//kaisa 18
箭头函数补充
箭头函数没有显式原型prototype,所以不能作为构造函数,使用new来创建对象。
如下:
- 箭头函数隐式原型指向Function的显式原型
- 箭头函数没有显式原型
const foo=()=>
console.log(foo.__proto__===Function.prototype);//true
console.log(foo.prototype)//undefined
展开语法
展开运算符其实是一种浅拷贝
函数调用时的使用:
const names=['a','b','c','d']
function foo(arg,...args)
console.log(arg,args);
foo(...names);//a (3) ['b', 'c', 'd']
const str="hello"
function foo(arg,...args)
console.log(args);
foo(...str);//(4) ['e', 'l', 'l', 'o']
数组构造时使用:
const names = ["aaa", "bbb", "ccc"];
const newNames = [...names, "ddd", "eee"]
console.log(newNames) // ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
构建对象字面量时使用:
const obj =
name: "kaisa",
age: 18
const info =
...obj,
height: 1.88,
address: "成都市"
console.log(info) // name: 'kaisa', age: 18, height: 1.88, address: '成都市'
二进制、八进制、十六进制
- 二:b
- 八:o
- 十六:x
// 十进制
const num1 = 100
// 二进制
const num2 = 0b100
// 八进制
const num3 = 0o100
// 十六进制
const num4 = 0x100
数字过长时,可以使用_作为连接符:
const num5 = 100_000_000
Symbol数据类型
是基本数据类型,翻译为符号。
为什么要有Symbol:防止造成属性名的冲突。如:有一个对象,我们希望在其中添加一个新的属性和值,但我们在不确定它原来内部有什么内容的情况下,很容易造成冲突,从而覆盖掉它内部的某个属性。Symbol的出现,就是为了防止这种冲突的。
- Symbol值通过Symbol函数生成,生成后可以作为属性名
- ES6中对象的属性名可以使用字符串,也可以使用Symbol值
const s1=Symbol()
const obj=
[s1]:'a'
;
console.log(obj);//Symbol(): 'a'
Symbol即使多次创建值,它们也是不同的:Symbol函数执行后每次创建出来的值都是独一无二的。
const s1=Symbol()
const s2=Symbol()
const obj=
[s1]:'a',
[s2]:'b'
;
console.log(obj);//Symbol(): 'a', Symbol(): 'b'
console.log(s1===s2);//false
作为属性名
我们通常会使用Symbol在对象中表示唯一的属性名。我们有以下几种写法。
1.属性名赋值
const s1 = Symbol();
const s2 = Symbol();
const obj = ;
obj[s1] = "aaa";
obj[s2] = "bbb";
2.定义字面量直接使用
const s1 = Symbol();
const s2 = Symbol();
const obj =
[s1]: "aaa",
[s2]: "bbb"
;
3.Object.defineProperty
const s1 = Symbol();
const s2 = Symbol();
const obj = ;
Object.defineProperty(obj, s1,
value: "aaa",
);
Object.defineProperty(obj, s2,
value: "bbb",
);
获取Symbol对应的key
我们获取对象的key的方法, 无法获取Symbol的key:
const s1 = Symbol();
const s2 = Symbol();
const obj =
name: "kaisa",
age: 18,
[s1]: "aaa",
[s2]: "bbb",
;
console.log(Object.keys(obj)); // ['name', 'age']
不过,可以通过Object.getOwnPropertySymbols()
方法:
const s1 = Symbol();
const s2 = Symbol();
const obj =
name: "kaisa",
age: 18,
[s1]: "aaa",
[s2]: "bbb",
;
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(), Symbol()]
相同值的Symbol
ES10新增了特性:description
。
const s1=Symbol('des')
console.log(s1.description);//des
创建相同的Symbol的方法:Symbol.for(key)
const s1=Symbol.for('a')
const s2=Symbol.for('a')
console.log(s1===s2);//true
获取对应的key:Symbol.keyFor
console.log(Symbol.keyFor(s1));//a
Set/Map数据结构
ES6中新增了两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap。
Set
可以用来保存数据,类似于数组,但是元素不能重复。
创建Set我们需要通过Set 构造函数
const set = new Set();
console.log(set); // Set(0) size: 0
Set中存放的元素是不会重复的,所以可以数组去重:
const set=new Set();
console.log(set);//Set(0) size: 0
set.add(1)
set.add(1)
set.add(1)
set.add(2)
console.log(set);//Set(2) 1, 2
常见属性和方法
属性:
- size:返回Set中元素的个数
方法:
- add(value):添加某个value,返回Set对象本身
- delete(value):从set中删除和value值相等的元素,返回boolean类型
- has(value):判断set中是否存在某个元素,返回boolean类型
- clear():清空set中所有的元素,没有返回值
- forEach(callback, [, thisArg]):通过forEach遍历set
const set=new Set();
set.add(1)
set.add(10)
set.add(100)
set.forEach((item)=>
console.log(item+1);//2 11 101
)
- set也支持for…of:
set.add(1)
set.add(10)
set.add(100)
for(item of set)
console.log(item+1);//2 11 101
WeakSet使用(了解)
与Set的区别:
- WeakSet中只能存放对象类型,不能存放基本数据类型
- WeakSet对元素的引用是弱引用,如果没有其他的对某个对象进行引用,那么GC可以对该对象进行回收
WeakSet常见的方法:
- add(value):添加某个元素,返回WeakSet对象本身;
- delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型;
- has(value):判断WeakSet中是否存在某个元素,返回boolean类型;
当我们不想通过非构造方法创建出来的对象来调用类方法时,可以使用weakSet:
使用前:
class Person
eating()
console.log(this, "在eating~")
const p = new Person()
p.eating()//Person 在eating~
p.eating.call( name: "kaisa" ) // name: 'kaisa' 在eating~
const newEating = p.eating.bind("aaa")
newEating() //aaa 在eating~
使用后:
const personSet = new WeakSet()
class Person
constructor()
personSet.add(this)
eating()
if(!personSet.has(this))
throw new Error("不能通过非构造方法创建出来的对象调用running方法")
console.log(this, "在eating~")
Map
Map,用于存储映射关系。对象也可以存储映射关系,它们的区别是:
- 对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key)
- 某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key
- Map可以使用对象类型作为Key
常见属性与方法
属性:
- size:返回Map中元素的个数
方法:
- set(key, value):在Map中添加或者设置key、value,并且返回整个Map对象
- get(key):根据key获取Map中的value
- has(key):判断是否包括某一个key,返回Boolean类型
- delete(key):根据key删除一个键值对,返回Boolean类型
- clear():清空所有的元素
- forEach(callback, [, thisArg]):通过forEach遍历Map, 获取的是对应的value
const key1=name:"name1";
const key2=age:"18"
const map=new Map()
map.set(key1,"a")
map.set(key2,"asd")
map.forEach(item=>
console.log(item);//a asd
)
- Map也可以通过for…of进行遍历, for…of遍历, 直接拿到的是将key和value组成的数组
const key1=name:"name1";
const key2=age:"18"
const map=new Map()
map.set(key1,"a")
map.set(key2,"asd")
for(item of map)
console.log(item);//[…, 'a'] […, 'asd']
- 如果想通过for…of拿到分开的key和value, 要解构
const key1=name:"name1";
const key2=age:"18"
const map=new Map()
map.set(key1,"a")
map.set(key2,"asd")
for(item of map)
const[key,value]=item
console.log(key);//name: 'name1' age: '18'
WeakMap使用
与Map的区别:
- WeakMap的key只能使用对象
- WeakMap的key对 对象 的引用是弱引用
常见方法:
- set(key, value):在Map中添加key、value,并且返回整个Map对象
- get(key):根据key获取Map中的value
- has(key):判断是否包括某一个key,返回Boolean类型
- delete(key):根据key删除一个键值对,返回Boolean类型
应用:
- 不能遍历
- 没有forEach方法,也不支持通过for…of的方式进行遍历
参考
coderwhy的课 以上是关于JavaScript高级ES6常见新特性:词法环境letconst模板字符串函数增强SymbolSetMap的主要内容,如果未能解决你的问题,请参考以下文章
ES6-ES12部分简单知识点总结,希望对大家有用~
ES6常见的新特性(超详细)、let/const、