ES6-基础

1.开始之前

在安装Babel之前,需要用npm init先初始化我们的项目。打开终端或者通过cmd打开命令行工具,进入项目目录,输入下边的命令:

1
npm init -y // 自动生成package.json文件

需求:如何将dist文件夹中的js将es6转化为es5编程。

1
2
3
4
npm install -g babel-cli
npm install --save-dev babel-preset-es2015 babel-cli
//编译命令
babel src/index.js -o dist/index.js

2.声明方式

ES6的三种声明方式:

  1. var:声明全局变量;
  2. let:声明局部变量,防止数据污染;
  3. const:声明常量,用来定义一个不可变的常量,如果改变了就会报语法错误。

VAR

1
2
3
4
5
var a = 'abc';
window.onload = function () {
console.log(a);
}
控制台打印出:abc,说明var声明的a是全局变量

LET

1
2
3
4
5
6
7
{
let a = 'abc';
}
window.onload = function () {
console.log(a);
}
结果:报错。说明let声明的是局部变量,它只在它所在的语句块中有用。

CONST

1
2
3
var a = "abc";
const a = "efg";
console.log(a);

会报语法错误:

3.解构赋值

什么是解构?ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。

解构的作用?解构赋值在实际开发中可以大量减少我们的代码量,并且让我们的程序结构更清晰。

数组的结构赋值:

1
2
3
4
5
6
let a=0;
let b=1;
let c=2;
//等同于
let [a,b,c] = [0,1,2];
//按照位置的对象关系对变量赋值
1
2
3
数组模式和赋值模式统一:
 
可以简单的理解为等号左边和等号右边的形式要统一,如果不统一解构将失败。

数组函数的解构赋值

1
2
3
4
5
6
7
let arr = ['good','better','best'];
function fn(a,b,c) {
console.log(a); //good
console.log(b); //better
console.log(c); //best
}
fn(...arr); //...对象扩展运算符,在后面会说到

解构的默认值:

解构赋值是允许你使用默认值的

1
2
let [foo = true] =[];
console.log(foo); //控制台打印出true
1
2
3
let [a,b="world"]=['hello '];
console.log(a+b); //控制台显示“hello world”
//hello为a的值,b的默认值为world,所以显示“hello world”

注意:undefined 和 null的区别

1
2
3
let [a,b="world"]=['hello ',undefined];
console.log(a+b); //控制台显示“hello world”
//说明undefined表示空
1
2
3
let [a,b="world"]=['hello ',undefined];
console.log(a+b); //控制台显示“hello null”
//null 表示有值

对象的解构赋值

1
2
let {a,b} ={a:"abc",b:"123"};
console.log(a+b); //控制台显示:"abc123"

注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

对象函数的解构赋值

1
2
3
4
5
6
7
8
9
let json = {
a:'abc',
b: 123
};
function fn({a,b=456}) {
console.log(a); //abc
console.log(b); //123
}
fn(json);

es6小坑:

1
2
3
4
5
6
7
8
9
//当先声明了对象,然后再对象解构,这会报错
let foo;
{foo} = {foo: "abc"};
console.log(foo);
 
//解决方法:解构时加一个圆括号
let foo;
({foo} = {foo: "abc"});
console.log(foo); //控制台显示:abc

字符串的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
const [a,b,c,d,e]="hello";
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
//控制台显示:
//h
//e
//l
//l
//o

4.对象扩展运算符和rest运算符

对象扩展运算符(…)

当编写一个方法时,我们允许它传入的参数是不确定的,这时候可以使用对象扩展运算符来作参数。

1
2
3
4
5
6
7
8
function fn(...arg) {
console.log(arg[0]);
console.log(arg[1]);
console.log(arg[2]);
console.log(arg[3]);
}
fn(1,2,3);
//控制台显示: 1 2 3 undefined

作用:用来解决数组赋值会改变原数组数据的问题。

1
2
3
4
5
let arr1 = ['a','b','c'];
let arr2 = arr1;
arr2.push("d");
console.log(arr2); //控制台显示:["a", "b", "c", "d"]
console.log(arr1); //控制台显示:["a", "b", "c", "d"] arr1改变了,这个是非常不好的。

使用对象扩展运算符后

1
2
3
4
5
let arr1 = ['a','b','c'];
let arr2 = [...arr1];
arr2.push("d");
console.log(arr2); //控制台显示:["a", "b", "c", "d"]
console.log(arr1); //控制台显示:["a", "b", "c"] arr1没有改变

REST运算符(…)

也用”…”表示

用法:

1
2
3
4
5
6
7
8
9
10
11
function fn(a,b,...arg) {
console.log(a); //0
console.log(b); //1
console.log(arg.length); //6
for(let val of arg){
console.log(val); //2,3,4,5,6,7
}
}
fn(0,1,2,3,4,5,6,7);
//可以看出a表示第一个值,b表示第二个值,...arg表示剩余的值
//所以a的值为0,b的值为1,...arg的值为剩余的值2,3,4,5,6,7

5.字符串模板

使用方法:字符串必须使用’`’(~下面的符号)包围,然后使用${变量}。

1
2
3
let name = 'whittney';
let str = `大家好,我是${name}`;
document.write(str);

字符串的方法:

1.查找是否存在:includes()

1
2
3
let name = 'whittney';
let str = `大家好,我是${name}`;
console.log(str.includes(name)); //true

2.判断开头是否存在:startsWith()

1
2
3
let name = 'whittney';
let str = `大家好,我是${name}`;
console.log(str.startsWith(name)); //false

3.判断结尾是否存在:endsWith()

1
2
3
let name = 'whittney';
let str = `大家好,我是${name}`;
console.log(str.endsWith(name)); //true

4.复制字符串:repeat()

1
2
let name = 'whittney';
console.log(name.repeat(3)); //whittneywhittneywhittney

6.数字操作

1.如何表示二进制数?

二进制的英文单词是Binary,以0(零)和b(或B)开头,后面为二进制值即可。

1
2
let binary = 0b0101;
console.log(binary); //5

2.如何表示八进制数?

八进制的英文单词是Octal,以0(零)和o(或O)开头,后面为八进制值即可。

1
2
let octal = 0o0032;
console.log(octal); //26

3.判断是否是数字

Number.isFinite( )来进行数字验证,只要是数字,不论是浮点型还是整形都会返回true,其他时候会返回false。

1
2
let a = 'a';
console.log(Number.isFinite(a)); //false

4.判断是否为整数Number.isInteger(xx)

1
2
let a=111.123;
console.log(Number.isInteger(a)); //false

5.转换为整数

1
2
let a= '111.123';
console.log(Number.parseInt(a)); //111

6.转换为浮点数

1
2
let a= '111.123';
console.log(Number.parseFloat(a)); //111.123

7.ES6中新增的数组知识

1.json数组格式是什么样的?

1
2
3
4
5
6
7
let json = {
'0': 'a',
'1': 'b',
'2': 'c',
length:3
}
//JSON数组格式跟普通的JSON对比是在最后多了一个length属性

如何将json数组转化为数组?

1
2
3
4
5
6
7
let json = {
'0': 'a',
'1': 'b',
'2': 'c',
}
let arr = Array.from(json);
console.log(arr); //["a", "b", "c"]

2.Array.of()方法

将一堆文本或者变量转换成数组

1
2
let arr = Array.of("abc",3,5);
console.log(arr); //["abc",3,5]

3.find()方法

从数组中查找元素

有三个参数:

val:表示当前查找的值;

index:表示当前查找的数组索引;

arr:表示当前数组。

1
2
3
4
5
let arr = [1,3,5,7,9];
console.log(arr.find(function (val,index,arr) {
return val >5;
})) //7
// 函数中如果找到符合条件的数组元素就进行return

4.fill()方法

数组进行填充,其实就是替换数组元素。

也有三个参数:第一个参数是要填充的内容,第二个参数是开始填充的位置,第三个是填充到的位置(不包括)。

1
2
3
let arr = [0,1,2,3];
arr.fill('abc',1,3);
console.log(arr); //[0, "abc", "abc", 3]

5.for..of循环

输出内容

1
2
3
4
let arr = ['a','b','c'];
for(let item of arr){
console.log(item); //a,b,c
}

输出索引

1
2
3
4
let arr = ['a','b','c'];
for(let index of arr.keys()){
console.log(index); //0,1,2
}

同时输出内容和索引

1
2
3
4
5
6
7
let arr = ['a','b','c'];
for(let [index,val] of arr.entries()){
console.log(index+':'+val);
}
//控制台输出:0:a
// 1:b
// 2:c

6.entries()

生成的是Iterator形式的数组,好处就是可以让我们在需要时用next()手动跳转到下一个值。

1
2
3
4
5
6
let arr = ['a','b','c'];
let list = arr.entries();
console.log(list.next().value); // [0, "a"]
console.log(list.next().value); // [1, "b"]
console.log(list.next().value); // [2, "c"]
//输出内容是数组,第一个值为所在arr的索引,第二只为arr中所在索引的内容。

7.in

判断对象或者数组中是否存在某个值。

对象判断:

1
2
3
4
5
let obj = {
a: 'abc',
b: 123
}
console.log('a' in obj); //true 注意:a元素要用引号

数组判断:

1
2
let arr= ['a','b'];
console.log(0 in arr); //true 注意:0表示索引,0指的是数组下标位置是否为空。

8.箭头函数

ES6中给我们增加了默认值的操作

1
2
3
4
function add(a,b=3) {
return a+b;
}
console.log(add(1)); //没有报错,显示:4

主动抛出错误:vue框架中就是这样抛出错误的。

1
2
3
4
5
6
7
function add(a,b=3) {
if(a == 0){
throw new Error("a is error");
}
return a+b;
}
console.log(add(0));

获得需要传递的参数个数

如果你在使用别人的框架时,不知道别人的函数需要传递几个参数怎么办?ES6为我们提供了得到参数的方法(xxx.length)。

1
2
3
4
function add(a,b) {
return a+b;
}
console.log(add.length); //2

两个坑:

(1)如果既使用默认值,又使用严谨模式的话,就会产生冲突。

1
2
3
4
5
function add(a,b=3) {
'use strict'
return a+b;
}
console.log(add(2));

(2)当参数中有默认值时,获取需要传递的参数个数时,不会计算有默认值的参数。所以这里需要注意的是add.length返回的参数个数是必须传递参数的个数。

1
2
3
4
function add(a,b=2) {
return a+b;
}
console.log(add.length); //1

这里说明一下,b的值不一定为2,也可以重新赋值

1
2
3
4
function add(a,b=2) {
return a+b;
}
console.log(add(2,4)); //6

箭头函数

如果箭头函数就一句,可以直接这么写

1
2
let add = (a,b=1)=> a+b;
console.log(add(2)); //3

否则需要加上花括号以及return

1
2
3
4
let add = (a,b=1)=> {
return a+b;
}
console.log(add(2)); //3

箭头函数中不可加new,也就是说箭头函数不能当构造函数进行使用。

9.ES6中的对象

对象赋值

之前对象赋值是这样的

1
2
3
4
let name = 'whittney';
let skill = 'web';
let obj = {name: name,skill:skill};
console.log(obj);

现在可以这样写

1
2
3
4
let name = 'whittney';
let skill = 'web';
let obj = {name,skill};
console.log(obj);

对象KEY值构建

1
2
3
4
5
let key = 'name';
let obj = {
[key]:'whittney'
};
console.log(obj);

OBJECT.IS( )方法进行对象比较

1
2
3
let obj1 = {name: 'whittney'};
let obj2 = {name: 'lily'};
console.log(Object.is(obj1.name,obj2.name)); //false

10.Symbol数据类型

1
2
let a = Symbol();
console.log(typeof a); //symbol

symbol数据类型和string数据类型的区别?

1
2
3
let a = Symbol('whittney');
console.log(a); //symbol数据类型,字体颜色为红色
console.log(a.toString()); //string数据类型,字体颜色为黑色

SYMBOL对象元素的保护作用

没有使用symbol之前

1
2
3
4
let obj = {name:'whittney',skill: 'web',age: 18};
for(let item in obj){
console.log(obj[item]); //输出 whittney web 18
}

假如这时有一个需求:不想打印出age

1
2
3
4
5
6
7
let obj = {name:'whittney',skill: 'web'};
let age = Symbol();
obj[age] = 18;
for(let item in obj){
console.log(obj[item]); //whittney web
}
console.log(obj); //{name:'whittney',skill: 'web',Symbol(): 18}

11.Set和WeakSet数据结构

SET数据结构(数组)

Set和Array 的区别是Set不允许内部有重复的值,如果有只显示一个,相当于去重。虽然Set很像数组,但是他不是数组。而且Set数据结构只能放数组。

1
2
let setData =new Set(['whittney','lily','lily','tina']);
console.log(setData); //Set(3) {"whittney", "lily", "tina"} 没有两个’lily‘,说明不能有相同的值

Set数据结构的增删查,没有改

(1)增:setData.add()

1
2
3
4
let setData =new Set(['whittney','lily','tina']);
console.log(setData); //Set(3) {"whittney", "lily", "tina"}
setData.add('jack');
console.log(setData); //Set(4) {"whittney", "lily", "tina", "jack"}

(2)删:setData.delete()

1
2
3
4
let setData =new Set(['whittney','lily','tina']);
console.log(setData); //Set(3) {"whittney", "lily", "tina"}
setData.delete('lily');
console.log(setData); //Set(2) {"whittney", "tina"}

(3)查:setData.has(),返回的是true或者false。

1
2
let setData =new Set(['whittney','lily','tina']);
console.log(setData.has('lily')); //true

(4)删除所有值:setData.clear();

1
2
3
let setData =new Set(['whittney','lily','tina']);
setData.clear();
console.log(setData); //Set(0) {}

(5)for…of…循环

1
2
3
4
let setData =new Set(['whittney','lily','tina']);
for(let item of setData){
console.log(item);
}

(6)forEach循环

1
2
3
4
let setData =new Set(['whittney','lily','tina']);
setData.forEach(function (item) {
console.log(item);
})

WEAKSET数据结构(对象)

WeakSet数据结构只能放数组。WeakSet里边的值也是不允许重复的。

1
2
3
4
let weakObj = new WeakSet();
let obj = { a:'abc',b:'efg'};
weakObj.add(obj);
console.log(weakObj);

坑:

1
如果你直接在new 的时候就放入值,将报错。

12.map数据结构

map的效率和灵活性更好。

(1)set():赋值

1
2
3
4
5
6
7
let json = {
name: 'whittney',
skill: 'web'
};
var map = new Map();
map.set(json,'js');
console.log(map);

(2)get():取值

1
2
3
4
5
6
7
8
9
10
let json = {
name: 'whittney',
skill: 'web'
};
var map = new Map();
map.set(json,'js'); //key:{name: "whittney", skill: "web"} value:"js"
map.set("iam",json);
console.log(map.get(json)); //'js'
console.log(map.get('iam')); //{name: "whittney", skill: "web"}
//由此可见,get获取的是map数据结构中的key值。

(3)delete():删除

1
2
3
4
5
6
7
8
let json = {
name: 'whittney',
skill: 'web'
};
var map = new Map();
map.set(json,'js'); //key:{name: "whittney", skill: "web"} value:"js"
map.delete(json);
console.log(map); //Map(0) {}

(4)map.has():查找是否有key为某某的map

1
2
3
4
5
6
7
8
let json = {
name: 'whittney',
skill: 'web'
};
var map = new Map();
map.set(json,'js'); //key:{name: "whittney", skill: "web"} value:"js"
console.log(map.has('js')); //false 查找key为'js'的map
console.log(map.has(json)); //true 查找key为json的map

(5)clear():清楚所有map

1
2
3
4
5
6
7
8
let json = {
name: 'whittney',
skill: 'web'
};
var map = new Map();
map.set(json,'js'); //key:{name: "whittney", skill: "web"} value:"js"
map.clear();
console.log(map);

13.用Proxy进行预处理

声明Proxy

1
2
3
4
5
let pro = new Proxy({
 
},{
// get set apply
})

第一个花括号就相当于我们方法的主体,后边的花括号就是Proxy代理处理区域,相当于我们写钩子函数的地方。

get属性

get属性是在你得到某对象属性值时预处理的方法,他接受三个参数:

target:得到的目标值

key:目标的key值,相当于对象的属性

property:这个不太清楚

1
2
3
4
5
6
7
8
9
10
11
12
13
let pro = new Proxy({
add: function (val) {
return val+100;
},
name: 'whittney'
},{
get: function (target,key,property) {
console.log(target); //{add: ƒ, name: "whittney"}
console.log(key); //name
return target[key]; //所以获取name,写法为target[key]
}
})
console.log(pro.name); //whittney

可以在控制台看到结果,先输出了target和key的值。相当于在方法调用前的钩子函数。

set属性

set属性是值你要改变Proxy属性值时,进行的预先处理。它接收四个参数。

target:目标值。

key:目标的Key值。

value:要改变的值。

receiver:改变前的原始值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let pro = new Proxy({
add: function (val) {
return val+100;
},
name: 'whittney'
},{
get: function (target,key,property) {
return target[key];
},
set: function (target,key,value,receiver) {
console.log(`setting ${key} = ${value}`); //setting name = lily
return target[key] = value;
}
})
console.log(pro.name); //whittney
pro.name='lily';
console.log(pro.name); //lily
//运行顺序是:
// whittney
// setting name = lily
// lily
apply属性

apply的作用是调用内部的方法,它使用在方法体是一个匿名函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
let target = function () {
return 'whittney';
};
var handler = {
apply(target, ctx, args) {
console.log('do apply');
return Reflect.apply(...arguments);
}
}
 
var pro = new Proxy(target, handler);
 
console.log(pro()); //do apply whittney

14.Promise

ES6中的promise很好的解决了回调地狱的问题。

什么是回调地狱?

回调地狱指的是多层嵌套回调时,写完的代码层次过多,很难进行维护和二次开发。

1
2
3
4
5
6
7
function fn1() {
function fn2() {
function fn3() {
...
}
}
}

PROMISE的基本用法

promise执行多步操作非常好用,那我们就来模仿一个多步操作的过程,那就以吃饭为例吧。要想在家吃顿饭,是要经过三个步骤的。

  1. 洗菜做饭。
  2. 坐下来吃饭。
  3. 收拾桌子洗碗。

这个过程是有一定的顺序的,你必须保证上一步完成,才能顺利进行下一步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
let state = 1;
function step1(resolve,reject) {
console.log("1.开始-做饭");
if(state == 1){
resolve("做饭--成功");
}else{
reject("做饭--错误");
}
}
function step2(resolve,reject) {
console.log("2.开始-吃饭");
if(state == 1){
resolve("吃饭--成功");
}else{
reject("吃饭--错误");
}
}
function step3(resolve,reject) {
console.log("3.开始-洗碗");
if(state == 1){
resolve("洗碗--成功");
}else{
reject("洗碗--错误");
}
}
 
new Promise(step1).then(function (val) {
console.log(val);
return new Promise(step2);
}).then(function (val) {
console.log(val);
return new Promise(step3);
}).then(function (val) {
console.log(val);
});
//1.开始-做饭
//做饭--成功
//2.开始-吃饭
//吃饭--成功
//3.开始-洗碗
//洗碗--成功

假如有中间有一个步骤失败,后面的步骤就不会进行下去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
let state = 1;
function step1(resolve,reject) {
console.log("1.开始-做饭");
if(state == 1){
resolve("做饭--成功");
}else{
reject("做饭--错误");
}
}
function step2(resolve,reject) {
console.log("2.开始-吃饭");
if(state == 1){
resolve("吃饭--成功");
}else{
reject("吃饭--错误");
}
}
function step3(resolve,reject) {
console.log("3.开始-洗碗");
let state = 2;
if(state == 1){
resolve("洗碗--成功");
}else{
reject("洗碗--错误");
}
}
 
new Promise(step1).then(function (val) {
console.log(val);
return new Promise(step2);
}).then(function (val) {
console.log(val);
return new Promise(step3);
}).then(function (val) {
console.log(val);
});
//1.开始-做饭
//做饭--成功
//2.开始-吃饭
//Uncaught (in promise) 吃饭--错误

15.类

类的使用

1
2
3
4
5
6
7
8
9
10
11
class Coder {
name(val){
return val; //这里没有返回值的话,后面使用name方法时会输出undefined
}
skill(val){
console.log(this); //this指的是Coder类
console.log(this.name('whittney')+':'+val);
}
}
let code = new Coder();
code.skill('web'); //whittney:web

注意:

1.两个方法中间不要写逗号;

2.这里的this指类本身;

3.注意return 的用法。

类的传参

用constructor( )进行传参,传递参数后可以直接使用this.xxx进行调用。

1
2
3
4
5
6
7
8
9
10
11
class Coder {
constructor(a,b){
this.a = a;
this.b = b;
}
add(){
return this.a + this.b;
}
}
let code = new Coder(2,3);
console.log(code.add()); //5

类的继承

声明一个htmler的新类并继承Coder类,htmler新类里边为空,这时候我们实例化新类,并调用里边的name方法。结果也是可以调用到的。注:使用extends继承。

1
2
3
4
5
6
7
8
9
10
class Coder{
name(val){
console.log(val);
}
}
class htmler extends Coder{
 
}
let code = new htmler;
code.name('whittney'); //whittney

16.模块化

模块化操作主要包括两个方面。

​ export :负责进行模块化,也是模块的输出。

​ import : 负责把模块引,也是模块的引入操作。

模块化基本使用

在src目录下新建一个temp.js文件,就是一个模块。里面代码如下,输出一个模块变量:

1
export var name = 'whittney';

在src目录的index.js文件中以import的形式引入:

1
2
import {name} from './temp';
console.log(name);

注意:

ES6的模块化不能直接在浏览器中预览,必须要使用Babel进行编译之后正常看到结果。

编译方法为:

一般我们的终端路径为项目名称下,如:project> 。但是执行以下命令时,需要进入project/src> 路径下

1
babel-node index.js

如何输出多个变量?

方法:把它们包装成对象就可以了。

temp.js文件

1
2
3
4
5
6
7
8
var a = 1;
var b = 2;
var c = 3;
export {a,b,c};
export function add(arg1,arg2){
return arg1+arg2;
}
//可以有多个export

index.js

1
2
3
4
5
import {a,b,c,add} from './temp';
console.log(a); //1
console.log(b); //2
console.log(c); //3
console.log(add(2,5)); //7

使用AS避免暴露模块里面的变量名称

给模块起一个更语义话的名称,输出和输入时直接使用该名称。比如:a as x 意思是给模块a另起一个名称x,避免模块a的名称暴露。

temp.js文件

1
2
3
4
5
6
7
8
var a = 1;
var b = 2;
var c = 3;
export {
a as x,
b as y,
c as z
}

index.js

1
2
3
4
import {x,y,z} from './temp';
console.log(x);
console.log(y);
console.log(z);

EXPORT DEFAULT的使用

temp.js文件

1
2
var a = 'whittney';
export default a;

index.js文件

1
2
import str from './temp';
console.log(str); //whittney

EXPORT和EXPORT DEFAULT的区别

export和export default最大的区别就是export不限变量数 可以一直写,而export default 只输出一次 而且 export出的变量想要使用必须使用{}来盛放,而export default 不需要 只要import任意一个名字来接收对象即可。

二、Array.includes()

在ES5,Array已经提供了indexOf用来查找某个元素的位置,如果不存在就返回-1,但是这个函数在判断数组是否包含某个元素时有两个小不足,第一个是它会返回-1和元素的位置来表示是否包含,在定位方面是没问题,就是不够语义化。另一个问题是不能判断是否有NaN的元素。

const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', NaN]
console.log('%s', arr1.indexOf(NaN))

结果:

-1

ES6提供了Array.includes()函数判断是否包含某一元素,除了不能定位外,解决了indexOf的上述的两个问题。它直接返回true或者false表示是否包含元素,对NaN一样能有效。

const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', NaN]
console.log('%s', arr1.includes('c'))
console.log('%s', arr1.includes('z'))
console.log('%s', arr1.includes(NaN))

结果:

true
false
true

includes()函数的第二个参数表示判断的起始位置。

const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', NaN]
console.log('%s', arr1.includes('d', 1))
console.log('%s', arr1.includes('d', 3))
console.log('%s', arr1.includes('d', 4))

结果:

true
true
false

第二个参数也可以是负数,表示从右数过来第几个,但是不改变判断搜索的方向,搜索方向还是从左到右。

console.log('%s', arr1.includes('k', -1))
console.log('%s', arr1.includes('k', -2))
console.log('%s', arr1.includes('i', -3))

结果:

原文地址:https://www.cnblogs.com/sylvia-Camellia/p/11001877.html