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('\uD83D\uDC2A')); // true console.log(/^\uD83D/u.test('\uD83D\uDC2A'));// 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