ES6
声明变量
var
function
let
- 块级作用域。
- 不存在变量提升。
- 同一作用域内不可重复声明。
const
- 块级作用域。
- 一定要赋初始值。
- 值不可修改。
但是对于数组和对象的元素进行修改,不会报错。因为数组和对象的常量中保存的是对它们的引用地址,值发生改变不会影响引用地址。 const TEAM = [‘A’, ‘B’, ‘C’];
import
class
注意
- ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
var 命令和function 命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let 命令、const 命令、class 命令声明的全局变量,不属于顶层对象的属性。
解构赋值
解构赋值指允许从数组和对象中提取值,对变量进行赋值。
const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);
const zhao = {
name: '赵本山',
age: '不详',
xiaopin: function(){
console.log("aa");
}
};
let {name: name, age: age, xiaopin: xiaopin } = zhao;
let {name, age, xiaopin} = zhao;
const obj1 = {};
const obj2 = {foo: 'bar'};
Object.setPrototypeof(obj1, obj2);
const {foo} = obj1;
foo
const [a, b, c, d, e] = 'hello';
a
let {length: len} = 'hello';
len
let [x = 1] = [undefined];
x
let [x = 1] = [null];
x
let x = 1;
let y = 2;
[x, y] = [y, x];
let data = {
id: 42,
status: 'ok',
data: [214, 321]
};
let {id, status, data: number} = data;
console.log(number);
function(url, {async = true, global = true }={}){
...
}
const { SourceMapConsumer, SourceNode } = require("source-map");
字符串
let str = `呃呃呃呃呃呃`;
let html = `<div>
<span></span>
</div>`;
let html = `<div>
<span>${str}</span>
</div>`;
let s = 'hello world!';
s.includes('l')
s.includes('hello', 6)
s.startsWith('h')
s.startsWith('world', 6)
s.endsWith('!')
s.endsWith('hello', 5)
'x'.repeat(3)
'na'.repeat(2.9)
'na'.repeat(Infinity)
'na'.repeat(-1)
'na'.repeat(-0.9)
'na'.repeat(NaN)
'na'.repeat('na')
'na'.repeat('3')
const str = 'hello';
str.at(1)
str.at(-1)
数值
function equal(a, b){
if(Math.abs(a-b) < Number.EPSILON){
return ture;
}else{
return false;
}
}
console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1+0.2, 0.3));
let b = 0b1010;
let o = 0o777;
isFinite(25)
isFinite('25')
Number.isFinite(25)
Number.isFinite('25')
isNaN(NaN)
isNaN('NaN')
Number.isNaN(NaN)
Number.isNaN("NaN")
Number.isNaN(1)
Number.isInteger(25)
Number.isInteger(25.1)
Number.isInteger(25.0)
Number.isInteger(5E-324)
Number.isInteger(5E-325)
Math.trunc(4.1)
Math.trunc(null)
Math.trunc()
函数
(1)箭头函数
箭头函数适合与this无关的回调,比如定时器、数组的方法回调。 不适合与this有关的回调,比如事件回调、对象的方法。
let f = (a, b) => {};
let f = function(a, b){};
let f = a => {};
let f = n => n*n;
let getItem = id => ({id: id, name: "temp"});
function Person(name, age){
this.name = name;
this.age = age;
}
let Person = (name, age)=>{
this.name = name;
this.age = age;
}
function getName(){
console.log(this.name);
}
let getName2 = ()=>{
console.log(this.name);
};
window.name = 'window';
const school = {
name: 'school'
};
getName.call(school);
getName2.call(school);
(2)参数
函数参数的默认值
function add(a, b, c=10){
return a+b+c;
}
let result = add(1, 2);
function connect({host = '127.0.0.1', username, password, port}){
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
username: 'root',
password: 'root',
port: 3306
});
rest参数
- 形式为…变量名
- 用于获取函数的实参,用来代替arguments。
- 必须放在参数最后。
- 返回的是数组。
function date(a, b, ...args){
console.log(a);
console.log(b);
console.log(args);
}
data(1, 2, 3, 4,5);
(3)属性方法
函数的length属性
(function (a) {}).length
(function (a = 5) {}).length
(function (a, b, c = 5) {}).length
(function (...args){}).length
(function (a = 0, b, c){}).length
(function f(name, age=18, gender, ...args){}).length
123['toString'].length + 123
函数的name属性
var f = function(){};
f.name
f.name
(new Function).name
function foo(){};
foo.bind({}).name
数组
(1)扩展运算符
扩展运算符…
const strs = ['a', 'b', 'c'];
function f(){
console.log(arguments);
}
f(...strs);
f('a', 'b', 'c');
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
arr1.push(...arr2);
const str1 = ['a', 'b'];
const str2 = [...str1];
const divs = document.querySelectorAll('div');
const divArr = [...divs];
f.apply(null, args);
f(...args);
(2)属性方法
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
var arr1 = [].slice.call(arrayLike);
let arr2 = Array.from(arrayLike);
Array.from(arrayLike, x => x * x);
Array.from(arrayLike).map(x => x * x);
Array.of()
Array.of(3)
Array.of(3, 11, 8)
Array()
Array(3)
Array(3, 11, 8)
[1, 2, 3, 4, 5].copyWithin(0, 3)
[1, 2, 3, 4, 5].find((value, index, arr)=>{
return value > 3;
})
for(let [index, elem] of ['a', 'b'].entries()){
console.log(index, elem);
}
for(let index of ['a', 'b'].keys()){
console.log(index);
}
for(let elem of ['a', 'b'].values()){
console.log(elem);
}
const arr = [5, 12, 8, 130];
arr.at(2)
arr.at(-2)
(3)数组的空位
数组的空位指的是,数组的某一位置上没有任何值。
ES5
forEach() , filter() , reduce() , every() 和some() 都会跳过空位。map() 会跳过空位,但会保留这个值join() 和toString() 会将空位视为undefined ,而undefined 和null 会被处理成空字符串。
ES6
对象
let name = 'a';
const obj = {
name,
improve(){}
};
var obj = {
foo: true,
abc: 123
};
let lastWord = 'last_word';
const a = {
'first_word': 'hellp',
[lastWord]: 'world',
['e'+'nd']: '!'
}
Object.is(+0, -0)
Object.is(NaN, NaN)
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
console.log(returnedTarget);
Object.assign([1, 2, 3], [4, 5])
super关键字
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find(){
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find()
const obj = {
foo: super.foo
};
const obj = {
foo: ()=> super.foo
};
const obj = {
foo: function(){
return super.foo;
}
};
__proto__
- 内部属性。
- 无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的
Object.setPrototypeOf() (写操作)、Object.getPrototypeOf() (读操作)、Object.create() (生成操作)代替。
symbol
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol 的原因。 表示独一无二的值。基本上,它是一种类似于字符串的数据类型。
特点
- Symbol的值是唯一的,用于解决命名冲突的问题。
- Symbol定义的对象属性不能使用for…in、for…of循环遍历,也不会被
Object.keys() 、Object.getOwnPropertyNames() 、JSON.stringify() 返回。但是可以使用Object.getOwnPropertySymbols() 来获取对象的所有Symbol属性名;或者使用Reflect.ownkeys 来获取对象的所有键名。
let s = Symbol();
let s1 = Symbol('foo');
let s2 = Symbol('bar');
console.log(s1);
console.log(s2);
console.log(s1.toString());
console.log(s2.toString());
let s1 = Symbol();
let s2 = Symbol();
s1===s2;
let s3 = Symbol('foo');
let s4 = Symbol('foo');
s3===s4;
s3.description
"aaaa" + s;
String(s);
Boolean(s);
Number(s);
let s = Symbol();
let a = {};
a[s] = 'hello';
let a = {
[s]: 'hello'
};
let a = {};
Object.defineProperty(a, s, {value: 'hello'});
a[s]
let s = Symbol();
let obj = {
[s]: function(arg){
}
};
let obj = {
[s](arg){}
};
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1===s2;
Symbol属性
class Even{
static [Symbol.hasInstance](obj){
return Number(obj) % 2 === 0;
}
}
1 instanceof Even
let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e')
iterator
const arr = ['a', 'b', 'c'];
for(let i in arr){
console.log(i);
}
for(let i of arr){
console.log(i);
}
Iterator 作用
- 为各种数据结构提供统一的访问接口。
- 使得数据结构的成员能够按照某种次序排列。
- 供for…of消费。当使用for…of遍历时,会自动寻找Iterator接口,默认的 Iterator 接口部署在数据结构的
Symbol.iterator 属性。
遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置。
let iterator = arrSymbol.iterator; - 第一次调用对象的next方法,指针自动指向数据结构的第一个成员。
iterator.next(); - 接下来不断调用next方法,指针一直向后移动,直到指向最后一个成员。
- 每调用next方法返回一个包含value和done属性的对象。
原生具备Iterator接口的数据结构如下:
- Array
- Map
- Set
- String
- TypedArray
- arguments
- NodeList
const obj = {
data: [
'b',
'c',
'd'
],
[Symbol.iterator](){
let index = 0;
return {
next: ()=>{
if(index < this.data.length){
return {value: this.data[index++], done: false};
}else{
return {value: undefined, done: true};
}
}
}
}
}
for(let i of obj){
console.log(i);
}
generator
function getUsers(){
setTimeout(()=>{
let data = 'users';
iterator.next(data);
}, 1000);
}
function getOrders(){
setTimeout(()=>{
let data = 'orders';
iterator.next(data);
}, 1000);
}
function getGoods(){
setTimeout(()=>{
let data = 'goods';
iterator.next(data);
}, 1000);
}
function* gen(){
let users = yield getUsers();
let orders = yield getOrders();
let goods = yield getGoods();
}
let iterator = gen();
iterator.next();
所谓"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。 比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。 相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。
Set
Set
let s = new Set([1,2,3,2,4]);
s
s.add(1);
s.delete(4);
console.log(s.has(4));
console.log(s.size);
s.clear();
Set.prototype.keys()
Set.prototype.values()
Set.prototype.entries()
Set.prototype.forEach()
let arr = [1,2,3,4,5,4,3,2,1];
let result = [...new Set(arr)];
[...new set('abbbdas')].join('');
let arr2 = [4,5,6,5,6];
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
let union = [...new Set([...arr, ...arr2])];
let result = [...new Set(arr)].filter(item => !new Set(arr2).has(item));
WeakSet
- 与Set类似,但是成员只能是对象(可以是数组或类似数组的对象)。
- 对象都是弱引用(垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中)。
- 不可遍历。
let ws = new WeakSet();
const obj = {};
ws.add(obj);
ws.delete(obj);
ws.has(obj);
Map
Map
- 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
- 也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
let m = new Map();
m.set('name', 'a');
m.set('change', function(){
...
});
let a = {
name: 'b'
};
m.set(a, [1, 2, 3]);
m.size
m.delete('name');
m.get('change')
m.has('change')
m.clear();
const map = new Map();
map.set(['a'], 555);
map.get(['a'])
Map.prototype.keys()
Map.prototype.values()
Map.prototype.entries()
Map.prototype.forEach()
WeakMap
- 类似Map,但是只接受对象(除了null)作为键名。
- 键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
let wm = new WeakMap();
let key = {};
let obj = {};
wm.set(key, obj);
vm.delete(key);
vm.get(key)
vm.has(key)
Proxy
代理器
- 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
var proxy = new Proxy(target, handler);
var person = {
name: 'a'
};
var proxy = new Proxy(person, {
get: function(){
...
}
});
Reflect
Promise
Promise对象代表一个异步操作。
- 有三种状态:pending、fulfilled、rejected。状态只会改变一次且不可逆。
- 作用
解决回调地狱问题。 代码可读性提高。
const p = new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET', 'url');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
p.then(value => {
return 123;
return new Promise((resolve, reject)=>{
resolve('ok');
});
throw new Error('出错啦');
}, error => {
console.log(error);
...
});
p.catch(error=>{
})
Class
class Phone{
constructor(brand, price){
this.brand = brand;
this.price = price;
}
call(){
console.log('a');
}
static name = '手机';
static change(){
console.log('b');
}
get price(){
console.log('get');
return '1';
}
set price(value){
console.log('set');
}
}
let huawei = new Phone('华为', 4128);
huawei.call();
huawei.change();
console.log(huawei.price);
huawei.price = '2';
class SmartPhone extends Phone{
constructor(brand, price, size, color){
super(brand, price);
this.size = size;
this.color = color;
}
call(){
...
}
}
模块化
好处
ES6之前的模块化规范
- CommonJs=>NodeJS、Browserify
- AMD=>requireJS
- CMD=>seaJS
export let s = 's';
export function f(){
...
}
let s = 's';
function f(){
...
}
export {s, f};
export default{
s: 's',
f: function(){
...
}
}
<script type="module">
import * as m1 from './src/js/m1.js';
console.log(m1.s);
import * as m2 from './src/js/m2.js';
console.log(m2.s);
import * as m3 from './src/js/m3.js';
console.log(m3.default.s);
import {s, f} from './src/js/m1.js';
consoel.log(s);
import {s as s_plus, f as f_plus} from './src/js/m2.js';
console.log(s_plus);
import {default as m3} from './src/js/m3.js';
console.log(m3.s);
import m3 from "./src/js/m3.js";
console.log(m3.s);
</script>
<script src="./src/js/app.js" type="module"></script>
import * as m1 from './src/js/m1.js';
console.log(m1.s);
import * as m2 from './src/js/m2.js';
console.log(m2.s);
import * as m3 from './src/js/m3.js';
console.log(m3.default.s);
import $ from 'jquery';
<script src="dist/bundle.js"></script>
Babel
Babel是一个ES6转码器,可以将ES6代码转为ES5代码,从而在老版本的浏览器执行。
{
"presets": [
"@babel/env",
"@babel/preset-react"
],
"plugins": []
}
babel-cli:实现命令行转码工具。 babel-preset-env:实现转码。 browserify(webpack):打包工具。
ES7
数组
[1, 2, 3].includes(3, 1)
运算符
指数运算符**
2**4
2 ** 3 ** 2
a **= 2
ES8
字符串
'x'.padStart(5, 'ab')
'x'.padEnd(5, 'ab')
'x'.padEnd(5, '0123456')
'x'.padStart(5)
对象
async函数
async function fn(){
return new Promise((resolve, reject)=>{
resolve('a');
});
}
const result = fn();
console.log(result);
await表达式
const p = new Promise((resolve, reject)=>{
resolve('success');
});
async function main(){
try{
let result = await p;
}catch(e){
console.log(e);
}
}
function send(url){
return new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
})
}
async function main(){
let result = await send('url');
console.log(result);
}
main();
ES9
对象
let {x, y, ...z} = {x: 1, y: 2, a: 3, b: 4}
x
y
z
let { ...z } = null;
let { ...z } = undefined;
let {x, ...y, ...z } = obj;
let a_copy = {...a};
let a_copy = Object.assign({}, a);
正则
let str = '<a href="http://www.baidu.com">abcd</a>';
const reg = /<a href="(.*)">(.*)<\/a>/;
console.log(reg.exec(str));
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
console.log(reg1.exec(str));
let str = 'js62349216你知道吗555啦啦啦';
const reg = /\d+(?=啦)/;
console.log(reg.exec(str));
const reg1 = /(?<=吗)\/d+/;
console.log(reg1.exec(str));
ES10
字符串
const s = ' abc ';
s.trim()
s.trimStart()
s.trimEnd()
函数
toString()
- 以前toString()方法返回函数代码本身,但会省略注释和空格。现在会返回一模一样的原始代码。
try…catch
try{
...
}catch(err){
...
}
try{
...
}catch{
...
}
数组
ES2019明确规定,Array.prototype.sort() 的默认排序算法必须稳定。
[1, 2, [3, 4]].flat()
[1, 2, [3, [4, 5]]].flat(2)
[1, [2, [3]]].flat(Infinity)
[2, 3, 4].flatMap(x => [x, x * 2]);
对象
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
ES11
运算符
链运算符?.
const firstName = message?.body?.user?.firstName || 'default';
a?.b
a?.[x]
a?.b()
a?.()
Null判断运算符??
const animationDuration = response.settings?.animationDuration??300;
数值
新数据类型BigInt
- 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
const a = 315264786478n;
42n === 42
typeof 123n
-42n
+42n
class
class Person{
name;
#age;
constructor(name, age){
this.name = name;
this.#age = age;
}
intro(){
console.log(this.#age);
}
}
Promise
console.log(Promise.allSettled([p1, p2]));
console.log(Promise.all([p1, p2]));
globalThis
始终指向全局对象(不论是浏览器还是node环境下)。
模块化
btn.onclick = function(){
import('./hello.js').then(module=>{
module.hello();
});
}
ES12
运算符
逻辑赋值运算符
x ||= y
user.id = user.id || 1;
user.id ||= 1;
x &&= y
x ??= y
字符串
'aabbcc'.replace('b', '_')
'aabbcc'.replaceAll('b', '_')
'aabbcc'.replaceAll(/b/, '_')
'abbc'.replaceAll('b', '$&')
'abbc'.replaceAll('b', '$`')
'abbc'.replaceAll('b', `$'`)
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
'abbc'.replaceAll('b', '$$')
数值
let num = 1_000_000_000;
123_000 === 12_300
0.000_001
1e10_000
WeakRef
用于创建对象的弱引用(弱引用实例不会妨碍原始对象被GC清除)。
let target = {};
let wr = new WeakRef(target);
let obj = wr.deref();
if(obj){
...
}
|