ES6(扩展)

字符串扩展

模板字符串
const xiaoming = {
    name:'小明',
    age:14,
    say1:function(){
        console.log('我叫' + this.name + ',我今年' + this.age + '岁了');
    },
    say2:function(){
        console.log(`我叫${this.name},我今年${this.age}岁了`);  // 这就是模板字符串!
    }
}
xiaoming.say1();    // 我叫小明,我今年14岁了
xiaoming.say2();    // 我叫小明,我今年14岁了
新的方法
  • padStart(参数1,参数2):从头部开始补全
// padStart(参数1,参数2):从头部开始补全
// 参数1:补全后的字符串长度
// 参数2:用来补全的字符串
let str = 'i';
let str1 = str.padStart(5,'mooc');
let str2 = str.padStart(8,'mooc');

console.log(str1);  // mooci
console.log(str2);  // moocmooi

// 常用于日期自动补全,比如 3 自动补全成 03
  • padEnd(参数1,参数2):从尾部开始补全
// padEnd(参数1,参数2):从尾部开始补全
// 参数1:补全后的字符串长度
// 参数2:用来补全的字符串
let str = 'i';
let str3 = str.padEnd(5,'mooc');
let str4 = str.padEnd(8,'mooc');

console.log(str3);    // imooc
console.log(str4);    // imoocmoo
  • repeat(参数:重复次数)
// repeat(参数:重复次数)
console.log('i'.repeat(10));    // iiiiiiiiii
  • startsWith(参数:字符串):判断是否以参数中的字符串开始
  • endsWith(参数:字符串):判断是否以参数中的字符串结束
const str = 'A promise is a promise';

console.log(str.startsWith('B'));       // false
console.log(str.startsWith('A pro'));   // true

console.log(str.endsWith('A'));         // false
console.log(str.endsWith('promise'));   // true
  • includes(参数:字符串):判断是否包含参数中的字符串
const str = 'A promise is a promise';

if(str.indexOf('promise') !== -1){
    console.log('存在1');   // 存在1
}

if(str.includes('promise')){
    console.log('存在2');   // 存在2
}
  • String.raw:在"\"之前自动添加转义字符"\"
console.log(String.raw`Hello\nworld`);  // Hello\nworld
console.log(`Hello\nworld`);            // Hello
                                        // world
for-of遍历字符串
const words = "promise";

for(let word of words){
    console.log(word);
}

// 输出结果:p r o m i s e
unicode表示法

unicode是一项标准,包括字符集,编码方案等。
它是为了解决传统的字符编码方案的局限而产生的,为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言,跨平台进行文本转移,处理的要求。

// 超出两个字节(0xFFFF)的unicode,要用{}包裹起来,否则不能正确显示
console.log(`\u0061`);      // a    正确表示
console.log(`\u20BB7`);     // ₻7   没有正确表示
console.log(`\u{20BB7}`);   //    正确表示
// charCodeAt不能正确取得字符长度超过2个字节的字符所对应的Unicode码
// 请看下面的codePointAt方法

let s = '';

// .length属性的计算规则:unicode长度是两个字节,.length的结果是1
// 该字符unicode长度查过0xFFFF,被认为是4个字节,所以.length的结果是2
console.log(s.length);          // 2     

console.log(s.charAt(0));       // �        乱码,前两个字节的unicode码对应的字符
console.log(s.charAt(1));       // �        乱码,后两个字节的unicode码对应的字符
console.log(s.charCodeAt(0));   // 55362     前两个字节的unicode码
console.log(s.charCodeAt(1));   // 57271     后两个字节的unicode码
// codePointAt可以正确取得字符长度超过2个字节的字符所对应的Unicode码

let s = 'a';

console.log(s.length);                      // 3        字符''长度2,字符'a'长度1,所以结果是3

console.log(s.codePointAt(0));              // 134071   字符''的unicode码
console.log(s.codePointAt(0).toString(16)); // 20bb7    字符''的unicode码的16进制表示
console.log(s.codePointAt(1));              // 57271    字符''的后两个字节的unicode码,没有什么意义
console.log(s.codePointAt(2));              // 97       字符'a'的unicode码
console.log(String.fromCharCode('0x20bb7'));    // ஷ    乱码,不能正确处理超过2个字节的字符
console.log(String.fromCodePoint('0x20bb7'));   //      正确显示,可以正确处理超过2个字节的字符

正则扩展

  • 新的写法
// 以下三种是ES5中就已经有的写法
const regex1 = new RegExp('xyz','i');
const regex2 = new RegExp(/xyz/i);
const regex3 = /xyz/i;

console.log(regex1.exec('xyz123xyz'));  // ["xyz", index: 0
console.log(regex2.exec('xyz123xyz'));  // ["xyz", index: 0
console.log(regex3.exec('xyz123xyz'));  // ["xyz", index: 0

// 以下是ES6中的新写法,允许第一个参数是字面量,然后再加第二个参数
// 此时第二个参数"i",会覆盖第一个参数的"ig"
const regex4 = new RegExp(/xyz/ig,'i');
console.log(regex4.exec('xyz123xyz'));  // ["xyz", index: 0
  • u unicode修饰符
// 如果所要匹配的字符串超过2个字节,需要用u修饰符
// .只能匹配0xFF之内的字符,超出0xFF需要用u修饰符去匹配

// 字符串'\ud83d\udc36',这一个整体表示的unicode,只有加上u之后匹配才算真正匹配到
console.log('\ud83d\udc36');    // 
console.log(/^\ud83d/.test('\ud83d\udc36'));        // true,这里把'\ud83d\udc36'当成2个字符
console.log(/^\ud83d/u.test('\ud83d\udc36'));       // false,这里把'\ud83d\udc36'当成1个字符
console.log(/^\ud83d\udc36/u.test('\ud83d\udc36')); // true,这里把'\ud83d\udc36'当成1个字符

// 如果{}包裹的是unicode编码,需要用u修饰符才能识别
console.log(/\u{61}/.test('a'));    // false
console.log(/\u{61}/u.test('a'));   // true,只有加u修饰符,才能识别

console.log(`\u{20BB7}`);       // 
const str = '';

// .并不能匹配到超出两个字节的字符,需要加u修饰符才行
console.log(/^.$/.test(str));       // false
console.log(/^.$/u.test(str));      // true

// {2}并不能匹配到超出两个字节的字符的数量,需要加u修饰符才行
console.log(/{2}/.test(''));   // false
console.log(/{2}/u.test(''));  // true
  • y 黏连修饰符
const r1 = /imooc/g;
const r2 = /imooc/y;
const str = 'imoocimooc-imooc';

console.log(r1.exec(str));
    // 找到第一个:["imooc", index: 0, input: "imoocimooc-imooc", groups: undefined]
console.log(r1.exec(str));
    // 找到第二个:["imooc", index: 5, input: "imoocimooc-imooc", groups: undefined]
console.log(r1.exec(str));
    // 找到第三个:["imooc", index: 11, input: "imoocimooc-imooc", groups: undefined]
console.log(r1.exec(str));
    // 没有了:null

// y修饰符是要黏连住的才能找到
// 当找到第二个之后,接下来的字符是"-",不符合"imooc",所以就找不到了
console.log(r2.exec(str));  
    // 找到第一个:["imooc", index: 0, input: "imoocimooc-imooc", groups: undefined]
console.log(r2.exec(str));  
    // 找到第二个:["imooc", index: 5, input: "imoocimooc-imooc", groups: undefined]
console.log(r2.exec(str));  
    // 没有了:null

// 判断某一个正则是否有y修饰符
console.log(r1.sticky);  // false
console.log(r2.sticky);  // true
  • s修饰符(ES6中还未实现,期待。。)
    可用于查找换行符,回车符,行分隔符,段分隔符

数值扩展

新的进制表示法
console.log(016);   // 14
// 以上其实是八进制的16,转换成十进制就是14
// 是不是容易不好理解,容易引起歧义?所以不建议这么写

// 以下是建议的书写方式
// 0o 0O octonary   八进制
// 0b 0B binart     二进制
console.log(0o16);      // 14
console.log(0b1111);    // 15
新的方法

在ES6中,以下方法挂载在Number对象上,所以使用的时候最好用Number.方法()的形式。

  • parseInt():取整(常用于字符串取整)
// 字符串必须以数字开头才能取到数值
console.log(Number.parseInt('123abc'));     // 123
console.log(Number.parseInt('abc123'));     // NaN
console.log(Number.parseInt(1.23));         // 1 这样用也是可以的
  • parseFloat():取小数(常用于字符串取小数)
// 字符串必须以数字开头才能取到数值
console.log(Number.parseFloat('1.23abc'));  // 1.23
console.log(Number.parseFloat('abc1.23'));  // NaN
console.log(Number.parseFloat(1.23));       // 1.23 这样用也是可以的
  • isNaN():判断其参数是否是NaN
// 只有当值是NaN的时候,才会返回true
console.log(Number.isNaN(NaN));     // true
console.log(Number.isNaN(-NaN));    // true
console.log(Number.isNaN(1));       // false
console.log(Number.isNaN('1'));     // false
console.log(Number.isNaN(true));    // false
  • isFinite():判断其参数是否是有限的
// 只有当其参数是一个正儿八经的有限数时,才会返回true
console.log(Number.isFinite(2/0));      // false
console.log(Number.isFinite(2/4));      // true
console.log(Number.isFinite(1234));     // true
console.log(Number.isFinite('1234'));   // false
console.log(Number.isFinite(true));     // false
console.log(Number.isFinite(NaN));      // false
  • isInteger():判断其参数是否是整数
console.log(Number.isInteger(25));      // true
console.log(Number.isInteger(25.0));    // true  25.0的值跟25是一样的,所以结果为true
console.log(Number.isInteger(25.1));    // false
console.log(Number.isInteger('25'));    // false 首先参数得是数字,否则结果都为false
  • isSafeInteger():判断其参数是否是安全数 (处于JS能表示的数值范围之内)
console.log(Number.MAX_SAFE_INTEGER);   // JS能表示的最大值:9007199254740991(2的53次 - 1)
console.log(Number.MIN_SAFE_INTEGER);   // JS能表示的最小值:-9007199254740991(-2的53次 + 1)

console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER - 1)); // true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false

console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER + 1)); // true
console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1)); // false
  • Math.trunc():取其参数的整数部分的值
console.log(Math.trunc(4.1));   // 4
console.log(Math.trunc(4.9));   // 4
  • Math.sign():判断其参数大于0,等于0,还是小于0
console.log(Math.sign(-5));     // -1
console.log(Math.sign(0));      // 0
console.log(Math.sign(5));      // 1
console.log(Math.sign("5"));    // 1    把字符"5"转换成了数字5,所以结果是1
console.log(Math.sign("-5"));   // -1   把字符"-5"转换成了数字-5,所以结果是-1
console.log(Math.sign("abc"));  // NaN  非数字,结果为NaN
  • Math.cbrt():取其参数的立方根
console.log(Math.cbrt(8));  // 2
幂运算
console.log(2 ** 3);        // 8(2的3次方)

// 幂运算是右结合的
// 以下两种结果是一样的
console.log(2 ** 3 ** 0);   // 2
console.log(2 ** (3 ** 0)); // 2

函数扩展

默认参数
function add1(a, b = 2) {
    console.log(a, b); // 1 2
}
add1(1);

// 这样写b的默认值也是可以的
function add2(a, b = a + 2) {
    console.log(a, b); // 1 3
}
add2(1);
剩余参数...

我们通过一个例子来解释什么是剩余参数...,它与扩展运算符的概念又有什么不同。

// 任务:把字符串装换为数组
const str = 'abcde';

// 方式1:使用扩展运算符...
// 这里的...叫扩展运算符,是负责扩展的
const arr1 = [...str];
console.log(arr1);      // ["a", "b", "c", "d", "e"]

// 方式2:使用剩余参数...
// 这里的...叫剩余参数,是负责聚合的
const [...arr2] = str;
console.log(arr2);      // ["a", "b", "c", "d", "e"]

// 方式3:使用Array原型对象的方法slice
const arr3 = Array.prototype.slice.call(str);
console.log(arr3);      // ["a", "b", "c", "d", "e"]
箭头函数(=>)
  • 一个简单的箭头函数
// 以下两种方式定义的函数是一模一样的
// 方式1:传统方式
function add1(a, b) {
    return a + b;
}

// 方式2:箭头函数
const add2 = (a, b) => a + b;

console.log(add1(2, 2)); // 4
console.log(add2(2, 2)); // 4
  • 不带返回值的箭头函数
const pop1 = arr => arr.pop();        // 运行arr.pop()处理,且返回处理后的值 
const pop2 = arr => void arr.pop();   // 运行arr.pop()处理,不返回

console.log(pop1([1, 2, 3]));    // 3
console.log(pop2([1, 2, 3]));    // undefined
  • 箭头函数是没有arguments的
const log = () => {
    console.log(arguments); // 报错:arguments is not defined
}
log(1,2,3);
  • 箭头函数中的this,是定义自身的环境中的this
// 例子1:对象中的方法要取得自身属性的话,还是不要用箭头函数了
// 方法可以使用简洁表示法,请继续往下看
const xiaoming = {
    name:'小明',
    say1:function(){
        console.log(this.name); // 小明 this指向的是对象本身
    },
    say2:() => {
        console.log(this.name); // 空 this指向的是window对象
    }
}
xiaoming.say1();
xiaoming.say2();
// 例子2:模拟取得ajax数据
// 方式1:传统方式,必须保存this然后才能使用
const xiaoming1 = {
    name:'xiaoming',
    age:null,
    getAge:function(){
        const _this = this;
        // ajax...
        setTimeout(function(){
            _this.age = 14;
        }, 1000);
    }
}
// 方式2:箭头函数,可以直接使用this
const xiaoming2 = {
    name:'xiaoming',
    age:null,
    getAge:function(){
        // ajax...
        setTimeout(() => {
            this.age = 14;  // this指向的是定义自己的环境中的this,也就是方式1中的_this
        }, 1000);
    }
}

xiaoming1.getAge(); // {name: "xiaoming", age: 14, getAge: ƒ}
xiaoming2.getAge(); // {name: "xiaoming", age: 14, getAge: ƒ}
尾调用
// 以下就是尾调用
// 当有多个函数嵌套使用的时候,可以用于提升性能

function tail(x){
    console.log('tail',x);
}
function fx(x){
    return tail(x);
}
fx(123);    // tail 123

对象扩展

简洁表示法
  • 传统方式
const getUserInfo1 = (id = 1) => {
    // Ajax...
    const name = 'xiaoming';
    const age = 10;

    return {
        name:name,
        age:age,
        say:function(){
            console.log(this.name + this.age);
        }
    }
}
const xiaoming1 = getUserInfo1();
  • 简洁表示
const getUserInfo2 = (id = 1) => {
    // Ajax...
    const name = 'xiaoming';
    const age = 10;

    return {
        name,
        age,
        say(){
            console.log(this.name + this.age);
        }
    }
}
const xiaoming2 = getUserInfo2();
属性名表达式
const key = 'age';
const xiaoming = {
    name:'xiaoming',
    [key]:14
}

// 跟以下内容是一模一样的
const xiaoming = {
    name:'xiaoming',
    age:14
}
复制对象
const obj = {
a: 1,
b: 2,
c: {
    aa: 11,
    bb: 22
}
};
// 复制对象
const cObj = { ...obj };
console.log(cObj); // {a: 1, b: 2, c: {aa:11,bb:22}}

// 可以看到,obj.aa改变了,cObj.aa也改变了。
// 这里的复制是浅复制。
obj.aa = 33;
console.log(cObj); // {a: 1, b: 2, c: {aa:11,bb:33}}
新的方法和属性
  • Object.is():与===几乎一样
// 与===不同的地方是这两个
console.log(Object.is(+0,-0));      // false
console.log(+0 === -0);             // true
console.log(Object.is(NaN,NaN));    // true
console.log(NaN === NaN);           // false
  • Object.assign():合并对象
// 注意:这里的合并也是浅拷贝!!
// 只拷贝自身的属性和方法,无法拷贝继承的属性和方法
const obj = Object.assign(
    { a: 1 },
    { b: 2 },
    { c: 3 },
    { d: 4, e: 5 }
);
console.log(obj);   // {a: 1, b: 2, c: 3, d: 4, e: 5}
  • Object.keys():取得对象的key并组成数组
  • Object.values():取得对象的value并组成数组
  • Object.entries():不知道怎么描述,还是看下面的输出结果体会吧
const obj = {
    a:1,
    b:2,
    c:3,
    d:4
};
console.log(Object.keys(obj));      // ["a", "b", "c", "d"]
console.log(Object.values(obj));    // [1, 2, 3, 4]
console.log(Object.entries(obj));   // ["a", 1],["b", 2],["c", 3],["d", 4]
  • for-in:遍历对象
// 顺便提下,最好能记住
// for-in是遍历对象的
// for-of是遍历数组和字符串,这种拥有迭代器的集合

// for-in
const obj = {
    a: 1,
    b: 2,
    c: 3
};
for (let key in obj) {
    console.log(key);  // a b c
}

// for-of
const arr = [1,2,3];
for(let i of arr){
    console.log(i);  // 1 2 3
}
  • Object.setPrototypeOf(参数1:目标对象,参数2:原型对象):设定原型对象
  • Object.getPrototypeOf(参数:目标对象):取得原型对象
const obj1 = {
    a: 1
};
const obj2 = {
    b: 2
};
const obj = Object.create(obj1);
console.log(obj.__proto__);         // {a: 1}

Object.setPrototypeOf(obj, obj2);  // 设定obj的原型对象为obj2
console.log(obj.__proto__);        // {b: 2}

// Object.getPrototypeOf(obj) 和 obj.__proto__是一样的
console.log(Object.getPrototypeOf(obj)); // {b: 2}
console.log(obj.__proto__);              // {b: 2}
console.log(Object.getPrototypeOf(obj) === obj.__proto__); // true
  • super:可以访问到原型对象
const obj = { name: "xiaoming " };
const cObj = {
    say() {
        console.log(`My name is ${super.name}`);
    }
};
Object.setPrototypeOf(cObj, obj);
cObj.say();

数组扩展

扩展
  • 结合扩展运算符
const arr = [1, 2, 233, 3, 4, 5];
console.log(Math.max(...arr));          // 233
console.log(Math.max.apply(null, arr)); // 233 
  • Set构造方法
// Set方法构造出来的内容,不会有重复
// 所以,可以用来做去重处理
const set = new Set([1, 2, 2, 3]);
const num = [...set];
console.log(num);  // [1, 2, 3]
新的方法
  • Array.indexOf(参数:查找目标):查找数组中的目标元素
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");  // 2
  • Array.from(参数:原对象,回调):将一个ArrayLike对象或者Iterable对象转换成一个Array
// 注意:类数组对象的属性名必须为数值型或字符串型的数字,就像下面这样
const obj = {
    0: 1,
    1: "22",
    length: 2
};

console.log(Array.from(obj, item => item * 2)); // [2, 44]
  • Array.of(各种参数):把参数合成一个数组
console.log(Array.of(1, 2, "123", false));  // [1, 2, "123", false]
console.log(Array.of());  // [] 空数组
  • Array#fill(content,start,end):填充数组
let arr1 = new Array(10).fill(0);
console.log(arr1);  // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

let arr2 = new Array(10).fill(0,0,3);
console.log(arr2);  // [0, 0, 0, empty × 7]  注意结束位置是end-1

console.log([1,2,3].fill(0));                // [0, 0, 0]
console.log(['a','b','c','d'].fill(7,1,3));  // ["a", 7, 7, "d"] 注意结束位置是end-1
  • Array#includes:检测数组中是否包含某一项(与字符串的includes方法类似)
const arr = [1, 2, 3, 4, NaN];

console.log(arr.includes(1));   // true
console.log(arr.includes(55));  // false
console.log(arr.includes(NaN)); // true  这个就很厉害了
  • Array#keys():取得数组的key
  • Array#values():取得数组的value
  • Array#entries():取得数组的key和value
const arr = [1, 2, 3, 444];

console.log(arr.keys()); // Array Iterator {}:迭代器
for (const i of arr.keys()) {
    console.log(i); // 0 1 2 3
}

for (const v of arr.values()) {
    console.log(v); // 1 2 3 444
}

for (const item of arr.entries()) {
    console.log(item);  // [0, 1] [1, 2] [1, 2] [2, 3] [3, 444]
}
  • find():根据条件(回调) 按顺序遍历数组 当回调返回true时 就返回当前遍历到的值
const arr = [1, 7, 6, 3, 8];
const rst = arr.find((value, index, arr) => value % 2 === 0);

console.log(rst);   // 6 找到符合条件的内容,就返回了,不再继续找了
  • findIndex():根据条件(回调) 按顺序遍历数组 当回调返回true时 就返回当前遍历到的下标
// 功能与indexOf有点类似
const arr = [1, 7, 6, 3, 8];
const rst = arr.findIndex((value, index, arr) => value % 2 === 0);

console.log(rst);   // 2

Symbol数据类型

概念:Symbol数据类型提供一个独一无二的值
// 声明方式1:Symbol()
let a1 = Symbol();
let a2 = Symbol();
console.log(a1 === a2); // false    a1和a2永远都不会相等

// 声明方式2:Symbol().for(key)
// 先检查key值是否已经注册
// 如果key值没有注册,那么生成一个新的独一无二的值
// 如果key值已经注册,那么返回那个已经生成的独一无二的值
let a3 = Symbol.for('a3');
let a4 = Symbol.for('a3');
console.log(a3 === a4); // true    a3已经被注册了,所有这里就返回那个值
作用:在定义对象属性的时候,可以不用考虑属性重复问题
let a1 = Symbol.for('abc'); // 好处:不用考虑其他人也在这个对象里使用'abc'属性了
let obj = {
    [a1]: '123',
    'abc': 345,
    'c': 456
}
console.log(obj);
// abc: 345
// c: 456
// Symbol(abc): "123"

// 只能取到非Symbol类型的数据
for (let [key, value] of Object.entries(obj)) {
    console.log(key, value);
    // abc 345
    // c 456
}

// 只能取到Symbol类型的数据
Object.getOwnPropertySymbols(obj).forEach(item => {
    console.log(item, obj[item]);
    // Symbol(abc) 123
})

// 可以取到所有类型的数据
Reflect.ownKeys(obj).forEach(item => {
    console.log(item, obj[item]);
    // abc 345
    // c 456
    // Symbol(abc) 123
})

类扩展

定义
class MyApp{
    constructor(){
        this.name = 'imooc';
    }
    sayHello(){
        console.log(`hello ${this.name}!`);
    }
}

// 实例化一个对象
const app = new MyApp();

// 使用对象的sayHello方法
app.sayHello();    // hello imooc
继承
class Parent {
    constructor(name = 'song') {
        this.name = name;
    }
}

class Child extends Parent {}
const child = new Child();

console.log(child); // {name: "song"}
继承(传递参数)
class Parent {
    constructor(name = 'song') {
        this.name = name;
    }
}

class Child extends Parent {
    constructor(name = 'child') {
        super(name);    // 这个要放在第一行,会覆盖父元素的name属性
        this.type = 'child';
    }
}
const child1 = new Child();
const child2 = new Child('hello');

console.log(child1); // {name: "child", type: "child"}
console.log(child2); // {name: "hello", type: "child"}
set,get
class Parent {
    constructor(name = 'song') {
        this.name = name;
    }
    // 注意:longName是一个属性
    get longName() {
        return 'mk' + this.name;
    }
    set longName(value) {
        this.name = value;
    }
}

let v = new Parent();
console.log(v.longName);    // mksong

v.longName = 'hello';
console.log(v.longName);    // mkhello
静态方法
class Parent {
    constructor(name = 'song') {
        this.name = name;
    }
    // 定义一个静态方法tell
    static tell() {
        console.log('tell');
    }
}

// 静态方法的调用方式:只能通过类调用
Parent.tell();  // tell
静态属性
class Parent {
    constructor(name = 'song') {
        this.name = name;
    }
    // 定义一个静态方法tell
    static tell() {
        console.log('tell');
    }
}

// 定义一个静态属性type
Parent.type = 'test';

// 静态属性的访问方式:只能通过类调用
console.log(Parent.type);   // test

你可能感兴趣的:(ES6(扩展))