变量let和常量const:
ES6新增了let命令,用来声明变量。
它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
for (let i = 0; i < 10; i++) {
console.log( i ); // 可以输出
}
console.log(i); //ReferenceError: i is not defined
块级作用域
代码:
for (let i = 0; i < 10; i++) {
btns[i].onclick = function () {
console.log(i);
}
}
另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
上面代码正确运行,输出了3次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
不存在变量提升
let所声明的变量一定要在声明后使用,否则报错。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError 这一部分为暂时性死区,不能操作tmp。
let tmp; // 不同作用域,变量重名不会报错
}
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。 不允许重复声明
let不允许在相同作用域内,重复声明同一个变量。
// 报错
function () {
let a = 10;
var a = 1;
}
// 报错
function () {
let a = 10;
let a = 1;
}
常量 const const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
上面代码表明改变常量的值会报错。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const foo;
// SyntaxError: Missing initializer in const declaration
上面代码表示,对于const来说,只声明不赋值,就会报错
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
if (true) {
console.log(MAX); // ReferenceError
const MAX = 5;
}
上面代码在常量MAX声明之前就调用,结果报错。
const声明的常量,也与let一样不可重复声明。
var message = "Hello!";
let age = 25;
// 以下两行都会报错
const message = "Goodbye!";
const age = 30;
质:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。 下面是另一个例子。
const a = [];
a.push('Hello'); // 可执行
console.log(a); // ["Hello"]
a.length = 0; // 可执行
console.log(a); // []
a = ['abc']; // 报错
上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
想将对象冻结,应该使用Object.freeze方法。
"use strict";
const foo = Object.freeze({a:1});
console.log(foo.a);
foo.prop = 123;// 常规模式时,下面一行不起作用;严格模式时,该行会报错
console.log(foo.prop);
变量的解构赋值:
基本用法
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。
let a = 1;
let b = 2;
let c = 3;
ES6允许写成下面这样。
let [a, b, c] = [1, 2, 3];
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。 默认值
解构赋值允许指定默认值。
let [x, y = 'b', z] = ['a', , 1]; // x='a', y='b', z=1
注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
对象的解构赋值
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
var {x, y = 5} = {x: 1};
x // 1
y // 5
字符串、数值、数组、函数扩展:
字符串扩展
传统上,JavaScript只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
示例
var s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
这三个方法都支持第二个参数,表示开始搜索的位置。
var s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对从字符串开始到第n个位置,而其他两个方法针对从第n个位置直到字符串结束。
repeat方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
'na'.repeat(-10) // 报错
字符串模版
传统的JavaScript语言,输出模板通常是这样写的。
var str = "abc",a=1,b=2,fn=function(){return "xx"};
div1.innerHTML = "<div>"+
"<b>"+str+"</b>"+
"<i>"+(a+b)+"</i>"+
"<u>"+fn()+"</u>"+
"</div>";
字符串模版es6写法:
上面这种写法相当繁琐不方便,ES6引入了模板字符串解决这个问题。
var str = "abc",a=1,b=2,fn=function(){return "xx"};
div1.innerHTML = `
<div>
<b>${str}</b>
<i>${a+b}</i>
<u>${fn()}</u>
</div>
`;
数值扩展
ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
Number.isInteger()用来判断一个值是否为整数。需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
Math.sign方法用来判断一个数到底是正数、负数、还是零。
它会返回五种值。
参数为正数,返回+1;
参数为负数,返回-1;
参数为0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
Math.sign(-5) // -1 参数为负数,返回-1;
Math.sign(5) // +1 参数为正数,返回+1;
Math.sign(0) // +0 参数为0,返回0;
Math.sign(-0) // -0 参数为-0,返回-0;
Math.sign(NaN) // NaN 其他值,返回NaN。
Math.sign('foo'); // NaN 其他值,返回NaN。
Math.sign(); // NaN 其他值,返回NaN。
数组扩展
Array.from方法用于将类似数组的对象或可遍历的对象转为真正的数组(用ff可看到数据类型)。
NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) {
console.log(p);
});
arguments对象
function foo() {
var args = Array.from(arguments);
}
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
函数扩展
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
log('Hello', undefined) // Hello World
ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
rest 参数中的变量代表一个数组,所以数组特有的方法都可以用于这个变量。下面是一个利用 rest 参数改写数组push方法的例子。
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
箭头函数
ES6允许使用“箭头”(=>)定义函数。
var f = v => v;
上面的箭头函数等同于:
var f = function(v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
等同于
var f = function () { return 5 };
加法运算
var sum = (num1, num2) => num1 + num2;
等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
var sum = (num1, num2) => { return num1 + num2; }
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。
var getTempItem = id => ({ id: id, name: "Temp" });
箭头函数使得表达更加简洁。
const isEven = n => n % 2 == 0;
const square = n => n * n;
如果箭头函数的内部存在this,那么它指向的是它所在的函数关键字function中的 this。
btn.onclick=()=>{
console.log(this); // window
}
btn.onclick = function(){
setTimeout(()=>{
console.log(this); // btn
}, 1);
}
使用箭头函数需要注意的地方:
this指向: this指向的是最近的function;arguments指向的是最近的function;bind、call、apply等无效
变量提升: 箭头函数实际上是把匿名函数赋给变量,所以在箭头函数的上面使用箭头函数时,报错
无法当构造函数使用: 无法通过 new 调用
Symbol类型:
Symbol类型,表示独一无二的值。它是 JS 的第七种数据类型,前六种是:undefined、null、Boolean、String、Number、Object。
var s = Symbol();
typeof(s);
产生的原因:为了防止重名造成的冲突,所以引入了Symbol。 Promise对象:
Promise是一种思维方式,是一种解决回调函数噩梦的解决方案。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise对象代表一个异步操作,有三种状态:
Pending(进行中)
Resolved(已完成,又称Fulfilled)
Rejected(已失败)
注:可以把Promise看成是状态机,当该Promise对象创建出来之后,其状态就是进行中,然后通过程序来控制到底是执行已完成,还是执行已失败。因为Promise处理的是异步任务,所以我们还得对Promise做监听,当Promise的状态发生变化时,我们要执行相应的函数。
Promise语法:
var promise = new Promise( function( resolve, reject ){
// 通常这里写一个异步任务,在这个异步任务中,通过resolve或reject来改变promise的状态。
resolve(“数据”); // resolve指将状态更改为已完成、reject指将状态更改为已失败。
} );
// then实际上是对promise的状态监听,当状态为已完成时,触发第一个参数函数。当状态为已失败时,触发第二个参数函数(第二个参数函数,可写可不写),每一个函数中的参数,指当初状态改变时,所保存的数据。
promise.then(function(str){}, function(err){});
all:每一个promise都执行后,再去执行then。
语法:
Promise.all( [ promise1, promise2… ] ).then( function( result ){} )
race:只要有一个promise执行后,就去执行then。
语法:
Promise.race( [ promise1, promise2… ] ).then( function( result ){} )
ES6 提供了新的数据结构Set。
它类似于数组,但是成员的值都是唯一的,没有重复的值。
const s = new Set();
// 将数组中的每个元素,通过add方法,添加到set结构中
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
var set = new Set([{},{}])
set //{{},{}}
set.size // 2
var set = new Set([NaN,NaN])
set //{NaN}
set.size // 1
set对象与数组之间的转换:
var arr = [1,2,3,4,4];
var set = new Set(arr) //数组转换set对象
set //{1,2,3,4}
//方法一
Array.from(set) //[1,2,3,4]
//方法二
[...set] //[1,2,3,4]
set与字符串
var str = 'siiva';
new Set(str) //{'s','i','v','a'}
Set.prototype.add() && Set.prototype.size
var mySet = new Set();
mySet.add(1) // {1}
mySet.add(2).add('2') //{1,2,'2'} 可以链式,2 '2' set看作不相等
mySet.size //3
console.log(Array.from(s));
console.log(s.size); // 获取长度
console.log(s.has(3)); // 是否存在元素3
console.log(s.delete(2)); // 删除元素2,如果删除成功,则返回真
console.log(Array.from(s));
s.clear(); // 清除所有元素,无返回值
console.log(Array.from(s));
var mySet = new Set()
mySet.add(1).add('1')
mySet.size //2
mySet.has('1') //true
mySet.clear();
mySet.size //0
遍历:
Set.prototype.keys() : 返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries(): 返回键值对的遍历器
Set.prototype.forEach() :回调函数遍历
var mySet = new Set(['s','i','v'])
for(let i of mySet.keys()){
console.log(i)
}
// s
// i
// v
for(let i of mySet.values()){
console.log(i)
}
// s
// i
// v
for(let i of mySet.entries()){
console.log(i)
}
// ['s','s']
// ['i','i']
// ['v','v']
var otherSet = mySet.entries();
otherSet.next().value // ['s','s']
otherSet // {'i','v'}
otherSet.next().value //['i','i']
otherSet // {'v'}
otherSet.next().value //['v','v']
otherSet // {}
mySet.entries(); // {"s", "i", "v"}
forEach 方法根据集合中元素的顺序,对每个元素都执行提供的 callback 函数一次。
mySet.forEach(callback[, thisArg])
已经被删除的元素,它是不会执行的,但是,undefined,null会执行
参数 callback 遍历的每个元素都会执行的函数
callback中有三个参数,第一个为键值,第二个为键名,第三个为set对象
thisArg 当执行callback的时候,this的指向。
function callback(value,key,set){
console.log(value,key,set)
}
new Set(['siva','hello',undefined,null]).forEach(callback)
// siva siva {"siva", "hello", undefined, null}
// hello hello {"siva", "hello", undefined, null}
// undefined undefined {"siva", "hello", undefined, null}
// null null {"siva", "hello", undefined, null}
let set = new Set(["ab", "xx", "123"]);
set.forEach((value, key, arr) => {
console.log(value, key, arr); // 注意:value和key相同
})
数组去重&并集:
new Set([...arr1,...arr2]) //{1,2,3,4,5,6,7,8}
let arr3 = [...new Set([...arr1,...arr2])] //[1,2,3,4,5,6,7,8]
交集:
let arr3 = new Set(arr1.filter(x=>b.has(x))) //{4,5}
差集:
let arr3 = new Set(arr1.filter(x=>!b.has(x))) //{1,2,3}
let arr4 = new Set(arr2.filter(x=>!a.has(x))) //{6,7,8}
[...arr3,...arr4] //[1,2,3,6,7,8]
Map含义和基本用法
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
上面代码原意是将一个 DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]。
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
const m = new Map();
const o = {p: 'Hello World'};
console.log(o); // {p: 'Hello World'}
m.set(o, 'content')
console.log(m.get(o)); // "content"
console.log(m.has(o)); // true
console.log(m.delete(o)); // true
console.log(m.has(o)); // false
上面代码使用 Map 结构的set方法,将对象o当作m的一个键,然后又使用get方法读取这个键。
Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
console.log(map.size); // 2
console.log(map.has('name')); // true
console.log(map.get('name')); // "张三"
console.log(map.has('title')); // true
console.log(map.get('title')); // "Author“
上面代码在新建 Map 实例时,就指定了两个键name和title。
Map 有一个forEach方法,与数组的forEach方法类似,可以实现遍历。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.forEach(function(value, key, map) {
console.log(key, value, map);
});
Map转数组的方法:
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
console.log([...map]);
数组转Map的方法:
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
console.log(map);
Generators生成器函数: Generator 函数,它最大的特点,就是可以交出函数的执行权,即暂停执行。
function * fn(){
yield 1;
yield 2;
return 3
}
var f = fn();
console.log( f.next() ); // {value:1, done:false}
console.log( f.next() ); // {value:2, done:false}
console.log( f.next() ); // {value:3, done:true}
注意:
1. 与普通函数相比,生成器函数需要在 关键字function 和 函数名之间,加一个星号,星号前后是否写空格无所谓,带有星号的函数,就是生成器函数,即 Generator函数。
2. yield类似return,中文为产出的意思,表示程序执行到 yield时,程序暂停,产出一个结果,这个结果为对象 {value: 值, done:[false| true]},value指的就是yield后面跟的值,done指程序是否已经完成。
3. 生成器函数本身只返回一个对象,这个对象具有next方法,执行next方法时,函数体内容碰到yield才会暂停。
1,ES6能够解决的问题,ES5都能解决。
2,并非所有浏览器都支持ES6,所以写ES6程序时,要慎重。不同版本的浏览器对ES6支持的程度不一样。
3,在企业中开发时,如果用ES6编程,最后都会通过babel将ES6转换为ES5,然后发布、上线。
4,虽然现在企业开发中ES6用的并不多,但ES6是未来趋势,应该提前了解、掌握。
5,ES6除了本文中提到的一些新特性外,还有其他很多内容,感兴趣的可以去官网了解一些,至于没有在本文中提出来,原因一部分是浏览器不支持,一部分是几乎没有使用场景,一部分是以后讲解的内容
1、指令
模块
服务 $scope,$http,$state
自定义服务
过滤器
自定义过滤器
自定义的指令:ECMA
路由
$http
GET,POST,DELETE,PUT
2、ES6
ECMASCRIPT6.0的缩写。2015.6月份提出的。
ES5.1.
ECMSACRIPT2015.
ECMAS JAVASCRIPT
是欧洲计算机协会。负责制定JS的规范的。JAVASCRIPT是用于实现的。
1、字符串模板:
需要用··进行包裹。然后用${}来放置变量。
2、定义变量
1、通过VAR来定义变量。
有变量提升,但是赋的值没有。
如果在定义的变量后面,直接再定义一次,并没有赋值。对之前的结果无影响。
变量分为两种 :全局的,局部的(函数内部的)
所有接收的参数都是局部变量。
代码块没有作用域。
2、let
let有块级作用域 。
let不允许重复定义
let没有变量提升的概念。
暂时性死区:通过let或const来声明变量之前来调用该变量会报错。
3、const:和LET,VAR一样都是用来定义变量的。通过CONST来定义的变量是不可以改变的。(引用类型来讲,指针不能发生改变,值是可以的。)
3、解构赋值:将对象或数组的值取出来赋给变量。称其为解构赋值。
数组与对象
4、箭头函数:=>
(参数,参数)=>{
函数体//如果函数体内只有一行代码的话,花括号可以省略,并默认将该行代码的结果进行返回
//如果一行代码只返回对象,因为对象与函数体都用的是大括号,所以需要以该对象外围增加一个圆括号。
}
5、字符串的扩展
1、 for of 对字符串进行遍历
// var str="中华人民共和国";
// for(let i of str){
// console.log(i);
// }
2、includes(字符串,开始位置):返回的是一个布尔值,用于查找该字符串是否包含指定的字符串。
startsWith:返回的是一个布尔值,用于判断该字符串是否由指定的字符串开始
endsWith:返回的是一个布尔值,用于判断该字符串是否由指定的字符串结束的。
repeat(数字):返回一个新的字符串,传递一个数字,指的是重复多少次。
padStart:头部补全
padEnd:尾部补全
6、数值的扩展
1、Number.isFinite(数值 ):返回的是一个布尔值。用于判断是不是Number
2、Number.isNaN:返回的是一个布尔值,用于判断是不是NaN;
3、Number.isInteger:返回的是一个布尔值,用于判断是否为整数。
4、Number.parseInt:转为整数
5、Number.parseFloat:转为浮点数
7、Math
1、Math.trunc 去除小数位
2、Math.sign 返回的结果1,0,-1.正数返回的是1,负数返回的是-1,0返回的是0
8、数组的扩展
1、Array.of():将一组值转为数组。
2、copyWithin:将指定的成员 复制到指定的位置上。
第一个参数:替换开始的位置
2.替换字符串的开始值,从0开始
3、替换字符串的结束位置,默认是数组的长度。从1开始的。
3、fill:1,要填充的内容,2,填充的开始位置,从0开始,3,填充的结束位置,从1开始
4、includes:判断数组是否包含指定的元素。返回值是布尔值。
5、find:返回第一个符合条件的元素。如果找不到符合条件的元素,返回undefined
6、findIndex:返回第一个符合条件的元素的下标。如果找不到符合条件的元素,返回-1
1、如果想以变量的值作为对象的属性的话,需要给该变量加上[].
*对象的属性只能是字符串
*对象分为普通对象与函数对象
*Desk.prototype.isPrototypeOf(obj);//返回的是一个布尔值。用于验证obj是不是通过Desk构造函数实例化出来的。如果是返回true,否则false
*通过构造 函数与字面量创建的对象有什么不同?
1、通过字面量创建的是单例模式。通过构造函数创建的两个是不能加等号的。
2、通过构造 函数创建对象可以传值。
*原型对象是共享的
*如果原型对象与实例对象有相同属性名的话,以实例为主。
先去实例对象中去查找,如果有则不去原型对象中查找了。直接返回。
如果没有,则去原型对象中查找。
*hasOwnProperty(属性):返回的是布尔值。当实例对象中具有该属性返回true,否则是false
*in :返回的是布尔值.当原型对象或实例对象具有该属性返回true,否则是false.
var age=14;
var obj={
[age]:19
}
console.log(obj["14"]);//19
2、运算符:
==:正常来判断
===:严格模式下去进行判断
Object.is(num,num2):加强版的严格模式。用于判断两个值是否相等,类似于====。区别:
// console.log(NaN==NaN);
// console.log(NaN===NaN);
// console.log(Object.is(NaN,NaN));
// console.log(+0==-0);//true
// console.log(+0===-0);//true
//console.log(Object.is(0,-0));
3、Object.assign(目标对象,源对象,源对象……):合并对象(将源对象的属性放到目标对象内)
*源对象与目标对象属性名相同,则源对象的属性会将目标对象的同名属性覆盖掉。
*assign的返回值是合并后的目标对象。
*浅复制。assign的一大特点。
*如果是数组,合并的是按照索引值来的。
var arr=[1,2,3,4];
var arr1=[3,4];
console.log(Object.assign(arr,arr1));//[ 3, 4, 3, 4 ]
4、遍历数组
// for(var i=0;i<arr.length;i++){
// console.log(i+":"+arr[i]);
// }
// for(var i in arr){//*i是一个string类型的
// // console.log(i);
// // console.log(typeof i);
// console.log(i+":"+arr[i]);
// }
// arr.forEach(function(value,index){*不支持break
// console.log(index+":"+value);
// break;
// })
for---of
// for(let v of arr){//遍历值
// console.log(v);
// break;
// }
// for(let index of arr.keys()){//遍历下标
// console.log(index);
// }
// for(let item of arr.entries()){//值与下标
// console.log(item);
// }
for([index,value] of arr.entries()){
console.log(index+":"+value);
}
5、数据结构(数组,json)
1、Set:所存储的数据都是唯一的。不会出现重复。
*是一个构造函数。需要通过new操作符来进行实例化。
*将数组转为SET结构。new Set(数组)。会将数组进行去重。
*将SET结构转为数组
1、Array.from(set)
2、[...set]
方法:
add():可以结set添加数据。 如果set内有该数据,只保留一份。
*该方法会将添加后的结构返回出来。
*NaN在set对象中会认为是等值。
delete():删除指定的数据。返回值是一个布尔值,如果删除的数据存在返回true,否则是false
has():是判断set对象中,是否有指定的值。有返回true,无false
clear():清空所有数据,返回值是undefind
属性:
size:是显示set对象中的数据的数量。
2、Map:与之前学过的对象很类似,但是功能要强大一些。主要体现在Map的键值可以是任意值
*set(key,value):可以添加属性
*get(key):获取Map的属性值。
*delete(key):删除指定的数据。返回值是一个布尔值,如果删除的数据存在返回true,否则是false
*has(key):判断key是否在Map对象中,是返回true,否false
*clear():清空所有数据,返回值是undefind
属性:
size:是显示Map对象中的键值对的数量。
3、Map转换:
var obj={
age:12
}
var myMap=new Map();
myMap.set("name","laoliu");
myMap.set(obj,"对象");
//Map转换为数组
// console.log([...myMap]);
// console.log(Array.from(myMap));
//Map的键转为数组
// console.log([...myMap.keys()]);
// console.log(Array.from(myMap.keys()));
//Map的值转为数组
// console.log([...myMap.values()]);
// console.log(Array.from(myMap.values()));
//Map的键值对转为数组(与省略entries功能相同)
// console.log([...myMap.entries()]);
// console.log(Array.from(myMap.entries()));
//将数组转为Map
// var map2=new Map([ [ 'name', 'laoliu' ], [ { age: 12 }, '对象' ] ]);
// console.log(map2);
类:通过类来实例化一个对象。 new操作符来实例化对象。
*通过class来定义类。通过new操作符实例化该类。
1、关于CLASS
*构造器内存放的属性可以理解为之前的实例对象内的属性。
*构造器外的都在原型对象中。
*静态方法只能访问静态的方法。同一个类中需要用this进行访问。
*实例化获得的对象,没有静态方法。静态方法不需要实例化。
*在继承中静态方法只能访问父类的静态方法。通过super进行访问。
*在继承中,如果子类与父类有相同的方法,则子类优先。
2、将对象转换为数组:Object.entries
var obj={
name:"12",
age:80
}
var arr=Object.entries(obj);
//将对象转为MAP
var myMap=new Map(Object.entries(obj));
console.log(myMap);
3、ES6兼容解决方法
1、在线转换
1、Traceur,Google公司出品: http://google.github.io/traceur-compiler/demo/repl.html#
2、Babel: https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015,react,stage-2&targets=&browsers=&builtIns=false&debug=false&code=
2、引入第三方的转换JS
一、1、引入<script src="lib/babel.min.js"></script>
2、将script的类型设为text/babel
<script type="text/babel">
let a=12;
alert(a);
</script>
二、1、引入<script src="lib/traceur.js"></script>
<script src="lib/bootstrap.js"></script>
2、将script的类型设为module
<script type="module">
let a=12;
alert(a);
</script>
3、babel工具
1、cnpm init -y 先创建一个package.json文件。
2、cnpm install -g babel-cli//global
3、cnpm install babel-preset-es2015 babel-cli --save-dev
4、创建一个文件 .babelrc
{
"presets":["es2015"]
}
5、转换命令:
将指定文件转换
babel src/index.js --out-file dist/index.js
或
babel src/index.js -o dist/index.js
指定的文件夹:
babel src --out-dir dist
或
babel src -d dist
6、命令简写
package.json中的
"scripts": {
"build": "babel src/index.js --out-file dist/index.js"
},
运行: cnpm run build
4、Symbol:独一无二。
string,number,boolear,null,undefind,object,
Symbol是一种数据类型。
1、声明Symbol类型的时候不需要加new
2、因为是独一无二的所以不相等
let s1=Symbol("abc");
let s2=Symbol("abc");
console.log(s1==s2);//false
console.log(s1===s2);//false
console.log(Object.is(s1,s2));//false
3、当以变量值为属性名的时候,切记不论是添加属性,还是获取属性值的时候一定一定要加上[]
var a=Symbol("abc");
var b=Symbol("abc");
var obj={
name:"haha",
[a]:"a",
[b]:"b"
}
console.log(obj[a]);
console.log(obj[b]);
4、当遍历对象的时候,如果对象下面的属性是Symbol类型的通过for...in或for....of 是遍历不出来的
5、可以通过Symbol下的for方法来添加关键词
var a=Symbol.for("abc");
var b=Symbol.for("abc");
console.log(a==b);//true
console.log(a===b);//true
console.log(Object.is(a,b));//true
6、可以通过Object.getOwnPropertySymbols来专门遍历属性是Symbol的对象。
获得对象属性是Symbols的。
将对象为Symbols的属性放到同一个数组里。
Object.getOwnPropertySymbols(obj).forEach(function(value){
console.log(obj[value]);
})
for(let key of Object.getOwnPropertySymbols(obj)){
console.log(obj[key]);
}
7、Reflect.ownKeys:返回一个数组。数组里面包含指定对象的所有属性,包括Symbol
5、Promise:是一种除了回调函数以外,另外一种解决异步操作的方案。
new Promise(function(resolve,reject){
//resolve:Promise成功的状态
//reject:Promise失败的状态。
})
Promise.all([]):将多个promise合并成一个promise.
如果有一个promise失败,就会调用reject.
如果会部成功,将所有promise返回的结果合并成一个数组来调用resolve.
Promise.race([]):多个promise,哪一个执行完毕,就用哪一个结果。
1、模块
/*************************************/
第一种:
1、导出 export
export let s=12;
export let age=66;
export let fn=function(){
alert(12);
}
2、导入 import:对象内的顺序可以随意,根据需要来导入内容。但是名字必须要和导出的一致。
import {s,fn,age} from "./m1.js";
console.log(s);
/*************************************/
第二种:
1、导出和第一种 一样
2、导入
import * as lession from "./m1.js";
/*************************************/
第三种:
1、导出
let a=12;
export default{
a
}
2、导入
import lession from "./m2.js"
ES9
1、Rest(剩余)/Spread(展开) 属性
ES6 在处理数组解构时,引入了 rest(剩余)元素的概念,例如:
const numbers = [1,2,3,4,5];
[first,second,...others] = numbers; // (5) [1, 2, 3, 4, 5]
const sum = (a,b,c,d,e)=>a+b+c+d+e;
const numSum = sum(...numbers);
console.log(numSum) // 15
ES2018 为对象引入了类似的功能。
rest(剩余) 属性:
const { first, second, ...others } = { first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
first // 1
second // 2
others // { third: 3, fourth: 4, fifth: 5 }
spread(展开) 属性 允许通过组合展开运算符 ... 之后传递的对象属性来创建新对象:
const items = { first, second, ...others }
items //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
2、Asynchronous iteration (异步迭代)
新的 for-await-of 构造允许您使用异步可迭代对象作为循环迭代:
for await (const line of readLines(filePath)) {
console.log(line)
}
由于这使用 await ,你只能在异步函数中使用它,就像普通的 await 一样(参见 async / await 章节)
3、Promise.prototype.finally()
当一个 promise 得到满足(fulfilled)时,它会一个接一个地调用 then() 方法。
如果在此期间发生错误,则跳过 then() 方法并执行 catch()方法。
finally() 允许您运行一些代码,无论 promise 的执行成功或失败:
fetch('file.json')
.then(data => data.json())
.catch(error => console.error(error))
.finally(() => console.log('finished'))
4、正则表达式改进
ES10
1、BigInt -任意精度整数
BigInt 是第七种 原始类型。
BigInt 是一个任意精度的整数。这意味着变量现在可以 表示²⁵³ 数字,而不仅仅是9007199254740992。
const b = 1n; // 追加 n 以创建 BigInt
在过去,不支持大于 9007199254740992 的整数值。如果超过,该值将锁定为 MAX_SAFE_INTEGER + 1:
const limit = Number.MAX_SAFE_INTEGER;
⇨ 9007199254740991
limit + 1;
⇨ 9007199254740992
limit + 2;
⇨ 9007199254740992 <--- MAX_SAFE_INTEGER + 1 exceeded
const larger = 9007199254740991n;
⇨ 9007199254740991n
const integer = BigInt(9007199254740991); // initialize with number
⇨ 9007199254740991n
const same = BigInt("9007199254740991"); // initialize with "string"
⇨ 9007199254740991n
等于运算符可用于两种类型之间比较:
10n === BigInt(10);
⇨ true
10n == 10;
⇨ true
数学运算符只能在自己的类型中工作:
200n / 10n
⇨ 20n
200n / 20
⇨ Uncaught TypeError:
Cannot mix BigInt and other types, use explicit conversions <
-运算符可以操作, + 不可用
-100n
⇨ -100n
+100n
⇨ Uncaught TypeError:
Cannot convert a BigInt value to a number
当你读到这篇文章的时候,matchAll 可能已经在 Chrome C73 中正式实现了——如果不是,它仍然值得一看。特别是如果你是一个正则表达式(regex)爱好者。
2、string.prototype.matchAll();
使用 .matchAll() 的好理由:
1、在与捕获组一起使用时,它可以更加优雅,捕获组只是使用 () 提取模式的正则表达式的一部分。
2、它返回一个迭代器而不是一个数组,迭代器本身是有用的。
3、迭代器可以使用扩展运算符 (…) 转换为数组。
4、它避免了带有/g标志的正则表达式,当从数据库或外部源检索未知正则表达式并与陈旧的RegEx对象一起使用时,它非常有用。
5、使用 RegEx 对象创建的正则表达式不能使用点 (.) 操作符链接。
6、高级: RegEx 对象更改跟踪最后匹配位置的内部 .lastindex 属性,这在复杂的情况下会造成严重破坏。
.matchAll() 是如何工作的?
让我们尝试匹配单词 hello 中字母 e 和 l 的所有实例, 因为返回了迭代器,所以可以使用 for…of 循环遍历它:
// Match all occurrences of the letters: "e" or "l"
let iterator = "hello".matchAll(/[el]/);
for (const match of iterator)
console.log(match);
这一次你可以跳过 /g, .matchall 方法不需要它,结果如下:
[ 'e', index: 1, input: 'hello' ] // Iteration 1
[ 'l', index: 2, input: 'hello' ] // Iteration 2
[ 'l', index: 3, input: 'hello' ] // Iteration 3
使用 .matchAll() 捕获组示例:
.matchAll 具有上面列出的所有好处。它是一个迭代器,可以用 for…of 循环遍历它,这就是整个语法的不同。
const string = 'black*raven lime*parrot white*seagull';
const regex = /(?<color>.*?)\*(?<bird>[a-z0-9]+)/;
for (const match of string.matchAll(regex)) {
let value = match[0];
let index = match.index;
let input = match.input;
console.log(`${value} at ${index} with '${input}'`);
console.log(match.groups.color);
console.log(match.groups.bird);
}
请注意已经没有 /g 标志,因为 .matchAll() 已经包含了它,打印如下:
black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull
也许在美学上它与原始正则表达式非常相似,执行while循环实现。但是如前所述,由于上面提到的许多原因,这是更好的方法,移除 /g 不会导致无限循环。
3、动态导入:现在可以将导入分配给变量:
element.addEventListener('click', async() => {
const module = await import(`./api-scripts/button-click.js`);
module.clickEvent();
});
4、Array.flat():
扁平化多维数组:
let multi = [1,2,3,[4,5,6,[7,8,9,[10,11,12]]]];
multi.flat(); // [1,2,3,4,5,6,Array(4)]
multi.flat().flat(); // [1,2,3,4,5,6,7,8,9,Array(3)]
multi.flat().flat().flat(); // [1,2,3,4,5,6,7,8,9,10,11,12]
multi.flat(Infinity); // [1,2,3,4,5,6,7,8,9,10,11,12]
5、Array.flatMap():
let array = [1, 2, 3, 4, 5];
array.map(x => [x, x * 2]);
结果:
[Array(2), Array(2), Array(2), Array(2), Array(2)]
0: (2) [1, 2]
1: (2) [2, 4]
2: (2) [3, 6]
3: (2) [4, 8]
4: (2) [5, 10]
使用 flatMap 方法:
array.flatMap(v => [v, v * 2]);
结果:
[1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
6、Object.fromEntries():将键值对列表转换为对象
let obj = { apple : 10, orange : 20, banana : 30 };
let entries = Object.entries(obj);
entries;
(3) [Array(2), Array(2), Array(2)]
0: (2) ["apple", 10]
1: (2) ["orange", 20]
2: (2) ["banana", 30]
将键值对列表转换为对象:
let fromEntries = Object.fromEntries(entries);
{ apple: 10, orange: 20, banana: 30 }
7、String.trimStart() 与 String.trimEnd()
let greeting = " Space around ";
greeting.trimEnd(); // " Space around";
greeting.trimStart(); // "Space around ";
trimStart / trimEnd 目前无法在 项目 使用,@babel/preset-env usage 模式目前无法转义,请使用其别名代替 trimLeft / trimRight
8、格式良好的 JSON.stringify:
此更新修复了字符 U+D800 到 U+DFFF 的处理,有时可以进入 JSON 字符串。 这可能是一个问题,因为 JSON.stringify 可能会将这些数字格式化为没有等效 UTF-8 字符的值, 但 JSON 格式需要 UTF-8 编码。
解析方法使用格式良好的JSON字符串,如:
'{ “prop1” : 1, "prop2" : 2 }'; // A well-formed JSON format string
注意,要创建正确 JSON 格式的字符串,绝对需要在属性名周围加上双引号。缺少或任何其他类型的引号都不会生成格式良好的JSON。
'{ “prop1” : 1, "meth" : () => {}}'; // Not JSON format string
JSON 字符串格式与 Object Literal 不同,后者看起来几乎一样,但可以使用任何类型的引号括住属性名,也可以包含方法(JSON格式不允许使用方法):
let object_literal = { property: 1, meth: () => {} };
不管怎样,一切似乎都很好。第一个示例看起来是兼容的。但它们也是简单的例子,大多数情况下都能顺利地工作!
9、稳定的 Array.prototype.sort():
V8 之前的实现对包含10个以上项的数组使用了一种不稳定的快速排序算法。
一个稳定的排序算法是当两个键值相等的对象在排序后的输出中出现的顺序与在未排序的输入中出现的顺序相同时。
但情况不再是这样了,ES10 提供了一个稳定的数组排序:
var fruit = [
{ name: "Apple", count: 13, },
{ name: "Pear", count: 12, },
{ name: "Banana", count: 12, },
{ name: "Strawberry", count: 11, },
{ name: "Cherry", count: 11, },
{ name: "Blackberry", count: 10, },
{ name: "Pineapple", count: 10, }
];
// 创建排序函数:
let my_sort = (a, b) => a.count - b.count;
// 执行稳定的ES10排序:
let sorted = fruit.sort(my_sort);
console.log(sorted);
控制台输出(项目以相反的顺序出现):
(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {name: "Blackberry", count: 10}
1: {name: "Pineapple", count: 10}
2: {name: "Strawberry", count: 11}
3: {name: "Cherry", count: 11}
4: {name: "Pear", count: 12}
5: {name: "Banana", count: 12}
6: {name: "Apple", count: 13}
10、新的Function.toString():
函数是对象,并且每个对象都有一个 .toString() 方法,因为它最初存在于Object.prototype.toString() 上。 所有对象(包括函数)都是通过基于原型的类继承从它继承的。
这意味着我们以前已经有 funcion.toString() 方法了。
但是 ES10 进一步尝试标准化所有对象和内置函数的字符串表示。 以下是各种新案例:
典型的例子:
function () { console.log('Hello there.'); }.toString();
控制台输出(函数体的字符串格式:)
⇨ function () { console.log('Hello there.'); }
下面是剩下的例子:
直接在方法名 .toString()
Number.parseInt.toString();
⇨ function parseInt() { [native code] }
绑定上下文:
function () { }.bind(0).toString();
⇨ function () { [native code] }
内置可调用函数对象:
Symbol.toString();
⇨ function Symbol() { [native code] }
动态生成的函数:
function* () { }.toString();
⇨ function* () { }
prototype.toString
Function.prototype.toString.call({});
⇨ Function.prototype.toString requires that 'this' be a Function"
11、可选的 Catch Binding
12、标准化 globalThis 对象:
这在ES10之前, globalThis 还没有标准化。
在产品代码中,你可以自己编写这个怪物,在多个平台上“标准化”它:
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
但即使这样也不总是奏效。因此,ES10 添加了 globalThis 对象,从现在开始,该对象用于在任何平台上访问全局作用域:
// 访问全局数组构造函数
globalThis.Array(0, 1, 2);
⇨ [0, 1, 2]
// 类似于 ES5 之前的 window.v = { flag: true }
globalThis.v = { flag: true };
console.log(globalThis.v);
⇨ { flag: true }
13、Symbol.description
description 是一个只读属性,它返回 Symbol 对象的可选描述。
let mySymbol = 'My Symbol';
let symObj = Symbol(mySymbol);
symObj; // Symbol(My Symbol)
symObj.description; // "My Symbol"
14、ES10类:private、static 和 公共成员: 非常不推荐,但是推荐es11
新的语法字符 #octothorpe(hash tag)现在用于直接在类主体的范围内定义变量,函数,getter 和 setter ......以及构造函数和类方法。
下面是一个毫无意义的例子,它只关注新语法:
class Raven extends Bird {
#state = { eggs: 10};
// getter
get #eggs() {
return state.eggs;
}
// setter
set #eggs(value) {
this.#state.eggs = value;
}
#lay() {
this.#eggs++;
}
constructor() {
super();
this.#lay.bind(this);
}
#render() {
/* paint UI */
}
}
老实说,我认为这会让语言更难读。
ES11
1、Optional Chaining 可选链式调用:?.
1.1、访问对象的属性:
const flower = {
colors: {
red: true
}
}
console.log(flower.colors.red) // 正常运行
正常console.log(flower.species.lily) // 抛出错误:TypeError: Cannot read property 'lily' of undefined
我们可以使用由一个问号和一个点组成的可选链式操作符,去表示不应该引发错误。如果没有值,应该返回 undefined。如下
es11: console.log(flower.species?.lily) // 输出 undefined
1.2、访问数组:
let flowers = ['lily', 'daisy', 'rose']
console.log(flowers[1]) // 输出:daisy
flowers = null
console.log(flowers[1]) // 抛出错误:TypeError: Cannot read property '1' of null
console.log(flowers?.[1]) // 输出:undefined
1.3、调用函数:
let plantFlowers = () => {
return 'orchids'
}
console.log(plantFlowers()) // 输出:orchids
plantFlowers = null
console.log(plantFlowers()) // 抛出错误:TypeError: plantFlowers is not a function
console.log(plantFlowers?.()) // 输出:undefined
2、Nullish Coalescing 空值合并: ??
let number = 1
let myNumber = number || 7
console.log(myNumber) // 7
let number = 0
let myNumber = number || 7
console.log(myNumber) // 7
let number = 0
let myNumber = number ?? 7
console.log(myNumber) // 0
3、Private Fields 私有字段:#
JavaScript 从 ES6 开始支持类语法,但直到现在才引入了私有字段。要定义私有属性,必须在其前面加上散列符号:#。
class Flower {
#leaf_color = "green";
constructor(name) {
this.name = name;
}
get_color() {
return this.#leaf_color;
}
}
const orchid = new Flower("orchid");
console.log(orchid.get_color()); // 输出:green
如果我们从外部访问类的私有属性,势必会报错。
console.log(orchid.#leaf_color) // 报错:SyntaxError: Private field '#leaf_color' must be declared in an enclosing class
4、Static Fields 静态字段:static
如果想使用类的方法,首先必须实例化一个类,如下所示:
class Flower {
add_leaves() {
console.log("Adding leaves");
}
}
const rose = new Flower();
rose.add_leaves();
Flower.add_leaves() // 抛出错误:TypeError: Flower.add_leaves is not a function
试图去访问没有实例化的 Flower 类的方法将会抛出一个错误。但由于 static 字段,类方法可以被 static 关键词声明然后从外部调用。
class Flower {
constructor(type) {
this.type = type;
}
static create_flower(type) {
return new Flower(type);
}
}
const rose = Flower.create_flower("rose"); // 正常运行
5、Top Level Await 顶级 Await
目前,如果用 await 获取 promise 函数的结果,那使用 await 的函数必须用 async 关键字定义。
const func = async () => {
const response = await fetch(url)
}
头疼的是,在全局作用域中去等待某些结果基本上是不可能的。除非使用 立即调用的函数表达式(IIFE)。
(async () => {
const response = await fetch(url)
})()
但引入了 顶级 Await 后,不需要再把代码包裹在一个 async 函数中了,如下即可:
const response = await fetch(url);
这个特性对于解决模块依赖或当初始源无法使用而需要备用源的时候是非常有用的。
let Vue
try {
Vue = await import('url_1_to_vue')
} catch {
Vue = await import('url_2_to_vue')
}
6、Promise.allSettled 方法:
等待多个 promise 返回结果时,我们可以用 Promise.all([promise_1, promise_2])。但问题是,如果其中一个请求失败了,就会抛出错误。然而,有时候我们希望某个请求失败后,其他请求的结果能够正常返回。针对这种情况 ES11 引入了 Promise.allSettled 。
promise_1 = Promise.resolve('hello')
promise_2 = new Promise((resolve, reject) => setTimeout(reject, 200, 'problem'))
Promise.allSettled([promise_1, promise_2])
.then(([promise_1_result, promise_2_result]) => {
console.log(promise_1_result) // 输出:{status: 'fulfilled', value: 'hello'}
console.log(promise_2_result) // 输出:{status: 'rejected', reason: 'problem'}
})
成功的 promise 将返回一个包含 status 和 value 的对象,失败的 promise 将返回一个包含 status 和 reason 的对象。
7、Dynamic Import 动态引入 不常用
// Alert.js
export default {
show() {
// 代码
}
}
// 使用 Alert.js 的文件
import('/components/Alert.js')
.then(Alert => {
Alert.show()
})
8、MatchAll 匹配所有项
const regex = /\b(apple)+\b/;
const fruits = "pear, apple, banana, apple, orange, apple";
for (const match of fruits.match(regex)) {
console.log(match);
}
// 输出
//
// 'apple'
// 'apple'
相比之下,matchAll 返回更多的信息,包括找到匹配项的索引。
for (const match of fruits.matchAll(regex)) {
console.log(match);
}
// 输出
//
// [
// 'apple',
// 'apple',
// index: 6,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ],
// [
// 'apple',
// 'apple',
// index: 21,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ],
// [
// 'apple',
// 'apple',
// index: 36,
// input: 'pear, apple, banana, apple, orange, apple',
// groups: undefined
// ]
9、globalThis 全局对象
JavaScript 可以在不同环境中运行,比如浏览器或者 Node.js。浏览器中可用的全局对象是变量 window,但在 Node.js 中是一个叫做 global 的对象。为了在不同环境中都使用统一的全局对象,引入了 globalThis 。
// 浏览器
window == globalThis // true
// node.js
global == globalThis // true
10、BigInt
JavaScript 中能够精确表达的最大数字是 2^53 - 1。而 BigInt 可以用来创建更大的数字。
const theBiggerNumber = 9007199254740991n
const evenBiggerNumber = BigInt(9007199254740991)