ES介绍
ES就是ECMAScript简称,JS就是ES的一个实现,这里ECMA(欧洲计算机制造商学会)每年发布一个ES新版本,2020年到了ES11,前置内容: JS,Ajax,Promise
为什么从ES6开始: 变动多,有里程碑意义,新增语法特性
ES兼容性:查询网站,即使不兼容我们也可以通过编译器编译成ES5
ES6新特性
eval函数(ES3函数补充)
eval()函数可计算某个字符串,并执行其中的的JavaScript代码。
- 语法: eval(string)
string: 要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。 - 返回值
通过计算 string 得到的值(如果有的话)。 - 说明
该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此请不要为eval()函数传递 String 对象来作为参数。 - 如果试图覆盖 eval 属性或把 eval() 方法赋予另一个属性,并通过该属性调用它,则 ECMAScript 实现允许抛出一个 EvalError 异常。
- 抛出
如果参数中没有合法的表达式和语句,则抛出 SyntaxError 异常。如果非法调用 eval(),则抛出 EvalError 异常。如果传递给 eval() 的 Javascript 代码生成了一个异常,eval() 将把该异常传递给调用者。 - 虽然 eval() 的功能非常强大,但在实际使用中用到它的情况并不多。不同浏览器不同版本对eval处理有差异
实例
eval("x=10;y=20;document.write(x*y)")
console.log(eval("2+2"))
var x=10
console.log(eval(x+17))
输出
200
4
27
- 作用域
和var x = 1; (function () { eval('var x = 123;'); console.log("I",x) })(); console.log(x);
在ES<=8,得到的是var x = 1; (function () { window.eval('var x = 123;'); console.log("I",x) })(); console.log(x);
在ES>8得到的是I 123 1 I 123 1
在ES8-下eval是函数作用域,在ES8+下eval的作用域取决于调用者I 123 1 I 123 123
let关键字
- 与
var的级别用法一样 let不可以重复声明,但是var可以var varIns = "A"; var varIns = "B"; // 合法 let letIns = "A"; let letIns = "B"; // 不合法let具有块级作用域,var没有块作用域,JS的作用域有- 全局作用域(例如
a=1,那么a就是window的成员) - 函数作用域(例如在函数中
var a=1, 那么出了函数a就没了) - eval作用域
- 块作用域(例如{a=1},if(){},while(){}…,那么在括号外面a就不可用)
- 全局作用域(例如
let不存在变量提升,例如console.log(a); // 输出undefined var a=1; console.log(a); // 输出1 console.log(b); // 报错 let b=1; console.log(b);let不影响作用域链
虽然是块级作用域,但是不影响如果函数内部没有变量会自动往外找
实例
在以前写代码的时候我们遇到过这个问题
// 我有5个button
var btns = document.querySelectorAll("button");
for(var i = 0;i < btns.length;i++){
btns[i].onclick = function(){
console.log(i);
}
}
这时候不管点哪个都显示5,这是因为onclick里面没有i,于是闭包传输了i,这个i是外面的i,i在变化,到点击的时候相当于是走完了
{
var i=0} //第1个循环
{
var i=1} //第2个循环
{
var i=2} //第3个循环
{
var i=3} //第4个循环
{
var i=4} //第5个循环
这个时候i就是5,因为i是for的块级作用域内部变量,var没有块级作用域,第二个循环的修改会影响第一个循环的i
我们有两个修改方法
增加参数
var btns = document.querySelectorAll("button");
for(var i = 0;i < btns.length;i++){
btns[i].idx = i;
btns[i].onclick = function(){
console.log(this.idx);
}
}
修改为let
// 我有5个button
var btns = document.querySelectorAll("button");
for(let i = 0;i < btns.length;i++){
btns[i].onclick = function(){
console.log(i);
}
}
相当于执行了
{let i=0} //第1个循环
{let i=1} //第2个循环
{let i=2} //第3个循环
{let i=3} //第4个循环
{let i=4} //第5个循环
let有块级作用域,第二个循环的修改不会影响第一个循环的i=1
const关键字
- 格式于let一样
- 必须赋初值
- 建议大写
- 不能修改
- 有块级作用域
- 常量指向数组/对象的修改不算修改,因为const对象指向的地址没有变
变量解构赋值
可以按照一定模式从数组/对象提取值,对变量进行赋值
-
对数组进行解构
[...]=Array,就是找对应元素分别对应数组,例如let [a,b,c,d]=[111,222,333,"789"]; console.log(a); console.log(b); console.log(c); console.log(d);不是很常用
-
可以对对象进行解构
{...}=Object,要求变量名一一对应,例如let t={ a:111, b:222, d:333, c:function(){ console.log("OK")} } let { a,b,c,d}=t; console.log(a); console.log(b); console.log(c); c(); console.log(d); d(); // Error解构一般用于提取方法,例如我之前要写
t.c()就可以简写成c()了 -
解构时候如果数目不同/不匹配时,会尽量匹配,例如
let [a,b] = [1,2,3] // a=1 b=2 let [a,b,c,d] = [1,2,3] // a=1 b=2 c=3 d=undefined let t={ x:111, y:222, z:333, w:function(){ console.log("OK")} } let { x,y} = t; // x=111 y=222 let { z,w,s} = t; // z=333 w=[function] s=undefined -
解构支持默认值
JS确认某个参数要使用默认值是这个参数===undefinedlet [m1,m2="S"] = ["A"] // m1="A" m2="S" let [n1,n2="S"] = ["A",undefined] // n1="A" n2="S" let [p1,p2="S"] = ["A",null] // p1="A" p2=null -
字符串的解构赋值
将字符串转化为数组let [a,b,c] = "Liu" // a="L" b="i" c="u" -
数值与布尔值解构
let { toString: s}=123; console.log(s===Number.prototype.toString) let { toString: r}=true; console.log(r===Boolean.prototype.toString)都是true
-
函数参数解构
function foo([a,b]){ console.log(a,b); // 1,2 } foo([1,2]) function foo2({ a=0,b=0}={ }){ // 无参时默认{} a,b也有默认值 //function foo2({a,b}={a=0,b=0}){ // 注意,这两种方法出的结果不同 console.log(a,b); } foo2({ a:1,b:2}) // 1,2 foo2({ a:1}) // 1,0 foo2({ a:undefined,b:2}) // 0,2 foo2() // 0,0 -
用处
- 交换值
[a,b]=[b,a] - 接受函数返回对象/数组
- 函数参数定义
- 函数参数默认值
- 加载模块
const { SourceMapConsumer, SourceNode} = require("source-map") - 获取map值
let map = new Map(); map.set("a","A") map.set("b","B") // 获取键值 for (let [key,value] of map) { // ... } // 获取键名 for (let [key] of map) { // ... } // 获取键值 for (let [value] of map) { // ... }
- 交换值
-
补充for的遍历
for in便历出来的是属性for of遍历的是value- 手动给对象添加属性后, for in 是可以将新添加的属性遍历出来 但是for of 不行
for in的属性是使用[]不可以使用 “.” eg: data[‘index’] instead of data.index
模板字符串
模板字符串使用``声明,支持
- 在内容中出现换行 例如
输出分别是let a = '123\n 456\n 789'; console.log(a); let b = `123 456 789`; console.log(b); let c = '123 456 789'; console.log(c);123 456 789 123 456 789 报错 - 支持变量拼接,使用${}
let name = "Liu"; let spk1 = `I'm `+name+`, Hello` let spk2 = `I'm ${ name}, Hello` console.log(spk1) console.log(spk2)
简化对象写法
可以在{}中直接写对象,例如
let aaa = "aaa"
let bbb = "bbb"
console.log({
aaa,bbb})
console.log({
aaa: "aaa", bbb: "bbb"})
console.log({
aaa, bbb, foo(){
console.log("OK")}})
console.log({
aaa: "aaa", bbb: "bbb", foo:function(){
console.log("OK")}})
结果是
{aaa: "aaa", bbb: "bbb"}
{aaa: "aaa", bbb: "bbb"}
{aaa: "aaa", bbb: "bbb", foo: ƒ}
{aaa: "aaa", bbb: "bbb", foo: ƒ}
这里要简写的是变量,不能是常量,例如我想构造{"A":"A"}不能写{"A"}
箭头函数
将function(a,b)=>{//code}简写为(a,b)=>{//code}
- this是静态的,始终指向函数声明时所在作用域下的this(call,apply修改对 他无效),而funcion是this指向调用者
输出S.prototype.work1=function(){ setTimeout(function(){ console.log(this)},1000) } S.prototype.work2=function(){ setTimeout(()=>{ console.log(this)},1000) } S.prototype.work3=()=>{ setTimeout(()=>{ console.log(this)},1000) } let s=new S(); s.age = 12; s.work1(); s.work2(); s.work3();window s对象 window - 不能作为构造函数实例化对象,因为this不能指向对象,会报错XX不是一个构造函数
- 不能使用arguments变量
function work1(){ console.log(arguments)} function work2(...arg){ console.log(arg)} work3=()=>{ console.log(arguments)} work4=(...arg)=>{ console.log(arg)} work1(1,2,3,4) // 输出Arguments变量 work2(1,2,3,4) // 输出数组 work4(1,2,3,4) // 输出数组 work3(1,2,3,4) // 报错arguments是undefined - 箭头函数还可以简写
- 当只有一个形参的时候可以把
(a)=>{// code}简写成a=>{// code} - 当代码体只有一条语句的时候
()=>{// onecode}简写成()=>// onecode,同时不能写return,此时语句的返回结果就是返回值,例如(a)=>{return a*a}简写为a=>a*a
- 当只有一个形参的时候可以把
- 特例,我想简写返回对象
x => { foo: x }会报错,换成x => ({ foo: x })
实例 不适合与this有关的操作,例如dom的回调
let [btn1,btn2] = document.querySelectorAll("button");
btn1.myflag=true;
btn1.onclick=function(){
setTimeout(function(){
console.log(this.myflag);
},1000)
}
btn2.myflag=true;
btn2.onclick=function(){
setTimeout(()=>{
console.log(this.myflag);
},1000)
}
点击第一个按钮是undefined,第二个是true
获取所有奇数
let s = [1,4,5,6,7,8]
console.log(s.filter(i=>i%2))
函数默认参数
- 略
- 与解构赋值结合
function foo({ url=127,port=22}={ }){ console.log(url,port) } foo({ url:128}) foo({ port:23}) foo({ lalala:128}) foo()
REST参数
对于function定义的函数可以使用arguments获取参数列表,arguments是一个伪数组,没有forEach等函数,我们可以使用REST参数解决,写法是…变量,
function foo(...args){
console.log(args)
}
foo(1,2,3,4); // 结果是[1,2,3,4]
与C语言的…一样,我们也可以指定一部分,但是…必须放末尾
function foo(x,y,...args){
console.log(args)
}
foo(1,2,3,4); // 结果是[3,4]
…Spread扩展运算符
与REST的…标识一样,作用不同,rest是放在形参的位置,扩展运算符是放在调用实参的位置,用来将数组分开(类似于解构数组)
function foo(){
console.log(arguments)
}
foo(...[1,2,3]) //Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
扩展运算符只能用在函数调用时候,但是也包括如写用法
// 1. 数组的合并
let ary = [...[1,2,3],...[4,5,6],...[7,8,9]]
// [1,2,3,4,5,6,7,8,9]
// 2. 数组的克隆
let aty_cp = [...ary]
// 当然这是个浅拷贝
// 3. 伪数组的转换
function foo(){
let agms = [...arguments]
console.log(agms)
}
foo(1,2,3,4,5)
...实际上是个语法糖
Symbol 数据类型
- Symbol是ES6引入的一种新的数据类型
- 用来表示独一无二的值
- 他是一种类似于字符串的值,保证值是唯一的
- Symbol值不能参与任何一种运算,外部也看不到Symbol的值是多少, 只能知道分别定义两个Symbol一定是不同的
创建Symbol
let s = Symbol() // 不用写new 因为是js的默认数据类型
console.log(s,typeof s) // Symbol() symbol
我们无法知道Symbol的值,js保证内部实现独一无二
我们还可以为Symbol传入一个注释
let s1 = Symbol("Liu");
let s2 = Symbol("Liu");
console.log(s1===s2) // false
但是相同的注释不是生成相同的结果,这个功能一般用于调试使用, 例如想为对象加入一个debug熟悉就可以Obj[Symbol(debug)]="OK",方便我们删除,在ES10中会有新方法对注释进行利用
我们可以像使用hash一样为相同的内容生成相同的Symbol
let s1 = Symbol.for("Liu");
let s2 = Symbol.for("Liu");
console.log(s1===s2) // true
Symbol的作用原文
Symbol的作用非常的专一,换句话说其设计出来就只有一个目的——作为对象属性的唯一标识符,防止对象属性冲突发生。
举个例子,你看上了公司前来的前台妹纸,想了解关于她的更多信息,于是就询问Hr同事,扫地阿姨,于是得到类似这样信息:
let info1 = {
name: '婷婷',
age: 24,
job: '公司前台',
description: '平时喜欢做做瑜伽,人家有男朋友,你别指望了'
}
let info2 = {
description: '这小姑娘挺好的,挺热情的,嘿嘿嘿……'
}
显然,你需要对这两个数据进行汇总,结果,就会发现,描述都用了同一个对象属性description,于是整合的时候,就容器冲突,覆盖,导致“人家有男朋友”这么重要的信息都没注意到。
但是,如果要是Symbol,则完全就不要担心这个问题了:
let info1 = {
name: '婷婷',
age: 24,
job: '公司前台',
[Symbol('description')]: '平时喜欢做做瑜伽,人家有男朋友,你别指望了'
}
let info2 = {
[Symbol('description')]: '这小姑娘挺好的,挺热情的,嘿嘿嘿……'
}
此时,我们对info1, info2对象进行复制,如下:
let target = {
};
Object.assign(target,
本文详细介绍了从ES6到ES12的各个版本中的新特性,包括let和const关键字、模板字符串、箭头函数、Promise、Set和Map、类、数值和字符串扩展、模块化等内容。讲解了新特性如何使用以及它们在实际开发中的应用,帮助开发者更好地理解和掌握JavaScript的最新进展。
最低0.47元/天 解锁文章
566

被折叠的 条评论
为什么被折叠?



