三阶段课程——Day02(ES6简介、let和const)(数据类型和结构:字符串扩展、Symbol、数组新增方法、对象新增、Set、Map、数组和对象解构、...运算符)
ECMAScript6简介
1、JavaScript遗留问题(ES5之前的一些问题)
弱类型语法造成的程序不可预测性(比如:未声明变量即可使用)
语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
2、为什么使用ES6
es6的语法和新增一些函数,帮我们解决了一些问题,和提升一些开发效率 。
为后面阶段学习框架做准备
3、ECMAScript6历史版本
ES6 实际上是一个泛指,泛指 ES2015 及后续的版本
ES6全称:ES2015年6月份发布的,每年的6月份都会更新一代。
let和const命令
ES6新增了let命令,用来声明变量。
ES6新增了const命令用来声明一个只读的常量。
1、let命令
语法:let 变量名 = 值;
let命令特点:(与var的区别)
- 不存在变量提升与暂时性死区
console.log(a); // undefined var a = 1; console.log(b); // Cannot access 'b' before initialization let b = 1;
- 不能重复声明
var a = 1; var a = 10; console.log(a); // 10 let b = 1; let b = 2; // Identifier 'b' has already been declared
- 块级作用域
if (true) { var a = 10; } console.log(a); // 10 if (true) { let b = 10; } console.log(b); // 报错
- let和循环
// for (var i = 0; i < 3; i++) { } // console.log(i); // 3 // for (let i = 0; i < 3; i++) { // console.log(i); // } // console.log(i); // 报错 var btn = document.getElementsByTagName('button'); for (let i = 0; i < btn.length; i++) { btn[i].onclick = function () { console.log(i); } }
2、const命令
语法:const 常量名 = 常量值;
const特点及建议
遵从let的特点
- 按照规范建议常量名大写
- 声明常量必须赋值
- 一但声明常量,则值是不能改的(指的是内存地址不能修改)
// const ABC = 10; // 声明时必须赋值 // ABC = 20; // 声明完成后不可以修改 const OBJ = { name: 'zs', age: 3 } // OBJ = {}; // 改地址 OBJ.name = 'ls'; // 没有改地址,改的是属性 console.log(OBJ); // {name: "ls", age: 3}
数据类型和数据解构
1、字符串扩展
1.1、模板字符串
字符串的问题:
- 字符串拼接复杂
- 引号嵌套的问题
- 定义字符串时不能换行
语法:
let str = `吃饭,睡觉,打豆豆`;
可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
优点:
可以解析js表达式(变量、字符串拼接、函数调用、三目运算)
${ 简单的js表达式 }
${ age > 7 ? '上幼儿园' : '上小学'}
1.2、新增方法(5个)
- starsWith
语法:字符串.starsWith(参数字符)
描述:参数字符串是否在原字符串的头部,返回布尔值(判断路径)
- endsWith
语法:字符串.endsWith(参数字符)
描述:参数字符串是否在原字符串的尾部 返回布尔值 (判断类型)
- repeat
语法:字符串.repeat(num)
描述:返回一个新字符串,表示将原字符串重复num次
- padStart
语法:字符串.padStart( 目标长度,填充的字符 )
描述:字符串头部补全(如果字符串没有达到这个长度,则在前面添加字符,以达到这个长度)(补0)
- padEnd
语法:字符串.padEnd( 目标长度,填充的字符 )
描述:字符串尾部补全(如果字符串没有达到这个长度,则在尾部添加字符,以达到这个长度)
// 语法:字符串.startsWith( 参数字符 ) // 描述:参数字符串是否在原字符串的头部 返回布尔值 let str = '/demo1/ab.html'; console.log(str.startsWith('/demo')); // true // ----------------------------------- // 语法:字符串.endsWith( 参数字符 ) // 描述:参数字符串是否在原字符串的尾部 返回布尔值 文件类型判断 let str = '/demo/ab/abc.jpg'; console.log(str.endsWith('.jpg')); // true // ------------------------------------ // 语法:字符串.repeat( num ) // 描述:返回一个新字符串,表示将原字符串重复num次 let str = '你爱我'; let s = str.repeat(10); console.log(s); // ----------------------------------- // 语法:字符串.padStart( 目标长度,填充的字符 ) // 描述:字符串头部补全(如果字符串没有达到这个长度,则在前面添加字符,以达到这个长度) let str = 'abc'; let s = str.padStart(10, '*'); // 如果str不够10个字符串,则用*在前面填充 console.log(s); let n = 1; let a = n.toString().padStart(2, '0'); console.log(a); // --------------------------- // 语法:字符串.padEnd( 目标长度,填充的字符 ) // 描述:字符串尾部补全(如果字符串没有达到这个长度,则在尾部添加字符,以达到这个长度) let str = 'abc'; let s = str.padEnd(10, '*'); // 如果str不够10个字符串,则用*在后面填充 console.log(s);
2、Symbol
数据基本类型:Number String Boolean Null Undefined Symbol
数据引用类型:Object
做为了解即可,用途比较少。为了我们后续学习iterator做铺垫。Symbol可以当作对象的键。
ES6 引入了一种新的原始数据类型Symbol
,表示独一无二的值。
它是 JavaScript 语言的第七种数据类型。
Symbol 值通过Symbol()
函数生成。
2.1、基础用法
// 1、基本使用 let sym = Symbol(); console.log(sym); // Symbol() console.log(typeof sym); // 'symbol' // 2、symbol不做任何运算 console.log(sym + 1); // 报错 Cannot convert a Symbol value to a number // 3、独一无二 let sym2 = Symbol(); console.log(sym2); console.log(sym == sym2); // false
2.1、Symbol描述符
// 标识符,就是为了好看,好区分是哪一个symbol let sym3 = Symbol('小张'); // 和上面的Symbol()除了外观有区别,没有任何本质区别 console.log(sym3);
2.3、应用场景
Symbol可以用在对象中,当作键使用。传统的键是使用字符串(一不小心可能会被覆盖)
一般常用于框架、js内置函数和对象中
// 对象的key必须是字符串(对象的key也可以symbol) let sym = Symbol('小张'); let obj = { name: 'zs', age: 3, // sym: '我就是我,不一样的烟火' // sym当做字符串 [sym]: '我就是我,不一样的烟火' // [sym],sym当做变量 }; console.log(obj); console.log(obj[sym]);
function fn() { let sym1 = Symbol('name'); let sym2 = Symbol('age'); return { [sym1]: '小王', [sym2]: 3 } } let v = fn(); console.log(v);
3、数组
es6中对数组一些方法进行了扩展。数组这种数据结构的特点:有序的。
静态方法:声明在构造函数的下面
Array.isArray();
Array.of();
Array.from();
实例方法:声明在数组的原型上
数组.indexOf();
数组.slice();
3.1、新增方法(静态方法)
- Array.of
语法:Array.of(num)
作用:实例化数组,解决new Array()传入数字时的缺陷。
代码案例:
// new Array创建时的缺陷 let arr1 = new Array(3); // 本意想得到这样的 [3] console.log(arr1); // 实际:[empty × 3] // 语法:Array.of( num ) // 作用:实例化数组,解决new Array()传入数字时的缺陷。 let arr2 = Array.of(3); console.log(arr2); // [3]
- Array.from
语法:Array.from( 伪数组 )
作用:把伪数组转换成数组,相对于ES5的写法,更加简洁方便
伪数组:arguments、NodeList、HtmlCollection
代码案例:
function fn() { console.log(arguments); let arr = Array.from(arguments); // 将arguments转成数组 console.log(arr); } fn(1, 2, 3) var btn = document.getElementsByTagName('button'); var btn2 = document.querySelectorAll('button'); // console.log(btn); // console.log(btn2); let arr = Array.from(btn); // console.log(arr); arr.forEach(function (item) { item.onclick = function () { console.log(1); } });
4、对象
对象(object)是 JavaScript 最重要的数据类型。ES6 对它进行了重大升级,包括(数据结构本身的改变和Object对象的新增方法)
特点:对象是无序的
4.1、对象属性简写/函数的简写
代码案例:
let value = 'a'; let len = 18; // let obj = { // "value": value, // "len": len // } let obj = { value, // 如果属性名和属性值同名,可以简写 len, fn: function () { console.log('我是fn'); }, fn1() { // 方法的简写 console.log('我是fn1'); } } console.log(obj); obj.fn() obj.fn1()
4.2、属性名表达式
还是中括号的用法:可以解析表达式(变量、字符串拼接)
代码案例:
let a = 'age'; function fn() { return 'abc' } // 如果是变量做为key值,则加上[],[]可以放变量、拼接、函数调用 let obj = { name: 'zs', [a]: 3, [a + 1]: 12, [fn()]: 456 } console.log(obj);
4.3、新增方法
- Object.assign
语法:Object.assign( target, source1, source2, ... )
描述:对象的合并(拷贝),将源对象(source),复制到目标对象(target),并返回目标对象
代码案例:
let o1 = { name: 'zs' } let o2 = { age: 3 } let o3 = { name: 'ls', sex: '男' } // 1、合并对象 let o = Object.assign({}, o1, o2, o3); console.log(o); // 2、浅拷贝 let ao3 = Object.assign({}, o3); ao3.age = 4; console.log(ao3); console.log(o3);
- Object.keys
语法:Object.keys( object )
描述:返回一个数组,成员是参数对象自身的属性的键名
代码案例:
// 作用:可以将对象像数组一样循环 let arr = Object.keys(o3); console.log(arr); // ["name", "sex"] arr.forEach(function (item) { console.log(item, o3[item]); })
- Object.values
语法:Object.values( object )
描述:返回一个数组,成员是参数对象自身的键值
代码案例:
let arr2 = Object.values(o3);
console.log(arr2);
- JSON.stringify
语法:JSON.stringify( object )
描述:把js对象转换成json字符串
- JSON.parse
语法:JSON.parse( jsonstr)
描述:把json字符串转换成js对象
let arr = ['刘备', '关羽', '张飞']; let str = JSON.stringify(arr); console.log(str); // '["刘备","关羽","张飞"]' let arr2 = JSON.parse(str); console.log(arr2); // ------------------------ // 深克隆,无法识别函数 let obj = { name: 'zs', age: 3, fn: function () { } } let obj2 = JSON.parse(JSON.stringify(obj)); console.log(obj2);
5、Set(了解)
new Set(数组 | 类数组)
代码案例:
// 类似于数组,最大特点是没有重复的值 let s1 = new Set([2, 3, 3, 221, 2, 2, 2, 2]); console.log(s1); // {2, 3, 221}
5.2、常见方法
- size 获取set集合的长度
- add(值) 给集合添加值,返回新set
- delete(值) 删除某个值,返回布尔值,表示是否删除成功
- has(值) 查询这个值是否集合的成员,返回布尔值
- clear() 清空集合,没有返回值
代码案例:
// set.size 长度 console.log(s1.size); // 3 // set.add(值) 添加 s1.add('2'); // set.delete(值) 删除 s1.delete('2') // set.has(值) 是否有某个值,返回布尔值 console.log(s1.has('2')); // false // set.clear() 清空 s1.clear(); console.log(s1);
5.3、应用
数组去重
let arr = [2, 3, 3, 221, 2, 2, 2, 2]; console.log(Array.from(new Set(arr)));
6、Map(了解)
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串。各种类型的值(包括对象)都可以当作键。
对象的键只能是字符串或symbol,而map的键可以是任何数据类型。
本质上Map 是一个构造函数(实例化对象:创建一个map数据结构)。
6.1、基本用法
new Map( [ [key1,value1],[key2,value2],... ] )
6.2、常见方法
- size 获取Map的长度
- set(key,val) 添加一条数据
- get(key) 根据key获取val
- has(lkey) 是否存在key
- delete(key) 删除某条数据
- clear() 清空所有数据
代码案例:
// 对象:key值是字符串或者symbol // map:key值可以是任何数据类型 // new Map( [ [key1,value1], [key2,value2], ... ] ) var btn = document.querySelector('button'); // 对象的问题:如果key是除字符串和symbol以外的值,则会转成字符串 // var obj = { // [btn]: 123 // } // console.log(obj); // console.log(btn.toString()); // -------------------------------------- let m1 = new Map([ [1, 'abc'], [null, '小王'], [btn, '小李'], ['name', '小张'] ]) // console.log(m1); // ---------------------------------- // map.size 长度 console.log(m1.size); // map.set(key, value) 设置 m1.set('age', 3); // map.get(key) 取对应的值 console.log(m1.get(btn)); // map.has(key) 是否有某个值 console.log(m1.has('name')); // map.delete(key) 删除某一个 m1.delete('name'); // map.clear() 清空所有 m1.clear(); console.log(m1);
7、解构赋值
7.1、概念及意义
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
从而更加方便地从数组或对象中取值。分为数组解构和对象解构。
7.2、数组解构
语法:
let [ 变量1,变量2,... ] = [ value1,value2,... ]
7.2.1、完全解构(掌握)
代码案例:前面和后面一样式
let [a, b, c] = ['刘备', '关羽', '张飞'];
console.log(a, b, c);
7.2.2、不完全解构
代码案例:前面比后面少
let [a, b] = ['刘备', '关羽', '张飞'];
console.log(a, b);
7.2.3、解构失败
代码案例:前面多,后面少
let [a, b, c, d] = ['刘备', '关羽', '张飞'];
console.log(a, b, c, d);
7.2.4、解构默认值
没有值为其变量赋值,或者赋的值为undefined,默认值才生效
代码案例:
let arr = ['刘备', '关羽', '张飞', null]; let [a, b, c, d = '小张'] = arr; // 当d对应的值如果是undefined,则会用上默认值 console.log(a, b, c, d);
7.2.5、缺省(掌握)
let [, b, c] = ['刘备', '关羽', '张飞']; console.log(b, c); // 关羽 张飞
7.2.6、数组解构应用(数据交换)
let a = 1; let b = 2; [b, a] = [a, b];
7.3、对象解构
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,而对象的属性没有次序。只和键名有关
语法:
完整语法 let { key2:变量名2,key1:变量名1 } = { key1:value1,key2:value2,... } 作用:把key2属性中的值赋值给变量名2 ,把key1属性中的值赋值给变量名1 简写语法: let { key2, key1 } = { key1:value1, key2:value2,... } 简写代表把同名属性的值给了一个和属性名相同的变量(我们就不用再思考起变量名)
let obj = { name: 'zs', age: 3, sex: '男' }
7.3.1、完整语法
代码案例:
let { name: userName, age: userAge, sex: userSex } = obj;
console.log(userName, userAge, userSex);
7.3.2、简写语法解构(推荐)
代码案例:
let { name, age, sex } = obj;
console.log(name, age, sex);
7.3.3、解构失败
代码案例:当没有对应的值的时候,就是解构失败
let { age, fn } = obj; console.log(age); console.log(fn); // undefined
7.3.4、解构默认值(重点)
代码案例:当值对应的是undefined时,就可以使用默认值
let { age, fn = '小二' } = obj;
console.log(age);
console.log(fn);
7.3.5、使用场景
代码案例1:从事件中解构鼠标位置等信息
document.onclick = function (ev) { // console.log(ev); // let disX = ev.clientX; // 原来的方法 let { clientX, clientY } = ev; // 从对象里面解构 console.log(clientX, clientY); }
代码案例2:优化函数传参
原来函数需要传很多个参数,还要注意顺序,我们可以改成只传一个对象,然后在形参那里解构接收
// 原来的方法 function fn(a, b, c, d) {} fn(1, 2, 3, 4) // 解构 function fn({ a, b, c, d }) { console.log(a, b, c, d); } fn({ b: 2, c: 3, a: 1, d: 4 })
8、...运算符
8.1、rest参数
接收剩余参数(如果没有定义形参,则接收所有参数),以数组形式接收,...rest参数必须放在最后,为了替代arguments。
// 之前的做法 function fn() { console.log(arguments); } fn(1, 2, 3, 4); // 接收全部参数 function fn(...rest) { console.log(rest); // [1,2,3,4] 返回一个数组,替代arguments } fn(1, 2, 3, 4); // 接收剩余的参数 function fn(a, ...rest) { // rest参数一定要写在参数形表的最后 console.log(rest); // [2,3,4] 接收没有被匹配上的实参 } fn(1, 2, 3, 4);
8.2、spread参数
rest参数的逆运算。
当作实参进行传递(展开数组的数据),展开数组展开对象(可用于浅拷贝、数组合并、伪数组转数组)
- 当做实参进行传递(展开数组的数据)
- 实现数组、对象浅拷贝
- 数组合并
- 伪数组转数组
function fn(a, b, c, d) { console.log(a, b, c, d); } fn(1, 2, 3, 4); // 正常传参 var arr = [5, 6, 7, 8]; fn(...arr); // 拆分之后传参 // 案例:找数组的最大值 var arr = [3, 32, 2, 424, 32, 324]; console.log(Math.max.apply(Math, arr)); // 原来的做法 console.log(Math.max(...arr)); // ---------------------------------- // 实现数组、对象浅拷贝 let arr = [5, 6, 7, 8]; let arr1 = [...arr]; // 数组浅拷贝 console.log(arr1); let obj = { name: 'zs', age: 3 } let obj2 = { ...obj }; // 对象浅拷贝 console.log(obj2); // ---------------------- // 数组合并 var arr1 = [5, 6, 7, 8]; var arr2 = ['刘备', '关羽', '张飞']; let arr = [].concat(arr1, arr2); // 原来的做法 console.log(arr); let arr = [...arr1, ...arr2]; console.log(arr); // ----------------------------- // 伪数组转数组 var btn = document.getElementsByTagName('button'); var arr = [...btn] console.log(arr);
案例:每个人薪水加2000
let persons = [ { username:'张飞', sex:'男', salary:50000 }, { username:'关羽', sex:'男', salary:60000 } ]