ES6 语法学习(一)

1、let 和 const 关键字

 let 与 var 的区别有:

a、let 声明的变量只在当前的块级作用域内有效(块级作用域通俗的话就是被{}包裹起来的区域声明对象的{}例外)。

b、let 声明的变量不能被重复声明。

c、不存在变量的提升。

<body>
<input type="button" value="test-1">
<input type="button" value="test-2">
<input type="button" value="test-3">
<input type="button" value="test-4">
<input type="button" value="test-5">
<input type="button" value="test-6">
<script>
    window.onload = function () {
        let ainp = document.getElementsByTagName('input');
        // for(var i=0;i<ainp.length;i++){
        //     ainp[i].index=i;
        //     ainp[i].onclick=function(){
        //         console.log(this.index);
        //     }
        // }
        for (let i = 0; i < ainp.length; i++) {
            ainp[i].onclick = function () {
                console.log(i);
            }
        }
    }

</script>
</body>

 const 常量--不可以改变的量

常量在声明的时候必需被赋值否则会报错(Missing initializer in const declaration),而变量在声明的时候可以不被赋值

常量是不可被改变的,但是常量为引用类型的时候不保证不会被改变(可以用Object.freeze进行冻结),也可以使用闭包的形式对其进行保护。

const a = {test: 'haha'};
console.log(a);
//输出 haha
a.test = 'are you ok???';
console.log(a);
//输出 are you ok???
//防止常量被修改可以用Object.freeze(object)进行冻结
const b = {name: 'king'};
Object.freeze(b);
b.name = 'haha';
console.log(b);
//输出 king
const t=[1];
Object.freeze(t);
t.push(2);
//会报错
console.log(Array.isArray(t));
//输出 true

 扩展:Object.freeze,Object.defineProperty,Object.seal

    // Object.freeze 是对对象的冻结,使对象不可被修改和扩展,但是多级的object那么就需要使用递归
    const obj = {
        name: 'test',
        age: 20,
        content:{
            t:'haha'
        }
    };
    // Object.freeze(obj);
    //并且实现递归
    Object.defineProperty(Object, 'yffreeze', {
        value: function (val) {
            for (let per in val) {
                if (val.hasOwnProperty(per)) {
                    if (typeof val[per] == 'object') {
                        arguments.callee(val[per]);
                    } else {
                        Object.defineProperty(val, per, {
                            writable: false
                        })
                    }
                }
            }
            //该函数实现对象的不可扩展性
            Object.seal(val);
        }
    });
    Object.yffreeze(obj);
    obj.content.t = 'nono';
    console.log(obj);
    //结果不会被更改

 2、解构赋值

解构赋值主要包括两个方面:数组的解构赋值,对象的解构赋值,字符串的解构赋值,数值与布尔值的解构赋值,函数参数的解构赋值。

数组的解构赋值

//多维数组解构赋值
let arr1 = [1, 2, 3, ['a', 'b', ['this is d']]];
let [, , , [, , [d]]] = arr1;
console.log(d);
//输出 this is d

//扩展运算符
let [a, b, ...arr] = arr1;
console.log(a, b, arr);
//输出 1  2  [3, ['a', 'b', ['this is d']]]

//利用扩展运算符合并多个数组
let t1 = [1, 2, 3];
let t2 = ['a', 'b', 'c'];
console.log([...t1, ...t2
])
;
//输出 [1, 2, 3, "a", "b", "c"];

//当且仅当,项数的值为undefined的时候,默认的等号才起作用(值为null的时候等号不起作用)
let [m, n = 'no'] = ['ok'];
console.log(n);
//输出 no

//交换变量
let p = 'are you ok???';
let q = 'today is good day!!!';
[p, q] = [q, p];
console.log(p, q);
//输出 today is good day!!!  are you ok???

//对已经声明的变量进行数组解构赋值
let ori;
[ori] = ['this is a test'];
console.log(ori);
//输出 this is test

 对象的解构赋值

//通常情况下解构赋值
let obj = {name: 'AAA', age: 30};
let {name, age} = obj;
console.log(name, age);
//输出 AAA 和 30

//给对象解构赋值,并且起新名
let obj1 = {name: 'BBB', age: 40};
let {name: new_name, age: new_age} = obj1;
console.log(new_name, new_age);
//输出 BBB 和 40
console.log(name, age);
//对于name 和age 是没有影响的

//扩展运算符在对象中的使用
let obj3 = {fav: 'reading'};
let obj2 = {...obj, ...obj3};
//拼接对象如果有同类项,那么后面的值会对前面的值进行覆盖
console.log(obj2);
//输出 {name: "AAA", age: 30, fav: "reading"}
let {name: obj2_name, ...other} = obj2;
//注意避免重名的方法就是起别名
console.log(obj2_name, other);
//输出 AAA {age: 30, fav: "reading"}

//对已经声明的对象进行解构赋值,注意要加上括号
let set;
({name: set} = obj);
console.log(set);

//声明解构赋值的默认值,并且只有在undefined的情况下,这种默认值有效
let {name: aa, age: bb, hobby = 'test'} = obj;
console.log(hobby);

//获取整项的同时又获取子项
{
    let {name, hobby, hobby: [hob1],} = {
        name: 'this is name',
        hobby: ['reading']
    };
    console.log(hobby);
    console.log(hob1);
}

//复杂情况下的解构赋值
{
    let data = {
        name: 'testName',
        age: 'testAge',
        content: [
            {first: 'AAA', son: ['A', 'a']},
            {second: 'BBB', son: ['B', 'b']},
            {third: 'CCC', son: ['C', 'c']},
        ]
    };
    //获取content并且用arr命名,获取content里除first的其他项
    let {content: arr, content: [first, ...rest]} = data;
    //获取content里面 second项里面的b值
    let {content: [, {son: [, sec_b]}]} = data;
}

 对象解构赋值在函数传参中的运用

//在ES6之前的参数匹配
let test = function (a = 'ok') {
    console.log(a);
};
test('abc');

let test1 = function (obj) {
    let name = obj && obj.name || 'name';
    let age = obj && obj.age || 30
    console.log(name, age);
};
test1({name: 'haha'});

//以ES6的形式进行传参,那么在函数进行调用的时候,必需传入对象,否则会报错
let test2 = function ({url = 'http://www.baidu.com', type = 'get'}) {
    console.log(url);
    console.log(type);
};
test2({url: 'http://www.taobao.com'});

 字符串的解构赋值

//对字符串进行解构赋值相当于str.split('')的效果
let [...arr] = 'congratulation';
console.log(arr);
//输出 ["c", "o", "n", "g", "r", "a", "t", "u", "l", "a", "t", "i", "o", "n"]

//对字符串的属性进行解构赋值
let {length, split: sp} = 'ok';
console.log(length);
console.log(sp);
//分解出来的方法要用call来调用
console.log(sp.call('no', ''));

 数值和布尔的解构赋值可以利用花括号对其属性的提取。

//在ES6之前获取函数面的实参的方法
let test = function () {
    console.log(arguments);
};
test(1, 2, 3);
//输出 Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//在ES6添加了一个扩展运算符
let test1 = function (...rest) {
    console.log(rest);
};
test1('a', 'b', 'c');
//输出 ["a", "b", "c"]

 3、ES6的函数扩展

 字符串方法的扩展

 --模板字符串:主要用的是``这个符号对字符串进行修辞,如果遇到变量,用${}对变量进行解析

let name = 'aaa';
let age = 30;
let str = `我的名称叫${name},我的年龄是${age}`;
console.log(str);
//输出 我的名称叫aaa,我的年龄是30
//效果等同于以下方法
let str1 = "我的名称叫" + name + ",我的年龄是" + age;
console.log(str1);

--字符串函数部份

//padStart padEnd  表示对字符串进行补全,padStart表示往字符串前添加,padEnd表示往字符串后面追加
let str = 'today';
console.log(str.padStart(10, 'ok'));
//输出 okokotoday  如果长度不刚好,这个函数会对其进行截取操作
console.log(str.padEnd(10, 'ok'));
//输出 todayokoko

//repeat 对字符串进行复制操作,repeat的参数不能为负数
console.log(str.repeat(3));
//输出 todaytodaytoday
//运用函数自己封装
let str_repeat = function (str, num) {
    //运用数组拼接的方法
    return new Array(num + 1).join(str);
};
console.log(str_repeat(str, 3));

//startsWith  endsWith  判断是否是以指定的字符串开头和结尾,返回的是一个布尔值
console.log(str.startsWith('t'));   //输出 true
console.log(str.startsWith('n'));   //输出 false
console.log(str.endsWith('y'));     //输出 true

//includes  表示包含的意思,返回的是一个布尔值
console.log(str.includes('od'));
console.log(str.includes('today'));
console.log(str.includes('ok'));

 --字符串的遍历方法

//ES6之前的方法是通过for来对字符串进行遍历的
let str = 'congratulation';
for (let i = 0, len = str.length; i < len; i++) {
    // console.log(str[i]);
    console.log(str.charAt(i));
}
//也可以Array.prototype.slice.call(str);

//注意区别for in,并且for...of...也可以用在数组里面,但是不可用在对象里面
for (let word of str) {
    console.log(word);
}

 --unicode 在没有办法解析的时候可以用花括号进行修辞 如 console.log(`u{1f436}`),输出的是一个小图标

 正则表达式的扩展

通常来讲,正则表达式的修辞符包括三个:i m g 但是在ES6中添加了两个修辞符,具体区别和例子如下

    console.log(/^uD83D/.test('uD83DuDC2A')); // true
    console.log(/^uD83D/u.test('uD83DuDC2A'));// false
    //正则表达式中,如果加了y那么就是表示连续的两个指定字符
    let reg1 = /ok/g;
    let reg2 = /ok/gy;
    let str = 'okok-are you okok--ok';
    console.log(str.match(reg1));
    console.log(str.match(reg2));

 函数的扩展

//函数参数默认值,在默认值调用的时候不能调用后面未声明的参数
let test = function (a = 'ok', b = a + 'yes') {
    console.log(a, b);
};
test();

//函数参数的扩展运算符,其使用情况和数组的扩展运算符一样
let test1 = function (a, ...rest) {
    console.log(a, rest);
};
test1(1, 2, 3, 4, 5, 6);

//箭头函数,在箭头函数中,是没有arguments这个获取参数的方法以及arguments.callee这个方法
let test2 = () => {
    // console.log(arguments);
};
test2(1, 2, 3, 4, 5);
//会报错

//简单的箭头函数如果避免其有返回值,在唯一返回值前添加一个void便可以避免其有返回值
let arr = [1, 2, 3, 4, 5, 6];
let test3 = arr => void arr.pop();
console.log(test3(arr));

//箭头函数没有自己的this其this指向的是自身所处环境的this
let test4 = function () {
    this.name = 'ok';
    let test5 = () => {
        console.log(this);
    };
    test5()
};
let t = new test4();
//输出 test4 {name: "ok"},说明test5的this指向是test4;

 对象的扩展

//ES6对象的表示法,如果对象的项与变量一样,那么只写一项就可以了
let name = 'AAA';
let age = 30;
let obj = {
    name, age, say() {
        console.log('ok');
    }
};
console.log(obj);
//输出 {name: "AAA", age: 30, say: ƒ}

//还有一种表示法
let n_obj = {
    [name]: 'BBB',
    [age]: 40
};
console.log(n_obj);
//输出 {30: 40, AAA: "BBB"}

//使用扩展运算符对对象进行复制,这个功能是浅复制,注意浅复制的顺序会影响对象里的顺序
let a_obj = {
    name,
    content: {
        set: 'ok'
    }
};
let b_obj = {...a_obj};
a_obj.name = 'aaa';
a_obj.content.set = 'change';
console.log(b_obj);
//name不会改变,但是set会变成change,说明这个是浅复制

对象方法的扩展

//Object.is 相当于===的的功能,判断两个参数之间是否全等,引用类型的仍然不能相等
console.log(Object.is('12', 12));
//输出 false
let obj = {name: 'aaa', age: 12};
let c_obj = {name: 'aaa', age: 12};
console.log(Object.is(obj, c_obj));
//输出 false
//两者之间的差别在于+0与-0之间,NaN之间
console.log(+0 === -0, Object.is(+0, -0));
//前者输出true,后者输出false
console.log(Number('no') === Number('yes'), Object.is(Number('no'), Number('yes')));
//前者输出false,后者输出true

//Object.assign 相当于扩展运算符的功能,合并或者复制的对象之间是浅复制
let obj1 = {name: 'aaa', like: {lan: 'english'}};
let obj2 = {age: 30, like: {sport: 'football'}};
console.log(Object.assign(obj1, obj2));
//同类项后者会覆盖前者的对象

//Object.keys 与 Object.values 前者返回的是对象的keys,后者返回的是对象的values,并且返回的都是数组形式
let person = {
    name: 'aaa',
    age: 30,
    sex: 'man'
};
console.log(Object.keys(person), Object.values(person));
//输出 ["name", "age", "sex"]  ["aaa", 30, "man"]

//Object.entries(obj)表示把指定的obj进行逐项拆解,并且里面的key,value成为每个数组的项如下例子,
console.log(Object.entries(person));
//输出 (3) [["name", "aaa"], ["age", 30],["sex", "man"]]

//__proto__与 Object.getPrototypeOf(obj)一样,是获取对象的原型
console.log(Object.is(person.__proto__, Object.getPrototypeOf(person)));
//输出 true

//扩展Object.create(obj)表示新建一个以obj为原型的对象
console.log(Object.create(person));
//输出一个以person为原型的空对象

//Object.setPrototypeOf(obj,原型对象)
console.log(Object.setPrototypeOf(obj, person));
//把obj的原型改成person

//super,调用原型属性或者方法,注意:只有在ES6数组里的新的函数表示法里面才能使用super,其他方式不能调用
let n_obj = {
    say() {
        console.log(`my name is ${super.name}`);
    }
};
Object.setPrototypeOf(n_obj, obj);
n_obj.say();
//输出 my name is aaa

 数组的扩展

//可以通过扩展运算符传参
let arr = ['小明', 20, ['男', '瘦'], '是个幽默的人'];
let test = (...rest) => {
    console.log(rest);
};
test(...arr);
//通过扩展运算符进行合并数组,但是也只是浅复制
let n_arr = [...arr];
arr[2][0] = 'ok';
console.log(n_arr);

//通过新对象set对数组进行去重
let a_arr = [1, 2, 3, 3, 3, 36, 8];
let b_arr = new Set(a_arr);
console.log(b_arr);
//输出 Set(5) {1, 2, 3, 36, 8}
let c_arr = [...b_arr];
console.log(c_arr);
//输出 [1, 2, 3, 36, 8]

//添加项
b_arr.add('ok');
//删除项
b_arr.delete(1);
//清除所有内容
// b_arr.clear();
//进行遍历set对象
b_arr.forEach(function () {
    // console.log(arguments);
});
for (let val of b_arr) {
    // console.log(val);
}
// console.log(b_arr.entries());   这个方法是输出下标与值
//判断是否有指定项
console.log(b_arr.has(3));
//获取所有的键名
console.log(b_arr.keys());
//获取所有的键值
console.log(b_arr.values());

 数组函数扩展学习

//Array.from(obj,fn)  作用是把类数组转变成数组,注意:类数组里面要有length这个属性
//obj是表示目标类数组,fn表示回调,并且把回调返回的值作为数组的值
let obj = {
    0: 'name',
    1: 'age',
    2: 'sex',
    length: 3
};
let a_obj = Array.from(obj, item => item + 'ok');
console.log(a_obj);
//输出 ["nameok", "ageok", "sexok"]

//Array.of 把里面的参数合成一个数组
let b_obj = Array.of('are', 'you', 'ok');
console.log(b_obj);
//输出 ["are", "you", "ok"]

//fill 是表示给数组填充默认值
let c_obj = new Array(5).fill('ok');
console.log(c_obj);
//输出 ["ok", "ok", "ok", "ok", "ok"]

//includes 表示数组是否包含指定项
console.log(a_obj.includes('nameok'));
//输出 true

//keys,values 表示数组的下标和值,entries是获取数组的下标和值
for (let [k, v] of a_obj) {
    console.log(k, v);
}
console.log(a_obj.entries());
//输出 Array Iterator {},要去循环才能获得到值

//find,findIndex 根据条件回调,按顺序遍历数组,当回调返回true时,就返回当前遍历到的值,而findIndex是返回当前遍历到的下标
let sign = [1, 3, 5, 8, 9].find((value, index, arr) => value % 2 === 0);
console.log(sign);
//输出 8
let signIndex = [1, 3, 5, 8, 9].findIndex((value, index, arr) => value % 2 === 0);
console.log(signIndex);
//输出 3
原文地址:https://www.cnblogs.com/rickyctbu/p/10038284.html