ES6新特性:解构、对象扩展、函数扩展、数组扩展、数值扩展

解构

1、什么是解构

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring),解构的本质属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。一般具有Iterator接口的数据数据类型能够进行解构操作。

2、数组解构

拓展运算符

拓展运算符使用三个点(…)表示。将一个数组转为用逗号分隔的参数序列。
例如:

let arr1 = [1,2,3];
let arr2 = [4,5,6];

// 数组合并
let arr = [...arr1,...arr2];
console.log(arr);
// 打印出:[1,2,3,4,5,6]

//数组复制
let arr3 = [...arr1]; 
console.log(arr3); //[1,2,3]

// 字符串转换为数组
let temp = [..."hello"];
console.log(temp);
// 打印出:['h','e','l','l','o']

// 将伪数组转为真数组
/*
<div></div>
<div></div>
<div></div>
*/
const divs = document.querySelectorAll("div");
const divArr = [...divs];
console.log(divArr);

为数组转为真数组结果:
在这里插入图片描述

数组解构

以前为变量赋值时只能直接指定值,如下

let a = 1;
let b = 2;
let c = 3;

ES6 允许写成下面这样。等号左边的变量放到中括号内部,匹配右侧数组中的元素。

let [a, b, c] = [1, 2, 3]; 

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
看如下例子:

//注意变量与值会按照索引一一对应
let [foo, [[bar], baz]] = [1, [[2], 3]];
//结果如下:
console.log(foo); // 1
console.log(bar); // 2
console.log(baz); // 3

//当未指定变量名时
let [ , , third] = ["foo", "bar", "baz"];
//结果如下:
console.log(third); // "baz"

//与索引一一对应
let [x, , y] = [1, 2, 3];
x // 1
y // 3

//...变量名 表示匹配前面变量未匹配到的值,存在数组中
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

//如果解构不成功,变量的值就等于undefined
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

let [bar, foo] = []; 
let [bar, foo] = [1];
//以上两种情况都属于解构不成功,`foo`的值都会等于`undefined`

不完全解构

不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2    //[b]和[2,3]的模式相同,但只会匹配到2
d // 4

如果等号的右边不是数组(或者严格地说,不是可遍历的结构)那么将会报错.

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

// 可以正常解构
let [a] = 'hello';
a // 'h'

上面的六个表达式都会报错,因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。原生具备 Iterator 接口的数据结构:Array、Map、Set、String、TypedArray、arguments、NodeList 等。

默认值
解构赋值允许指定默认值。注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [x, y = 'b'] = ['a'];   
// x='a', y='b’

//默认值也可以为函数
function f() { console.log('aaa'); } 
let [x = f()] = [1]; 
// x = 1,该f函数不会执行,函数在x取到undefined的时候才会执行,并将返回值赋值给x,如下
let [y = f] = []; 
// y = f
let [z = f()] = [];
// z = undefined

3、对象解构

对象解构指的是将等号左边的变量放到大括号内部,匹配右侧数组中的元素。
对象的属性没有次序,变量必须与属性同名,才能取到正确的值。如下:

let { foo, bar } = { foo: "aaa", bar: "bbb" };	
// foo = "aaa"; bar = "bbb"

重命名结构
如果变量名与属性名不一致,必须写成下面这样进行重命名。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };  
// baz = "aaa"

这实际上说明,对象的解构赋值是下面形式的简写。

let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

嵌套解构

let obj = { p: [ "Hello", { y: "World" } ] };   
let { p: [x, { y }] } = obj;  
// x = "Hello”; y = "World"

默认值

默认值生效的条件是,对象的属性值严格等于undefined

let {x: y = 3} = { x: 1 }; 
// y = 1
let {x: y = 3} = {}; 
// y = 3

运算符…
...用到等号左侧是聚合, ...用到等号右侧就是展开

let obj = { name: 'zhangsan', age: 12 }
//==========================================

let {...person} = obj // 赋值

console.log(person); // { name: 'zhangsan', age: 12 }
 
console.log(person === obj) // false 说明person是一个新对象

person.gender = "男" // 给person对象添加新的属性和属性值
console.log(person) // { name: 'zhangsan', age: 12, gender: '男' }

//==========================================
let stu = {
  ...obj,
  gender: '1'
}
console.log(stu) //{ name: 'zhangsan', age: 12, gender: '1' }

let {gender="2",...zs} = stu;
console.log(gender,zs)//1 { name: 'zhangsan', age: 12 }

4、字符串解构

等号左边的变量如果放在中括号内进行的类似于数组解构,从字符串中获取指定字符;如果放在大括号内进行的类似于对象解构,从实例属性获方法中解构。

const [a, b, c, d, e] = 'hello';   
// a = h;b = e;c = l;d = l;e = o

//将string字符串转成数组
let [...arr] = 'hello';
console.log(arr); //[ 'h', 'e', 'l', 'l', 'o' ]

// 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len // 5

5、其他不咋用解构

数值解构

等号左边的变量放在大括号中进行解构,可以获取到数值包装器构造函数原型中指定的方法。

let { valueOf } = 12;   
// valueOf = Number.prototype.valueOf

布尔类型解构

等号左边的变量放在大括号中进行解构,可以获取到布尔包装器构造函数原型中指定的方法。

let { valueOf } = true;   
// valueOf = Boolean.prototype.valueOf

6、嵌套赋值

let obj = {};
let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });

obj // {prop:123}
arr // [true]

圆括号的使用

解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。

由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。

但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。
在这里插入图片描述

在这里插入图片描述

补充

(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x;
({x} = {x: 1});

(2)解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。

({} = [true, false]);
({} = 'abc');
({} = []);

上面的表达式虽然毫无意义,但是语法是合法的,可以执行。

(3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3

上面代码对数组进行对象解构。数组arr的0键对应的值是1,[arr.length - 1]就是2键,对应的值是3。方括号这种写法,属于“属性名表达式”。

常用扩展

1、对象扩展

ES6中对于Object的拓展主要是静态方法的拓展。

  1. Object.is()
    该方法用来判断两个值是否“完全相等”,或者说是否为同一个值。
    格式:Object.is(value1,value2);
    结果:返回一个Bolean类型表示两个参数是否为同一个值。为true则相同,为false表示不同

该方法和"=="有区别:
"==“在判断相等前对两边的变量(如果不是同一类型)进行强制转换,而Object.is()方法不会这么做
该方法和”==="也有区别:
“===“先比较类型,类型不相同则结果一定不等,如果类型相同,则继续比较值,值相等,则结果相等。并且”===” 将数字 -0 和 +0 视为相等,而将Number.NaN 与NaN视为不相等,而Object.is()方法将这两个均视为不等。

Object.is('foo', 'foo');  // true
Object.is(window, window);  // true
Object.is('foo', 'bar');   // false,这是两个对象,存放的地址位置不同
Object.is([], []);  // false,这是两个对象,存放的地址位置不同

let foo = { a: 1 };
let bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false,这是两个对象,存放的地址位置不同

Object.is(null, null); // true
console.log(1 === 1);//true
console.log(Object.is(1, 1));//true
console.log(Object.is(1, 2)); //false

console.log(+0 === -0);  //true
console.log(Object.is(+0, -0));  //false

console.log(0 === -0);  //true
console.log(Object.is(0, -0));  //false

console.log(NaN === NaN); //false
console.log(Object.is(NaN, NaN));  //true

console.log(isNaN(NaN)); //true

console.log(NaN === 0/0); //false

console.log(Object.is(NaN, 0/0));  //true

简单理解就是Object.is()方法比较值其实就是看两个值的存储位置是不是一样,一样则相等。

  1. Object.assign()
    该方法用于将所有可枚举类型的值从一个或多个源对象分配到目标对象。返回目标对象。简而言之就是合并对象。
    语法:object.assign(target,...sources);target是目标对象,sources源对象,而可以为一个或多个。

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性,此外需要注意Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。看如下例子

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// Object { a: 1, b: 4, c: 5 }

补充:该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。
如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty()。
Object.assign()拷贝的是(可枚举)属性值。假如源值是一个对象的引用,它仅仅会复制其引用值。

  1. Object.getPrototypeOf()
    该方法返回指定对象的原型。
    语法:Object.getPrototypeOf(object);object是要返回其原型的对象
    返回的是给定对象的原型,如果没有继承属性则返回null
let obj = {};
// 获取obj的原型对象
console.log(Object.getPrototypeOf(obj));
// 打印出:obj的原型对象
console.log(Object.getPrototypeOf(obj)===Object.prototype);
//打印出:true
console.log(Object.getPrototypeOf(obj)===obj.__proto__);
//打印出:true
  1. Object.setPrototypeOf()
    该方法设置一个指定的对象的原型到另一个对象或 null。
    语法:Object.setPrototypeOf(obj,prototype);obj是要设置其原型的对象,protoType是该对象obj的新原型
let dict = Object.setPrototypeOf({}, null);

由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.proto = … 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果关心性能,应该避免设置一个对象的 [[Prototype]]。相反,应该使用 Object.create()来创建带有想要的[[Prototype]]的新对象。

  1. Object.keys()
    该方法用于获取所有可枚举属性名,并且返回一个由给定对象自身可枚举属性组成的数组,数组中属性名的排序和正常循环遍历该对象时返回的顺序一致。
    语法:object.keys(obj); obj是要返回其枚举自身属性的对象。
//例如一个简单的数组
let arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); 
// 打印出: ['0', '1', '2']

// 例如一个对象
let obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // ['0', '1', '2']
//遍历
Object.keys(obj).forEach((item) => {
  console.log(item, obj[item]);
})
// 0 a
// 1 b
// 2 c

//一个带有随机排序key的对象
let anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj));  // ['2', '7', '100']

// getFoo is a property which isn't enumerable
let myObj = Object.create({}, {
	getFoo: {
		value: function () { return this.foo; }
	}
});
myObj.foo = 1;
console.log(Object.keys(myObj)); 
// 打印出: ['foo']

当然,如果想获取一个对象的所有属性,甚至包括不可枚举的,请使用Object.getOwnPropertyNames()方法。

  1. Object.values()
    该方法可以获取所有可枚举属性的属性值,并返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for…in循环的顺序相同(区别在于for-in循环枚举原型链中的属性)。
    语法:Object.values(obj); obj表示可以枚举属性值的对象。
let obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]

let obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj));  // ['a', 'b', 'c']

// array like object with random key ordering
// when we use numeric keys, the value returned in a numerical order according to the keys
let an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(an_obj));  // ['b', 'c', 'a']

// getFoo is property which isn't enumerable
let my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = 'bar';
console.log(Object.values(my_obj)); 
// 打印出: ['bar']

// non-object argument will be coerced to an object
console.log(Object.values('foo')); 
// 打印出: ['f', 'o', 'o']
  1. Object.entries
    该方法获取所有的可枚举属性名和属性值键值对返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
    语法:Object.entries(obj);obj 可以返回其可枚举属性的键值对的对象。
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]

// array like object
const obj2 = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); 
// 打印出: [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); 
// 打印出: [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]

// getFoo is property which isn't enumerable
const myObj = Object.create({}, { getFoo: { value() { return this.foo; } } });
myObj.foo = 'bar';
console.log(Object.entries(myObj)); 
// 打印出: [ ['foo', 'bar'] ]

// non-object argument will be coerced to an object
console.log(Object.entries('foo')); 
// 打印出: [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]

// iterate through key-value gracefully
const obj3 = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
	console.log(`${key} ${value}`); 
	// 打印出: "a 5", "b 7", "c 9"
}

// Or, using array extras
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`); 
// 打印出: "a 5", "b 7", "c 9"
});
  1. Object.fromEntries()
    传入二维数组或者Map集合,返回一个对象
// 二维数组
const result1 = Object.fromEntries([
	['name','jack'],
	['course','English'],
]);
console.log(result1); // { name: 'jack', course: 'English' }
// Map
const m = new Map();
m.set('name','jack');
const result2 = Object.fromEntries(m);
console.log(result2); // { name: 'jack' }

2、函数扩展

函数参数

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。通常情况下,定义了默认值的参数,应该是函数的尾参数,并且注意:函数的length属性,将返回没有指定默认值的参数个数

  • 设置参数默认值
function log(x, y = 'World') { 
	console.log(x, y);
	// 打印出:1,'World'
}
log(1);
  • 参数结构
    参数默认值可以与解构赋值的默认值,结合起来使用。
function foo({x, y = 5}) { 
	console.log(x, y); 
	// 打印出:1,5
}
foo({x:1});

此外,函数参数对象解构、数据结构等。

function test({ name, age = 1, ...obj }) {
  console.log(name, age, obj);
}
test({ name: 'zhangsan', age: 12, gender: 1,weight:40 });
//zhangsan 12 { gender: 1, weight: 40 }

rest参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,得到的是一个数组

function add(a,b,...values) {
	console.log(a);
	console.log(b);
	console.log(values);
}
add(1,2,3,4,5,6,7);
结果为:
1
2
[3,4,5,6]

rest参数必须要放到参数最后

箭头函数

JavaScript中,经常使用回调函数,箭头函数的出现大大简化了回调函数的写法,当然,除了作为函数参数,箭头函数也可以出现在其他地方。
语法:(0个或1个或多个参数)=>{代码块部分}

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号括参数部分如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。其实箭头函数还可以继续省略,当形参只有一个参数的时候,可以省略圆括号;当代码块只有一条语句的时候,可以省略花括号。

let f = v => v;
// 等价于
let f = function(v) { 
	return v; 
};

主要特性:
1、箭头函数里面没有自己的this,而是引用外层作用域中的this,且不可以改变this指向,因此箭头函数不适合与this有关的回调,例如事件回调,对象的方法回调
2、箭头函数里面不能使用arguments、super变量
3、不能使用new关键字创建实例化对象
4、没有原型prototype
5、不支持重复的命名参数。

例如:箭头函数里面没有自己的this,而是引用外层作用域中的this,且不可以改变this指向

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>箭头函数</title>
</head>

<body>

    <script>
        function getName1() {
            console.log(this.name);
        }

        let getName2 = () => {
            console.log(this.name);
        }

        // 设置window对象的name属性
        window.name = "rose";

        // 创建另一个对象obj
        const obj = {
            name: "jack"
        }

        // 直接调用时
        getName1(); //rose
        getName2(); //rose

        //使用call()方法调用函数时(此时会修改this指向的对象)
        getName1.call(obj); //jack
        //普通方式定义的函数this指向改变。
        getName2.call(obj); //rose 
        //箭头函数的this指向的依然是外层的且为原来的那个对象--这里是window对象(即不会改变原来this指向)
    </script>
</body>
</html>

例如:箭头函数中不能使用new关键字创建实例化对象

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>箭头函数</title>
</head>

<body>

    <script>
        let Person = (name, age) => {
            this.name = name;
            this.age = age;
        }
        let me = new Person("jack",20);
        console.log(me); //报错:Uncaught TypeError: Person is not a constructor
    </script>
</body>
</html>

如果将普通函数和箭头函数分别定义在setTimeout(function(),时间)延时方法中。那么区别在哪里?如下:

var obj = {
		 x: 100,
		show() {
		setTimeout(
			function () {
				console.log(this.x); // undefined
				console.log(this); // window对象
			}, 1000);
		}
}
	obj.show();

普通函数中的this总是指向它的直接调用者,而匿名函数function()并没有被直接调用,所以这里this应该是指向window对象,而全局作用域没有定义x变量,所以this.x结果为undefined。

如果想要this指向obj,则需要在setTimeout()方法和show()方法之间定义一个引用:let _this = this;,接收全局的的this。

       var obj = {
           x:100,
          show(){
               setTimeout(() => {
                   console.log(this.x); //100
                   console.log(this); //obj对象
               }, 1000);
           }
       }
       obj.show();

使用箭头函数简写时,this指向的对象是作用域链上的对象,此时的this会沿着作用域链一层一层往上找,直到找到含有x的对象,然后进行调用。可以再obj对象中添加一个变量来判断为什么延时函数中的this代表了obj对象,如下:

var obj = {
            x: 100,
            y:this,
            show() {
                setTimeout(() => {
                    console.log(this.x); //100
                    console.log(this); //obj对象
             	}, 1000);
          	}
     	 }
 obj.show();
 console.log(obj.y); //obj对象

可以看到其实obj中的this指向的也是obj对象,而this沿着作用域链不断向上找,找到x=100;

关于普通函数和箭头函数中的this指向问题

3、数组扩展

数组在静态方法与实例方法中都有所拓展。

  • Array.from()
    该方法将类似数组或可迭代对象转为数组,从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
    语法:Array.from(arrayLike[, mapFn[, thisArg]])
    参数:
    • arrayLike 想要转换成数组的伪数组对象或可迭代对象。
    • mapFn 可选 如果指定了该参数,新数组中的每个元素会执行该回调函数。
    • thisArg 可选 执行回调函数 mapFn 时 this 对象。

Array.from() 可以通过以下方式来创建数组对象:
伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

Array.from('foo');
// [ "f", "o", "o" ]

function f() {
	return Array.from(arguments);
}
f(1, 2, 3);
// [ 1, 2, 3 ]
  • Array.of()
    该方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
    语法:Array.of(element0[, element1[, ...[, elementN]]])
    参数:
    elementN 任意个参数,将按顺序成为返回数组中的元素。
Array.of(7);       // [7]
Array.of(1, 2, 3); // [1, 2, 3]

Array(7);          // [ , , , , , , ]
Array(1, 2, 3);    // [1, 2, 3]

Array.of(1);         // [1]
Array.of(1, 2, 3);   // [1, 2, 3]
Array.of(undefined); // [undefined]

该方法和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 表示创建一个具有单个元素 7 的数组,而Array(7)
表示创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。

  • Array.prototype.find()
    该方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
    语法:arr.find(callback,[thisArg])
    参数:
    callback 在数组每一项上执行的函数,接收3个参数:

    • tem 当前遍历到的元素。
    • index 可选 当前遍历到的索引。
    • array 可选 数组本身。
      thisArg 可选 执行回调时用作this 的对象。
  • Array.prototype.findIndex()
    该方法找到一个元素在数组中的位置,返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
    语法:arr.findIndex(callback[, thisArg])
    参数:
    callback 在数组每一项上执行的函数,接收3个参数:

    • tem 当前遍历到的元素。
    • index 可选 当前遍历到的索引。
    • array 可选 数组本身。
      thisArg 可选 执行回调时用作this 的对象。
//查找等于2的元素
let arr = [10,8,3,2,4,2,5];
//find方法返回第一个满足条件的元素或者undefined
let resultNum = arr.find((item, index) => {
  return item === 2;
});
console.log(resultNum);//2
// findIndex返回第一个满足条件的元素的索引或者-1
let resultIdx = arr.findIndex((item, index) => {
  return item === 2;
});
console.log(resultIdx);//3
function isPrime(element, index, array) {
	let start = 2;
	while (start <= Math.sqrt(element)) {
		if (element % start++ < 1) {
			return false;
		}
	}
	return element > 1;
}

console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2
  • Array.prototype.includes()
    该方法找到一个元素是否存在于数组中,用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。使用 includes()比较字符串和字符时是区分大小写。
    语法:arr.includes(valueToFind,[ fromIndex])
    参数:
    • valueToFind 需要查找的元素值。
    • fromIndex 可选 从fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜 (即使从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜寻)。默认为 0。如果 fromIndex 大于等于数组的长度,则会返回 false,且该数组不会被搜索。
      返回值:
      返回一个布尔值 Boolean ,如果在数组中找到了(如果传入了 fromIndex ,表示在 fromIndex 指定的索引范围中找到了)则返回 true 。
[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
  • Array.prototype.fill()
    该方法用来填充数组,用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
    语法:
    arr.fill(value[, start[, end]])
    参数:
    • value 用来填充数组元素的值。
    • start 可选 起始索引,默认值为0。
    • end 可选 终止索引,默认值为 this.length。
      如果 start和end 是个负数, 则开始索引会被自动计算成为 length+start
[1, 2, 3].fill(4);  // [4, 4, 4]
[1, 2, 3].fill(4, 1);  // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);  // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);  // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3);  // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);  // [4, 2, 3]
  • Array.prototype.keys()
    该方法获取数组key,返回一个包含数组中每个索引键的Array Iterator对象。
    语法:arr.keys()
let arr = ["a", , "c"];
let sparseKeys = Object.keys(arr);
let denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys);  // [0, 1, 2]
let arr = [2, 3, 4, 5, 6, 2];
// 遍历
let keys = arr.keys();
console.log(keys);
//keys变量当前是迭代器对象Object [Array Iterator] {}

// 遍历迭代器对象
let result;
while (!(result = keys.next()).done) {
  console.log(result);
}

/* 
console.log(keys.next());// { value: 0, done: false }
console.log(keys.next());// { value: 0, done: false }
console.log(keys.next());
console.log(keys.next());
console.log(keys.next());
console.log(keys.next());
console.log(keys.next());//{ value: undefined, done: true }
console.log(keys.next());//{ value: undefined, done: true }
*/

// 迭代器实现了Iterator接口,只要有实现了Iterator接口就可以for-of遍历
for (let key of keys) {
  console.log(key);
}
  • Array.prototype.values()
    Array.prototype.values()方法获取数组元素,返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值。
    语法:arr.values()
let arr = ['w', 'y', 'k', 'o', 'p'];
let eArr = arr.values();

for (let letter of eArr) {
	console.log(letter);
} 
//"w" "y "k" "o" "p"
  • Array.prototype.entries()
    该方法获取数组中的key、value键值对,返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
    语法:arr.entries()
    一个新的 Array 迭代器对象。Array Iterator是对象,它的原型(proto:Array Iterator)上有一个next方法,可用用于遍历迭代器取得原数组的[key,value]。
let arr = ["a", "b", "c"];
let iterator = arr.entries();
console.log(iterator);
// 打印出:Array Iterator {  }
for (let letter of iterator) {
	console.log(letter);
} 
// 打印出:
// Array [ 0, "a" ]
// Array [ 1, "b" ]
// Array [ 2, "c" ]
  • flat()
    将多维数组转为低维数组
// 二维转一维
const arr1 = [1,2,3,4,[5,6]]; // 二维数组
console.log(arr.flat()); // [1,2,3,4,5,6]; 

// 三维转二维
const arr2 = [1,2,3,[4,5,[6,7]]]; // 三维数组
console.log(arr.flat()); // [1,2,3,4,5,[6,7]]; 

// 三维转一维
const arr3 = [1,2,3,[4,5,[6,7]]];
console.log(arr.flat(2)); // 参数2表示深度
// [1,2,3,4,5,6,7]

4、数值扩展

  • Number.EPSILON
    该方法表示JavaScript中数值的最小精度,EPSILON无限接近于2.2204460492503130808472633361816E-16。当两个数进行大小比较时,如果差值小于这个EPSILON,那么就将这两个数看做相等。

有如下代码:

console.log(0.1+0.2);

其结果并不是我们想象中的0.3,而是如下结果:
在这里插入图片描述

function equal(a, b){
    if(Math.abs(a-b) < Number.EPSILON){
        return true;
    }else{
        return false;
    }
}
console.log(0.1+0.2); //0.30000000000000004
console.log(0.1 + 0.3); // 0.4
console.log(0.1 + 0.3 === 0.4); // true
console.log(equal(0.1 + 0.3,0.4)); // true
console.log(0.1 + 0.2 === 0.3); // false
console.log(equal(0.1 + 0.2,0.3)); // true
  • 二进制、八进制
let b = 0b1010; //二进制
console.log(b); // 10
let o = 0o777;  // 八进制
console.log(o); // 511
let d = 100;    // 十进制
console.log(d); // 100
let x = 0xff;   // 十六进制
console.log(x); // 255
  • Number.isFinite
    检测一个数值是否为有限数
console.log(Number.isFinite(100)); // true
console.log(Number.isFinite(100/0)); // false
console.log(Number.isFinite(Infinity)); // false
  • Nuber.isNaN
    检测一个值是否为NaN
console.log(Number.isNaN(123)); // false
  • Nuber.parseInt和Number.parseFloat
    字符串转整数(从左往右,在碰到字母后,后面的内容全部神略)
console.log(Number.parseInt('432423love')); // 432423
console.log(Number.parseFloat('4.32423love')); // 4.32423
console.log(Number.parseInt('432423love3434')); // 432423
console.log(Number.parseFloat('4.32423love342')); // 4.32423
  • Nubmer.isInteger
    判断一个数是否为整数
console.log(Number.isInteger(5));
console.log(Number.isInteger(2.5));
  • Math.trunc
    直接将数字的小数部分省略
console.log(Math.trunc(2.4)); // 2
  • **
    求幂
console.log(Math.pow(2,10)); // 1024
console.log(2 ** 10); // 1024
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值