本篇文章我们续接ES6学习(8)-- 各类数据类型扩展的汇总(1)学习剩下的部分:函数的扩展,数组扩展,对象的扩展,运算符的扩展;同样的,在这里我们还是摘取出来大家常见,常用,或者有机会用到的知识点。
4,函数的扩展
函数参数的默认值
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
注意:
参数变量是默认声明的,所以不能用let
或const
再次声明。
使用参数默认值时,函数不能有同名参数。
参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
// 例1
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
//例2
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
//例3
// 不报错
function foo(x, x, y) {
// ...
}
// 报错
function foo(x, x, y = 1) {
// ...
}
// SyntaxError: Duplicate parameter name not allowed in this context
与解构赋值默认值结合使用
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
rest参数
定义:ES6 引入 rest 参数,用于获取函数的多余参数,这样就不需要使用arguments
对象了。
形式:...变量名,
变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
// 注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
// 报错
function f(a, ...b, c) {
// ...
}
rest参数与arguments对象相比差异:
rest参数时数组,可以直接使用所有的数组方法。arguments对象是‘类数组’,本质上是对象。想要使用数组的方法需要Array.from()进行转换。
name属性
函数的name
属性,返回该函数的函数名。
// 一般函数
function baz(){
...
}
baz.name // baz
// 匿名函数
var baz = function(){
...
}
baz.name // baz
// 表达式函数
var baz = function foo(){
...
}
baz.name // foo
// 构造函数
(new Function).name //anonymous
箭头函数
具体请转至 ES6学习(6)-- 箭头函数 。
5,数组的扩展
扩展运算符
扩展运算符(spread)是三个点(...
)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
特点:
1,扩展运算符主要与函数一起使用
2,扩展运算符后可以放置表达式
3,只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错。
4,扩展运算符后面是一个空数组,则不产生任何效果。
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
// 函数调用
function push(array, ...items) {
array.push(...items);
}
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
// 表达式
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
// 空数组
[...[], 1]
// [1]
Array.from()
Array.from
方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
Array.from()方法可以有两个参数,第一个参数是需转换的类数组,第二个参数是用来对每个元素进行处理,将处理后的值放入返回的数组。
// 一般用法,一个参数
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
// 两个参数
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
Array.of()
Array.of()
基本上可以用来替代Array()
或new Array()
,并且不存在由于参数不同而导致的重载。它的行为非常统一:总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
find() 和 findIndex()
find() : 用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true
的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
。第二个参数用来绑定回调函数的this
对象。
findIndex() :用法与find
方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
。
// find()
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
// findIndex()
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
fill()
fill
方法使用给定值,填充一个数组。它可以接受三个参数:第一个参数,指定填充数组的值或内容。(可以为空);第二个参数:填充的起始位置;第三个参数:填充的结束位置;(不包含结束参数本身);
//情况一:三个参数
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
// 情况二,一个参数
['a', 'b', 'c'].fill(7) // [7, 7, 7]
new Array(3).fill(7) // [7, 7, 7]
// 注意,如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。
let arr = new Array(3).fill({name: "Mike"});
arr[0].name = "Ben";
arr // [{name: "Ben"}, {name: "Ben"}, {name: "Ben"}]
let arr = new Array(3).fill([]);
arr[0].push(5);
arr // [[5], [5], [5]]
entires()、keys()、values()
entries()
,keys()
和values()
——用于遍历数组。它们都返回一个遍历器对象,可以用for...of
循环进行遍历,唯一的区别是keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历。使用方法可以参考:ES6学习(7)-- Set和Map数据结构 。
includes()
Array.prototype.includes
方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes
方法类似。该方法可以接受两个参数:第一个参数是判定值;第二个参数是表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4
,但数组长度为3
),则会重置为从0
开始。
相比于原来的数组方法indexOf()的方法,includes()方法有两大优点:
语义化更好,返回结果就是true和false,不用去比较indexOf的返回值是不是-1;
与indexOf相比,它是有这新的判定算法,改掉了indexOf的(===)算法,可以判定NaN。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
6,对象的扩展
属性的遍历
ES6 一共有 5 种方法可以遍历对象的属性:
1,for...in:循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
2,Object.keys(obj):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
3,Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
4,Object.getOwnPropertySymbols(obj):返回一个数组,包含对象自身的所有 Symbol 属性的键名。
5,Reflect.ownKeys(obj):返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
super关键字
详见我的其他文章:ES6学习(2)--class的基本语法和继承
扩展运算符
上边的数组的扩展中我们已经认识了扩展运算符了。同样的,对象中也有扩展运算符,让我们汇总一下对象的扩展运算符的相关特性:
定义:对象的扩展运算符(...
)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。(这里拷贝是深拷贝)在我其他的文章里也提到了此方法实现深拷贝的使用方法,有兴趣的伙伴可以去瞅瞅:JavaScript 引用数据类型的浅拷贝和深拷贝
7,运算符的扩展
指数运算符( ** )
特点:
1,运算符的一个特点是右结合,而不是常见的左结合。多个指数运算符连用时,是从最右边开始计算的。
2,指数运算符可以与等号结合,形成一个新的赋值运算符(**=
)。
2 ** 3 // 8
2 ** 3 ** 2 // 512 (相当于 2 ** (3 ** 2))
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
链判断运算符( ?. )
我们经常会遇到对象含有多层结构的现象,当我们需要判断内层的某个数据时,需要层层的判断,这非常的麻烦。因此 ES2020 引入了“链判断运算符”(optional chaining operator)?.
,简化多层判断多次的写法。
// 错误的写法
const firstName = message.body.user.firstName || 'default';
// 正确的写法
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
// 链判断运算符的写法
const firstName = message?.body?.user?.firstName || 'default';
注意点:
1,短路机制:本质上,?.
运算符相当于一种短路机制,只要不满足条件,就不再往下执行。
2,括号的影响:如果属性链有圆括号,链判断运算符对圆括号外部没有影响,只对圆括号内部有影响。一般来说,使用?.
运算符的场合,不应该使用圆括号。
3,报错场合:以下写法是禁止的,会报错。
// 构造函数
new a?.()
new a?.b()
// 链判断运算符的右侧有模板字符串
a?.`{b}`
a?.b`{c}`
// 链判断运算符的左侧是 super
super?.()
super?.foo
// 链运算符用于赋值运算符左侧
a?.b = c
4,右侧不得为十进制数值:为了保证兼容以前的代码,允许foo?.3:0
被解析成foo ? .3 : 0
,因此规定如果?.
后面紧跟一个十进制数字,那么?.
不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。
Null判断运算符( ?? )
Null 判断运算符??
。它的行为类似||
,但是只有运算符左侧的值为null
或undefined
时,才会返回右侧的值。
const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;
逻辑赋值运算符( ||=
、&&=
、??=
)
// 或赋值运算符
x ||= y
// 等同于
x || (x = y)
// 与赋值运算符
x &&= y
// 等同于
x && (x = y)
// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)
到此结束!
以上就是函数,数组,对象,运算符的扩展内容(不是全部!!!不是全部!!!),这里只是摘取了一部分,它们在我们实际的工作中是比较常用的,希望对大家有帮助,有需要的伙伴可以在这里极快的筛选查找一下,应该可以提高一点效率。
拜了个拜!迪迦。。。