第十三节:ES6之模板字符串、Function、展开运算符和剩余参数、Number详解
一. 模板字符串
1. 模板字符串
我们会使用 `` 符号来编写字符串,称之为模板字符串; 其次,在模板字符串中,我们可以通过 ${expression} 来嵌入动态的内容;
{ const name = "ypf"; const age = 1.82; function getMsg() { return "你好,ypf"; } console.log(`name:${name},age:${age},msg:${getMsg()}`); }
2. 标签字符串
(1). 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中
(2). 第二个参数是模块字符串中, 第一个 ${}
(3). 第三个参数是模块字符串中, 第二个 ${}
{ function foo(m, n, x) { console.log("---------", m, n, x); } const name = "ypf"; const age = 1.82; foo`hi${name}hello${age}`; //--------- [ 'hi', 'hello', '' ] ypf 1.82 }
二. Function详解
1. 默认参数
(1). ES5时期,对参数进行判断,如果没有值,则赋一个默认值,通过 || 符号来实现,但这种模式有个bug, 它认为:0和空字符串"",都是false
(2). ES6中引入默认参数解决上述痛点问题,通过 = 符号直接参数赋值
(3). 默认值的参数尽量往后放,这样当用默认值的时候,后续的参数可以省略不用输入
注:默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了!
// 1. ES5时候默认参数的判断 { function foo(name, age) { name = name || "ypf"; age = age || 1.82; console.log(name, age); } foo("", 0); //ypf 1.82 , 实际上我们想输出 “” 0,这就是bug所在 foo(undefined, undefined); //ypf 1.82 } // 2. 默认参数 { function foo(name = "ypf", age = 1.82) { console.log(name, age); } foo("", 0); //"" 0 foo(undefined, undefined); //ypf 1.82 foo("lmr", 1.99); //lmr 1.99 function foo2(name, age, msg) { console.log(name, age, msg); } function foo3(name, age = 1.82, msg) { console.log(name, age, msg); } console.log(foo2.length); //3 console.log(foo3.length); //1 }
2. 剩余参数
(1). 用途:在写函数的时候,部分情况我们不是很确定参数有多少个,可以使用剩余参数, 形式为 ...变量名
(2). 剩余参数的中数据存放在一个数组里
(3). 剩余参数必须放在最后的位置
PS:与arguments的区别:剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参;arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供并且希望以此来替代arguments的。
{ function sum(m, ...nums) { let total = m; nums.forEach(item => (total = total + item)); return total; } console.log(sum(10, 1, 2, 3, 4, 5)); //25 }
3. length属性
返回函数参数的个数
注:默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了!
function foo2(name, age, msg) { console.log(name, age, msg); } function foo3(name, age = 1.82, msg) { console.log(name, age, msg); } console.log(foo2.length); //3 console.log(foo3.length); //1
4. name属性
返回函数的名称
{ function foo() {} console.log(foo.name); //foo }
5. 箭头函数
(1). 普通写法, 如下案例
(2). 特殊写法
A. 如果参数只有一个,可以省略小括号()
A. 返回值是表达式,可以省略 return 和 {}
B. 返回值是字面量, 需要加小括号()
(3).特殊点
A. 箭头函数中没有this,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的
B. 不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误。
C. 箭头函数不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
{ //普通函数两种写法 function sum1(m1, m2) { return m1 + m2; } let sum2 = function (m1, m2) { return m1 + m2; }; // 箭头函数写法 let sum3 = (m1, m2) => { return m1 + m2; }; // 特殊写法 let GetMsg = msg => { console.log(msg); }; let pow = x => x * x; let GetUserInfo = name => ({ myName: name, age: 20, addr: "Beijing City", }); console.log(GetUserInfo()); // 箭头函数this指向 { var obj = { data: [], getData: function () { // 发送网络请求, 将结果放到上面data属性中 // 在箭头函数之前的解决方案 // var _this = this // setTimeout(function() { // var result = ["abc", "cba", "nba"] // _this.data = result // }, 2000); // 箭头函数之后(不绑定this,就去外层作用域(也就是getData中的this),也就是obj) setTimeout(() => { var result = ["abc", "cba", "nba"]; this.data = result; }, 2000); }, }; obj.getData(); } }
三. 展开运算符
1. 含义
把固定的数组内容“打散”到对应的参数中
可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开
2. 用法
A. 函数调用的时候,将数组或者字符串展开到参数中,如:foo(...names);
B. 构造数组时,将数组或者字符串展开到参数中,如:[...names, ...name];
C. 构建对象字面量时, 将对象或者字符串展开到参数中,后面的属性会覆盖前面的, 如:{ ...myInfo, age, height: 1.82 };
{ const names = ["ypf1", "ypf2", "ypf3"]; const name = "ypf"; const myInfo = { name: "ypf", age: 30 }; // 1.1 函数调用 function foo(x, y, z) { console.log(x, y, z); } foo(...names); //ypf1 ypf2 ypf3 foo(...name); //y p f foo.apply(null, names); //ypf1 ypf2 ypf3 // 1.2 构造数组时 const myNames = [...names, ...name]; console.log(myNames); //[ 'ypf1', 'ypf2', 'ypf3', 'y', 'p', 'f' ] // 1.3 构建对象字面量时(ES9-ES2018) let age = 40; const myObj = { ...myInfo, age, height: 1.82 }; console.log(myObj); //{ name: 'ypf', age: 40, height: 1.82 } //1.4 对象+数组 { // filterRouteArray是一个数组,数组中的每个值都是一个{}对象 // pathMatch是一个对象 filterRouteEnd[0].children = [...filterRouteArray, { ...pathMatch }]; } }
3. 复制数组、对象(浅拷贝)
A. 对于数组:数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。
使用展开运算符,相当于获得一份新的数据空间,新的引用地址,指向新的栈空间
B. 对于对象:展开运算符是浅拷贝,只能将对象中的一级内容直接copy,对于对象中的对象,copy的仍然是引用地址!!
//数组的复制-浅拷贝 { //直接把array1赋值给array2,相当于把引用地址赋值给了array2, 这个时候array1和array2都指向堆内存的同一个空间 const array1 = [1, 2, 3]; const array2 = array1; array2[0] = 111; console.log(array1[0]); //111 } { // 使用展开运算符,相当于array2获得一份新的数据空间,新的引用地址,指向新的栈空间 const array1 = [1, 2, 3]; const array2 = [...array1]; array2[0] = 111; console.log(array1[0]); //1 } // 对象的赋值--浅拷贝 { let obj1 = { name: "ypf", age: 18, myChild: { cName: "ypf1", cAge: 20, }, }; let obj2 = { ...obj1 }; obj2.name = "lmr"; obj2.myChild.cName = "lmr1"; console.log(obj1.name, obj1.myChild.cName); //ypf lmr1 }
4. 数组合并
使用展开运算符,可以实现数组的合并,但是不能去重,如果想去重,需要借助Set数据结构来实现。
{ let array1 = [1, 3, 4]; let array2 = [2, 3, 5]; // 展开运算符合并数组(注:不去充) console.log([...array1, ...array2]); //[ 1, 3, 4, 2, 3, 5 ] 不去重!!! // 配合Set数据类型进行去重 let s = new Set([...array1, ...array2]); console.log([...s]); //[ 1, 3, 4, 2, 5 ] //或者利用Array.from转成数组 console.log(Array.from(s)); //[ 1, 3, 4, 2, 5 ] }
四. 剩余参数
1. 含义
把固定的数组内容“打散”到对应的参数 【同Function章节介绍的一样】
2. 用途
在写函数的时候,部分情况我们不是很确定参数有多少个,可以使用剩余参数, 形式为 ...变量名
3. 剩余参数的中数据存放在一个数组里
4. 剩余参数必须放在最后的位置
PS:与arguments的区别:剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参;arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;
arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供并且希望以此来替代arguments的。
{ function sum(m, ...nums) { let total = m; nums.forEach(item => (total = total + item)); return total; } console.log(sum(10, 1, 2, 3, 4, 5)); //25 } { console.log("-----------------1. 剩余参数---------------------"); function sum1(...nums) { console.log(nums); console.log( nums.reduce((preValue, currentValue) => preValue + currentValue, 0) ); //求和 } //调用 sum1(1, 2); //[1,2] sum1(1, 2, 3); //[1,2,3] sum1(1, 2, 3, 4); //[1,2,3,4] function sum2(num1, num2, ...nums) { console.log(nums); console.log( nums.reduce( (preValue, currentValue) => preValue + currentValue, num1 + num2 ) ); //求和 } //调用 sum2(1, 2); //[] sum2(1, 2, 3); //[3] sum2(1, 2, 3, 4); //[3,4] }
五. Number详解
1. 进制的新写法
二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示
{ // b -> binary const num2 = 0b100; // 二进制 // o -> octonary const num3 = 0o100; // 八进制 // x -> hexadecimal const num4 = 0x100; // 十六进制 }
2. 新增方法
(详见:http://es.xiecheng.live/es6/number.html#新增方法)
(1). Number.parseInt(): ES6 将全局方法parseInt()移植到Number对象上面,行为完全保持不变。
(2). Number.parseFloat(): ES6 将全局方法parseFloat()移植到Number对象上面,行为完全保持不变。
(3). Number.isInteger(): 用来判断一个数值是否为整数。
(4). Number.isFinite()
(5). Number.isNaN()
(6). Number.MAX_SAFE_INTEGER
(7). Number.MIN_SAFE_INTEGER
(8). Number.isSafeInteger()
{ // ES5的写法 console.log(parseInt("12.34")); // 12 // ES6的写法 console.log(Number.parseInt("12.34")); // 12 } { // ES5的写法 console.log(parseFloat("123.45#")); // 123.45 // ES6的写法 console.log(Number.parseFloat("123.45#")); // 123.45 } { Number.isInteger(25); // true Number.isInteger(25.1); // false Number.isInteger(); // false Number.isInteger(null); // false Number.isInteger("15"); // false Number.isInteger(true); // false }
3. Math扩展
(1). Math.trunc():方法用于去除一个数的小数部分,返回整数部分。
(2). Math.sign(): 方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
(3). Math.cbrt():方法用于计算一个数的立方根。
4. ES2021新增特性
数字过长时,可以使用_作为连接符
{ // 大的数值的连接符(ES2021 ES12) const num = 10_000_000_000_000_000; console.log(num); }
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。