一、字符串的扩展
1. includes()、startWith()、endWith()方法
let str = 'Hello World';
console.log(str.includes('llo')); //true
console.log(str.startWith('He')); //true
console.log(str.endWith('ld')); //true
2.repeat()方法
let str = 'abc';
console.log(str.repeat(3)); //abcabcabc
参数记得传整数,传小数会取整,数组对象什么的就别传了,别为难人家库函数了。
3.padStart()、padEnd()方法
padStart(n, str)/padEnd(n, str),在前面或者后面补字符串,直到整个字符串的长度 == n :
let str = 'x';
console.log(str.padStart(4, 'ab')); //abax
console.log(str.padEnd(4, 'ab')); //xaba
但是只有当原字符串的长度小于n时才会补,如果大于则不做操作:
let str = 'xxxxx';
console.log(str.padStart(4, 'ab')); //xxxxx
应用情况:月份和日期补零:
let year = '2020';
let month = '9';
let day = '9';
console.log(year + month.padStart(2,'0') + day.padStart(2, '0')); //20200909
4.字符串模板
{ }里可以是变量,也可以是表达式,也可以是函数调用
let [a, b, c] = [1, 2, 3];
let s = `<ul>
<li>${a}</li>
<li>${b}</li>
<li>${c + b}</li>
</ul>`;
console.log(s);
输出:
二、数值的扩展
1.二进制和八进制的表示方法
0b开头代表二进制
let a1 = 0b0101;
console.log(a1); //5
0o开头代表八进制
let b1 = 0o77;
console.log(b1); //63
2.parseInt() 和 parseFloat()
和Number.parseInt()的效果一样
console.log(Number.parseInt === parseInt); //true
3.Number.isInteger()
JS的基本类型里整形和浮点型统一用Number表示,我们可以进一步用Number.isInterger()判断这个数是否是整数。
let a = 1;
let b = 1.5;
console.log(Number.isInteger(a), Number.isInteger(b)); //true false
实现原理,用向下取整进行判断
function myIsInteger(a){
return Math.floor(a) === a;
}
console.log(myIsInteger(1.5)); //false
4.Number.EPSILON
表示极小的常量
console.log(Number.EPSILON); //2.220446049250313e-16
常用来做误差检查
function withErrorMargin(left, right){
return Math.abs(left - right) < Number.EPSILON;
}
withErrorMargin(0.1 + 0.2, 0.3); //true
5. 安全整数Number.isSafeInteger()、Number.MAX_SAFE_INTEGER()
console.log(Number.isSafeInteger(5)); //true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); //false
console.log(Number.MAX_SAFE_INTEGER); //9007199254740991
6. Math扩展出来的API
6.1 trunc()方法 去掉小数部分
ES5里的Math.floor()也可以取整,但是是向下取整,如果要操作的对象是负数的时候,和我们想要达到的效果不一样,所以有了更方便的方法trunc:
let a = 1.5;
let b = -1.5;
console.log(Math.floor(a), Math.floor(b)); //1 -2
console.log(Math.trunc(a), Math.trunc(b)); //1 -1
6.2 Math.cbrt()方法 立方根
console.log(Math.cbrt(27)); //3
ES5里求立方根的方法
console.log(Math.pow(27, 1/3)) //以27为底的1/3次方
6.3 Math.hypot() 对所有的数据求平方和,然后开方
2个参数时,相当于求直角三角形的斜边
console.log(Math.hypot(3, 4)); //5
还有一些对数,正弦、余弦函数的方法,用到再查了。
三、函数的扩展
1.箭头函数
情况1:只有一个参数,一个返回
// ES5的写法
var f = function(a){
return a + 1;
}
// ES6的写法
let f = a => a + 1; //简化了很多
情况2:没有参数,只有一个返回
// ES5的写法
var f = function(){
return 'a';
}
// ES6的写法
let f = () => 'a';
情况3:多个参数,1个返回
// ES5的写法
var f = function(a, b, c){
return a + b + c;
}
// ES6的写法
let f = (a, b, c) => a + b + c;
情况4:函数里面有多条语句
// ES5的写法
var f1 = function(a, b){
var c = 0;
c += a * a;
c += b * b;
c = Math.sqrt(c);
return c;
}
// ES6的写法
let f2 = (a, b) => {
let c = 0;
c += a * a;
c += b * b;
c = Math.sqrt(c);
return c;
}
情况5:特例:当只有一个返回,且是一个对象的时候
// ES5
var f11 = function(a, b){
return {a: a, b: b}
}
// ES6
// 如果直接返回一个对象,那么大括号外面要有小括号
let f21 = (a, b) => ({a: a, b: b});
console.log(f21(1,2));
情况6:箭头函数和解构赋值的结合
var f1 = function({a, b}){
var c = Math.sqrt(a * a + b * b);
return c;
}
var obj = {a: 3, b: 4};
console.log(f1(obj));
let f2 = ({a, b}) => {
let c = Math.sqrt(a * a + b * b);
return c;
}
console.log(f1(obj));
情况7:常见的应用
map()里参数的处理
console.log([1, 2, 3].map(function(x){
return x * x;
}));
console.log([1, 2, 3].map(x => x * x)); //1 4 9
sort()的简化
console.log([1, 5, 2, -3].sort(function(a, b){
return a - b;
}));
console.log([1, 5, 2, -3].sort((a, b) => a - b)); //[-3, 1, 2, 5]
情况8:rest参数
let [a, ...args] = [1, 2, 3, 4];
console.log(args); //[2, 3, 4]
//1赋值给了a,其他剩下的值赋给args
用于函数的简化
// ES5的写法
function f1(a, ...args){
return args;
}
// ES6的写法
let f2 = (a, ...args) => args;
情况9:箭头函数的this是在定义时确定的,不能再调用时确定
// ES5
function f(){
setTimeout(function(){
console.log(this.id); //undefined
}, 1000);
}
f.call({id:5});
因为f.call的调用id是给了f,settimeout里的function函数有自己的this,所以输出undefined
// ES6
function f(){
setTimeout(() => {console.log(this.id)}, 1000); //1
}
let obj = {id: 1}
f.call(obj);
因为箭头函数不初始化this,所以会向上父作用域里找this,最后输出1。
情况10:箭头函数不可以作为构造函数,否则报错
因为箭头函数里没有this
let f2 = () => {
this.a = 1;
this.b = 2;
};
let a = new f2();
情况11:箭头函数不能使用arguments对象,需使用rest参数
// ES5
var f1 = function(){
console.log(arguments); // []
}
f1(1, 2, 3, 4);
// ES6
let f2 = (...args) => {
console.log(args);
}
f2(1, 2, 3, 4);
情况12:嵌套的箭头函数:箭头函数内嵌套箭头函数
也就是所说的管道机制
// ES5
function f1(...args1){
console.log(args1);
return {f2: function(...args2){
console.log(args2);
return {f3: function(...args3){
console.log(args3);
}};
}};
}
var c = f1(1, 2, 3).f2(4, 5, 6).f3(7, 8, 9); //[1, 2, 3] [4, 5, 6] [7, 8, 9]
// ES6
let f1 = (...args) => ({f2: (...args) => ({f3: (...args3) => {console.log(args3);}})})
var c = f1(1, 2, 3).f2(4, 5, 6).f3(7, 8, 9); // [7, 8, 9]
2.函数参数的默认值
情况1:默认值的基本用法
不设置默认值的写法
function f(x, y){
x = x || 'Hello';
y = y || 'World';
console.log(x, y);
}
f(); //Hello World
f('Lao Wang'); // Lao Wang World
f('Lao Wang', ''); //问题1:希望输出是空,实际输出Lao Wang World
为解决上面的问题1,可以通过设置默认值解决
function f2(x = 'Hello', y = 'World'){
console.log(x, y);
}
f2('Lao Wang', ''); //Lao Wang
f2('Lao Wang'); //Lao Wang World
情况2:函数默认值的参数不能重复声明
2.1 不能声明和形参一样的变量
function f(x = 5){
const x = 3;
}
f(); // 运行时会报错
2.2 当参数有了默认值后,不能重复声明
function f(x, x, y = 1){
console.log(x, y);
}
f(3, 4, 5); // 报错
想要重复声明,参数就不能赋默认值
function f(x, x, y){
console.log(x, y);
}
f(3, 4, 5); //4 5
2.3 参数默认值的计算是惰性的
每次调用都会重新计算参数里的表达式
let x = 9;
function f(y = x + 1){
console.log(y);
}
f(); //10
x = 10;
f(); // 11
情况3:函数默认值与解构默认值的结合使用
function f({a = 0, b = 0} = {a: 3}){
console.log(a, b);
}
f({a: 3, b: 4}); //3 4
f({a: 3}); //3 0
f({}); //0 0
f(); //3 0
函数默认是:a = 0, b = 0 结构默认值是:{a: 3}
情况4:实参省略的方法
在解构赋值里参数省略的方法
let [, b, c] = [1, 2, 3];
console.log(b, c); //2 3
但是在函数里不能这样省略
function f(x, y = 2, z){
console.log(x, y);
}
f( , 4, 3); //错误传参
f(undefined, 4, 3); //正确传参
情况5:函数的length:这个函数需要的必须参数的个数
console.log((function(a, b, c){}).length); //3
console.log((function(){}).length); //0
console.log((function(a, b, c = 0){}).length); //2
console.log((function(a = 1, b, c = 0, d ){}).length); //2
如果出现默认值,从默认值出现开始往后,都不算进length里
情况6:函数的name
函数的声明
function f(){
console.log('hello');
}
console.log(f.name); // f
函数的表达式
let f2 = function(){
console.log('hello');
}
console.log(f2.name); //f2
console.log((f2.bind({})).name); //bound f2
情况7:this的绑定和调用
call、aplay、bind的使用和区别
let obj = {
a: 25
};
function f(a, b){
console.log(this.a, a, b);
}
f.call(obj, 1, 2); // 25 1 2
f.apply(obj, [1, 2]); // 25 1 2
f.bind(obj)(1,2); // 25 1 2
四、数组的扩展
1.扩展运算符...(rest参数)
用于数组的解构赋值
let [a, ...args] = [1, 2, 3, 4];
console.log(args); // 1 2 3 4
用于函数参数的传递
let f = (a, ...args) => {console.log(args)};
f(1, 2, 3, 4); //1 2 3 4
数组的逆向读取
console.log(...[1, 2, 3]); //1 2 3
2. ...常用于替代apply
function f(){
console.log(arguments);
}
let args = [3, 4, 5];
f(args[0], args[1], args[2]); // 3 4 5
f.apply(null, args); // 3 4 5
f(...args); // 3 4 5
应用1: 求数组里的最大值
let a = [1, 2, 3];
console.log(Math.max(1, 3, 5));
console.log(Math.max.apply(null, a));
console.log(Math.max(...a));
应用2: 拼接两个数组
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
arr1.push(...arr2);
console.log(arr1);
console.log(arr1.concat(arr2));
console.log([...arr1, ...arr2]);
3.扩展的变量必须是最后一个,否则报错
let [a, ...b] = [1, 2, 3, 4]; //正确
let [a, ...b, c] = [1, 2, 3, 4]; //报错
4.字符串也可以使用扩展变量
console.log([...'hello']); // ['h', 'h', 'l', 'o', 'o']
//想要实现同样的效果,ES5是这样操作的
var str = 'hello';
var strArr = str.split('');
5.把类数组变成数组
5.1自定义的类数组
let arrayLike = {
'0': '1',
'1': '25',
'2': 'abc',
length: 3
}
// ES5
// let array = Array.prototype.slice.call(arrayLike);
let array = [].slice.call(arrayLike);
console.log(array); // ["1", "25", "abc"]
// ES6
let array2 = Array.from(arrayLike);
console.log(array2); // ["1", "25", "abc"]
5.2 DOM NodeList
let divs = document.querySelectorAll('div');
console.log(divs.__proto__.constructor.name); // NodeList
console.log(divs);
let array = Array.from(divs);
console.log(array.__proto__.constructor.name); //Array
console.log(array);
5.3 函数的 arguments
function f(){
console.log(arguments.__proto__.constructor.name); //object
console.log(arguments);
let args = Array.from(arguments);
console.log(args.__proto__.constructor.name); // Array
console.log(args);
}
f(1, 2, 3, 4);
6.Array.of: 把零散的数据变为数组
let a = [1, 2, 3]; // [1, 2, 3]
let b = new Array(3); //长度为3,但值为空的数组
let c = Array.of(3); // [3]
console.log(a, b, c); // [1, 2, 3]
7.实例实例的find(), findIndex() 写一个回调函数
find()里可以是一个函数,找到符合条件的值
let a = [1, 4, -3, 9];
console.log(a.find(x => x < 0)); // -3
console.log(a.find((value, index, arr) => {
console.log(value, index, arr);
return value < 0;
}));
找到符合条件值对应的索引
console.log(a.findIndex((value, index, arr) => {
console.log(value, index, arr);
return value < 0;
}));
找到NaN的值,这是在ES5里比较难做到的
let b = [1, 4, NaN];
console.log(b.findIndex((value, index, arr) => {
console.log(value, index, arr);
return Object.is(NaN, value);
}));
需要用Object.is,不能使用isNan,因为NaN == NaN 是false
8. 数组实例的填充fill()
let a = new Array(5);
a.fill(0);
console.log(a); // [0, 0, 0, 0, 0]
let b = new Array(5);
b.fill(0, 1, 3); // (填充的值,从第几个开始填充,填充到第几个之前)
console.log(b); // [ , 0, 0, , ]
9. 数组实例的entries(), keys(), values()
遍历下标
let a = [1, 2, 3, 4];
for(let index of a.keys()){
console.log(index); // 0 1 2 3
}
遍历值
for(let elem of a.values()){
console.log(elem); // 1 2 3 4
}
遍历下标和值
for(let [index, elem] of a.entries()){
console.log(index, elem); // 0 1, 1 2, 2 3, 3 4
}
逐个输出下标和值
let entries = a.entries();
console.log(entries.next().value); // 0 1
console.log(entries.next().value); // 1 2
10.数组实例的includes()
let a = [1, 2, 5, NaN];
console.log(a.includes(2)); // true
console.log(a.includes(10)); // false
console.log(a.includes(NaN)); // true
比indexOf好的地方:1. 语义化, 2. NaN