JavaScript-ECMAScript6
ES6 简介
- ECMAScript 6简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
1.变量
1.1 var 关键字
- 存在变量提升
<body>
<script>
// 变量提升:var
console.log(num1) //undefined
var num1 = 6;
var num1 = 9;
console.log(num1) //9
// 相当于执行了一下的代码顺序
/* 1.var num1;
2.console.log(num1)
3.num1=6;
4.num1=9 */
</script>
</body>
-
允许重复声明变量
-
允许重复赋值
-
var 关键字属于全局作用域
<body>
<script>
var arr = []
for (var i = 0; i < 2; i++) {
arr[i] = function() {
console.log(i)
}
}
arr[0](); //2
arr[1](); //2
</script>
</body>
1.2 let 关键字
- let 声明的变量只在所处于的块级作用域之内有效
- 不存在变量提升
<body>
<script>
//正确格式
let num = 6;
console.log(num);
//错误格式
console.log(num2)
let num2 = 2;//报错
let num2 = 222; //报错 重复赋值
</script>
</body>
- 不允许重复声明变量
- 不允许重复赋值
- let关键字暂时性死区——块级作用域
<body>
<script>
//let关键字暂时性死区 在块级作用域之内使用let关键字声明了变量,那么块级作用域内与外部没有关系
//块级作用域内,如果没有let关键字声明的变量,那么这个块级作用域受外界的影响
var num1 = 30;
if (true) {
console.log(num1); //30
}
//如果作用域之外的关键字和作用域之内的不同,而且作用域内的和之外的等同,那么还会受影响
var aaa = 100;
if (true) {
let num2 = 20;
console.log(aaa); //100
}
//块级作用域内如果有let声明的关键字,那么就不会受外界的影响(块级作用域之外的关键字和作用域之内相等的情况下)
var num2 = 10;
if (true) {
let num2 = 20;
console.log(num2); //20
}
var nu3 = 10;
if (true) {
console.log(num3); //报错 不会受作用域之外的影响
let num3 = 20;
}
</script>
</body>
1.3 const 关键字
- 必须赋初始值,赋值后不能修改
- 不允许重复声明
- 具有块级作用域
- 标识符一般要大写
- 定义对象类型用 const, 非定义对象类型用 let
<script>
var PI = 3.14; //PI是常量
PI = 3.1415926; //常量本身不能给他重新赋值,但是此处不会报错
var name = "zhangsan"; //name是变量
const myPi = 3.14;
//myPi = 3.1415963; //报错,此处常量不能重新赋值
//const myAge; //报错 因为没有赋初始值
// 定义对象类型用 const
const stu = {
nam: 'zhangsan',
age: 20
}
stu.nam = "王五" //没有改变stu的唯一标识,所以不会报错(const针对的是stu整体,具体内容不会影响)
console.log(stu.nam) //王五
//stu = {} //给stu重新赋值,则会报错
// 非定义对象类型用 let
let six="男"
</script>
1.4 var let const 三者有什么区别
- 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
- 使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
- 使用 const 声明的常量,在后面出现的代码中不能修改该常量的值
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可更改 | 值可更改 | 值不可更改 |
2. 解构赋值
解构赋值:把数组或对象里面的数据拿出来赋值给对应位置上
- 数组解构赋值
数组解构允许我们按照一一对应的关系从数组中提取值,然后将值重新赋给变量
<body>
<script>
//数组解构允许我们按照一一对应的关系从数组中提取值,然后将值重新赋给变量
//1.变量的数量和数组的长度相等,则意义对应
let arr = [1, 2, 3]
let [a, b, c] = arr
console.log([a, b, c]) //[1, 2, 3]
//2.变量的数量和数组的长度不相等的情况下
//数组长度>变量的数量时,从前往后以此赋值
let arr2 = [3, 5, 6]
let [e, d] = arr2
console.log([e, d]) //[3, 5]
let arr4 = [2, 3, 4]
let [w, , r] = arr4
console.log([w, , r]) // [2, 空白, 4]
//数组长队<变量个数的时候,从前往后依次赋值,不够的就用undefined定义
let arr3 = [5, 8, 4, 9]
let [z, x, v, n, s, h] = arr3
console.log([z, x, v, n, s, h]) //[5, 8, 4, 9, undefined, undefined]
</script>
</body>
- 对象解构赋值 key:value
对象解构允许我们按照一一对应的关系从数组中提取值,然后将值重新赋给变量
<body>
<script>
// 1.对象属性名和变量的属性名一样
//对象解构:允许我们使用变量的名字匹配对象的属性,匹配成功将对象属性的值赋给变量
let person = {
name: '张三',
sex: '男',
age: '20'
}
let stu = {
name,
sex,
age
} = person
//打印
console.log(stu) //{name: '张三', sex: '男', age: '20'}
//2.对象的属性值和变量的属性值不一样的时候
let worker = {
name: '李四',
age: 30,
sex: '男'
}
let teacher = {
sex,
name: myName
} = worker
console.log(teacher) //{name: '李四', age: 30, sex: '男'}
//3.指定对象内的某个数据进行赋值 比如指定name
const obj = {
name: 'zahngsan',
age: 20
}
const {
name: res
} = obj;
console.log(res) //zhangsan
//4.key:value数量上 结构对象<赋值对象 bc没有对应的值,那就是undefined咯
const {
ac,
bc
} = {
ac: 6
}
console.log(ac) //6
console.log(bc) //undefined
</script>
</body>
3. rest(…)运算符
3.1 剩余参数
- 函数剩余参数
- 参数默认值
- 不定参数(只能放在最后且只有一个)
<body>
<script>
//剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
//...AA:表示把剩下的参数全部取过来,以数组的形式包装
function sum(first, ...args) {
console.log(first); // 10
console.log(args); // [20, 30]
}
sum(10, 20, 30);
//实参和形参一一对应
function add(x, y) {
return x + y;
}
console.log(add(1, 2)); //3
//形参有默认值且实参<形参/实参>形参
function add(a, b = 6) {
return a + b;
}
console.log(add(1)); //7
console.log(add(1,3)); //4 相当于b被重新赋值,原来的值被替换
// ...z是一个不定参数,必须放在最后,有且仅有一个
function add(x, y = 6, ...z) {
return x + y;
}
console.log(add(1)); //7
console.log(add(1,2)); //3 y被重新赋值
console.log(add(1, 2, 3)); //3 y被重新赋值
//实参<形参
function a(w,x){
return w+x;
}
console.log(a(1))//NaN 非数字型数据类型 Not a Number
console.log(a(1,2,3))//3
</script>
</body>
- 数组剩余参数+解构赋值
<body>
<script>
//剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
//...AA:表示把剩下的参数全部取过来,以数组的形式包装
function sum(first, ...args) {
console.log(first); // 10
console.log(args); // [20, 30]
}
sum(10, 20, 30);
//剩余参数和解构配合使用
let arry = ['张三', '李四', '王五']
let [a, ...b] = arry;
console.log(a) //张三
console.log(b) //['李四', '王五'] 数组Array
</script>
</body>
3.2 数组对象展开
<body>
<div></div>
<div></div>
<div></div>
<script>
//DOM对象
//querySelectorAll和querySelector获取的是真数组
const arr4 = document.querySelectorAll('div') //获取的是真数组
console.log(...arr4);
//getElementsByTagName获取的是伪数组 伪数组不具有数组的方法:例如push foreach等等
var arr5 = document.getElementsByTagName('div') //获取的是伪数组
var arr7 = Array.from(arr5); //伪数组转真数组
console.log(...arr7)
//对象
const stu = {
name: "zhangsan",
age: 30
}
const stu2 = {
...stu,
sex: "男"
};
console.log(stu2);
</script>
<script>
//数组
//把数组拆分以逗号分隔的数组序列,控制台输出的时候逗号被解析
//展开数组
const arr = [1, 2, 3];
console.log(...arr); //1 2 3
const arr1 = [4, 5, 6];
//合并数组
const arr3 = [...arr, ...arr1];
console.log(...arr3) //1 2 3 4 5 6
</script>
</body>
4. 数组的扩展方法
4.1 Array.from()
4.2 find()
5. 箭头函数
5.1 箭头函数的使用
-
箭头函数就是函数的简写方式
语法:参数=>函数体
使用场景:回调函数 -
参数:
1.没有参数或者多个参数时
没有参数时:()=>{}
有参数时:(x,y)=>{}
2.只有一个参数时,()可以省略
<body>
<script>
/* 参数
1.没有参数或者多个参数时
a.没有参数时:()=>{}
b.有多个参数时:(x,y)=>{}
c.只有一个参数的时候,()可以省略 x=>{}
*/
// 1.没有参数或者多个参数时
//a.没有参数时候:()=>{}
const fn1 = function() {
console.log('aaaaa');
}
fn1();
//转化成箭头函数
const fn11 = () => {
console.log('aaaaa')
}
fn11();
//b.有多个参数时:(x,y)=>{}
function fn2(x, y) {
let m = x + y;
console.log(m) //3
}
fn2(1, 1);
//转化成箭头函数
const fn21 = (x, y) => {
let m = x + y;
console.log(m); //3
}
fn21(1, 2)
//2.只有一个参数时,()可以省略
const arr = [2, 5, 6, 5];
arr.forEach(function(val) {
console.log(val);
})
//转成箭头函数
const arr2 = [2, 5, 6, 5];
arr2.forEach(val => console.log(val));//function()只有一个参数时,()可以省略
</script>
</body>
- 函数体
1.有多条语句时,要用{}括起来
2.(x)={ 语句1; 语句2;}
3.只有一条语句时,且需要返回结果时,那么大括号{},return也可以省略,结果会自动返回
<body>
<script>
//1.有多条语句时,要用{}括起来
let fn23 = function() {
console.log('nihao');
console.log(23232);
}
fn23();
//转换成箭头函数
let fn22 = () => {
console.log('nihao');
console.log(23232);
}
fn22();
//2.只有一条语句时,且需要返回结果时,那么大括号{},return也可以省略,结果会自动返回
let f1 = function(x, y) {
return x + y;
}
console.log(f1(3, 3));
//转换成箭头函数
let f11 = (x, y) => x + y;
console.log(f11(2, 3)) //5
</script>
</body>
5.2 箭头函数不适用的场景
- 解释原因:因为箭头函数中,没有this指向,默认指向window
- 对象的方法 在添加事件的时候也是属于对象的方法,不能使用箭头函数
<body>
<script>
//箭头函数不适合使用的场景
//1.对象的方法 在添加事件的时候也是属于对象的方法,不能使用箭头函数
let stu = {
name: "张三",
study: function() {
console.log(this.name + ",好好学习"); //张三好好学习
}
}
stu.study();
//箭头函数
study: () => {
console.log(this); //this 指向window 不是指向study这个当前对象,自然就访问不到name
console.log(this.name + ",好好学习"); //好好学习 访问不到name
}
}
stu.study();
</script>
</body>
- 构造函数
构造函数里面的this都是有特定指向的,所以不能使用箭头函数
<body>
<script>
//2.构造函数
function Student(name) {
this.name = name;
this.study = function() {
console.log(this.name + ",好好学习");
}
}
let stu2 = new Student("李四");
stu2.study();
</script>
</body>
- 添加事件,监听事件等等(DOM\jQuery中)
因为有特定的this指向,所以不能使用箭头函数
<body>
<script>
var btn = document.querySelector("button");
//原函数
btn.addEventListener('click', function() {
console.log(222);
})
//转化为箭头函数
/* btn.addEventListener("click", () => {
console.log("abc"); //abc
console.log(this); //window
}) */
</script>
</body>
5.3 函数内部的this指向问题
- 这些this 的指向,是当我们调用函数的时候确定的。调用方式的不同决定了this 的指向不同一般指向我们的调用者
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法指向实例对象 |
对象方法调用 | 改方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
<body>
<button>点击</button>
<script>
//函数的不同调用方式决定了this的指向不同
// 1. 普通函数 this指向 window
function fn() {
console.log(this) //window
}
fn()
// 2. 对象的方法 this 指向的是对象 obj
var obj = {
sayHi: function() {
console.log(this)
}
}
obj.sayHi()
// 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是ldh这个实例对象
function Star() {
this.sing = function() {
console.log(this); //Star
}
}
var ldh = new Star();
ldh.sing();
// 4. 绑定事件函数 this 指向的是函数的调用者 btn
var btn = document.querySelector('button')
btn.addEventListener('click', function() {
this.style.backgroundColor = 'red'
console.log(this) //点击的button
})
// 5. 定时器里面的 this 指向的是也是window
window.setTimeout(function() {
console.log(this) //window
}, 1000);
// 6. 立即执行函数
(function() {
console.log(this) //window
})();
</script>
</body>
5.4 改变this指向
- call方法可以改变this的指向
- call()作用:调用 呼唤
调用函数
改变函数内的this指向 - 参数:
call(参数1,参数2,参数3…)
1.参数1:函数运行时内的this 指向的另一个函数的对象名
2.参数2,参数3… - 返回值:就是函数的返回值
<body>
<script>
// 1. call()
//作用 调用函数和改变this指向
var o = {
name: 'andy'
}
function fn() {
console.log(this) //原来指向的是window,call之后指向的是name
}
fn.call(o, 1, 2);
//call的主要作用可以实现继承
function Father(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
}
function Son(uname, age, sex) {
Father.call(this, uname, age, sex);
}
var son = new Son('刘德华', 18, '男')
console.log(son) //Son {name: '刘德华', age: 18, sex: '男'}
</script>
</body>
6. 对象简写
- 当key和value相等的时候,可以合并写
<body>
<script>
let name = "张三";
let age = 20;
const stu1 = {
name: name,
age: age,
study1: function() {
console.log(this.name + ",好好学习");
}
}
console.log(stu1.name);
stu1.study1();
//简写形式
const stu2 = {
name,
age,
study2() {
console.log(this.name + ",好好学习");
}
}
console.log(stu2.name);
stu2.study2();
</script>
</body>
7.类
- ES5原生构造函数
<body>
<script>
// ES5构造函数
//构造函数
function Student(name, age) {
//属性
this.name = name;
this.age = age;
//方法
this.study = function() {
console.log(this.name + 'haohao xiexi ') //换成箭头函数的时候此处this指的是window
}
}
//创建实例对象
let s = new Student('zhangsajj', 18)
console.log(s.name);
</script>
</body>
- ES6通过Class类关键字构造函数
<body>
<script>
// ES6通过类关键字构造函数
class Student2 {
//构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
//对象 方法的简写
study() {
console.log(this.name + '你好')
}
}
//创建实例对象
let s2 = new Student2('lisi', 30)
console.log(s2.name);
</script>
</body>
8. 继承
-
原生ES5继承
-
ES6通过类关键字实现类的继承
子类extend父类{
construction(参数1参数2,…){
super(参数)
}
}
<body>
<script>
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat() {
console.log(999999999999);
}
}
class Student extends Person {
//继承属性
constructor(name, age, score) {
//this.name = name;
//this.age = age;
super(name, age); //调用父类的构造属性:继承父
this.score = score;
}
//继承方法行为
menth() {
console.log(2222);
}
eat() {
//自己拥有和父相同的属性的时候,自己的不会被覆盖
console.log(8888888888888);
}
do(){
//super继承父类对的方法
super.do()
}
}
var stu = new Student("zhangsan", 20, 60)
console.log(stu.name);
stu.menth(); //222
stu.eat(); //9999 方法属性都能继承过来 相当于把他所有的内容都继承过来了
// stu.eat();//8888888888 先把父元素的方法调用过来,然后自己对其进行更改(重写)
stu.do()//吃吃吃
</script>
</body>
9. 静态属性
- 静态属性只能通过构造函数来访问
- 非静态属性通过实例对象访问
<body>
<script>
// ES5写法
function Student(name, age) {
this.name = name;//非静态属性
this.age = age;//非静态属性
this.study = function() {
console.log('先好好学习');
}
}
let stu1 = new Student('ddd', 60)
Student.score = 90; //静态属性
console.log(stu1.score) //undefined
console.log(Student.score) //90 输出静态属性值的方式
//改成ES6写法
class Student2 {
static score = 100; //静态属性
constructor(name, age) {
this.name = name;
this.age = age;
}
study() {
console.log('先好好学习');
}
}
let stu = new Student2('ZHANGDAN', 60)
console.log(stu.name) //ZHANGDAN
console.log(stu.score) //undefined
console.log(Student2.score) //100
stu.study(); //先好好学习
</script>
</body>
10. 模板字符串
- 传统的 JavaScript 语言,输出模板通常是这样写的
<body>
<script>
let name = '张三';
let str = 'my name is' + name;
console.log(str)
</script>
</body>
- 上面的这种写法相当繁琐不方便,ES6引入了模板字符串解决这个问题
模板字符串:对应字符串的增强,用反引号``
1.可以插入变量和表达式
2.可以调用函数
3.换行和空格都会保留
<body>
<script>
let name = '张三';
let age = 20;
let str = `my name is ${
name}`;//my name is 张三
console.log(str)
</script>
</body>
<body>
<div></div>
<script>
function fn() {
return "男";
}
//保留空格和换行,调用函数,插入变量和表达式
//动态创建表
let html2 = `<table>
<tr>
<td>${
name}</td>
<td>${
age+1}</td >
<td>${
fn()}</td > //调用函数
</tr>
</table>`;
var div = document.querySelector('div')
div.innerHTML = html2;
console.log(html2)
</script>
</body>
11. Set
11.1 Set 数据结构
- Set 数据结构
1.ES6 提供了新的数据结构 Set 它类似于数组 但是存储的值是唯一的(不允许出现重复的值)
2.Set本身是一个构造函数,用来生成 Set 数据结构 语法 const s = new Set
3.Set函数可以接受一个数组作为参数,用来初始化 语法 const set = new Set([1, 2 ,3 ,4 , 5])
<body>
<script>
//声明一个空的set对象实例
//利用size查看set里面有没有值或者有多少值
const s1 = new Set()
console.log(s1.size) //0 空
//给予set实例化一个值
const s2 = new Set([2, 3])
console.log(s2.size) //2
//利用set 进行数组去重 ... 里面放一个数组
var arr = ['a', 'b', 'a', 'b']
var s3 = new Set(arr)
console.log(s3.size) //2 说明set已经过滤了重复的值
//数组去重
let arr2 = [...s3]
console.log(arr2) //['a', 'b']
</script>
</body>
11.2 Set 增|删|改|查|遍历|清空|判断
- Set:存储的值是唯一的(不允许出现重复的值)
1.增:add
2.查:forEach() size
3.判断:has
4.删:delete
5.清空:clear
6.遍历:foreach
<body>
<script>
var set = new Set()
// 1.增
set.add('zhangsan').add(2).add('lisi') //链式添加
set.add('你好')
set.add([3, 4, 8, 9])
console.log(set) //{'zhangsan', 2, 'lisi', '你好', Array(4)}
//增加重复元素
set.add('zhangsan')
console.log(set) //{'zhangsan', 2, 'lisi', '你好', Array(4)} 不增加重复值
//2.查看set长度
console.log(set.size) //5 表示存储了5 个值
//3.遍历foreach
set.forEach(val => {
console.log(val)
});
//4.删
set.delete('zhangsan')
console.log(set) // {2}
//5. has 判断某个元素是不是set中的元素
//has 有返回值 Boolean值 true|false
console.log(set.has('lisi')) //true
console.log(set.has('zhangsan')) //false 因为上面删除了
//6.clear删除所有的元素
set.clear()
console.log(set.size) //0 说明已清空
</script>
</body>
11.3 数组 <=>Set 相互转换
<body>
<script>
//数组转set 转换并去重
let arr = [1, 2, 4, 4, 5, 6];
var s2 = new Set(arr);
console.log(s2) //Set(5) {1, 2, 4, 5, 6}
//set转数组
let arr2 = [...s2]; //json类似 统一转数组方式‘...’先把原来的对象元素拆分,然后赋值给数组
console.log(arr2) // [1, 2, 4, 5, 6]
//字符串转set
let s3 = new Set("test");//Set(3) {'t', 'e', 's'}
console.log(s3)
</script>
</body>
12.Map
<body>
<script>
let m1 = new Map();
//增加 "key":"value"(类似JSON格式的字符串)
m1.set("name", '张三');
m1.set("age", 50);
//m1.set('name', '李四');
console.log(m1)
//查 get("key") 根据key找value size查看有多少对数据
console.log(m1.get("name")); //张三
// console.log(m1.get('name')) //李四 开始是张三,但是后面被李四覆盖了 因为代码从上往下执行
console.log(m1.size)//2
//删 delet("key")
m1.delete('age')
console.log(m1.age) //undefined 已删除
//清空 clear()
m1.clear();
console.log(m1); //清空
</script>
</body>
13. 遍历
<body>
<script>
//1.遍历数组
let arr = [1, 2, 3, 4];
//for循环+传统遍历方式
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
//foreach+箭头函数遍历
arr.forEach(val => console.log(val));
//2.遍历对象
let stu = {
name: 'zhangsan',
age: 20
}
// console.log(stu.name)
//遍历
for (const key in stu) {
// console.log(key) //属性名
// console.log(stu[key]); //属性值
//console.log(key + ':' + stu[key]) //拼接方式1 传统方式拼接属性名和属性值
console.log(`${
key}:${
stu[key]}`) //拼接方式2 模板字符串拼接属性名和属性值
}
//set、map
//3.set 遍历for of
let arr2 = [1, 2, 3, 4, 5, 6];
var s2 = new Set(arr2);
for (let key of s2) {
//iterator计数器
console.log(key);
}
</script>
</body>
14. Symbol
- 数据类型:
1.基本: string,number,boolean,null,undefined
2.复杂: Object(数组,函数,自定义对象,内置对象)
3.ES6新增数据类型:Symbol 表示独一无二
<body>
<script>
let s1 = Symbol('zhangsan')
let s2 = Symbol('zhangsan')
console.log(typeof(s1, s2)) //symbol
console.log(s1 === s2) //false 因为s1,s2中的数据都是独一无二
let name = Symbol('name')
let stu = {
name: 'zhangsan',
age: 20,
name: 'sss', //替换了zhangsan
[name]: 'lisi', //创建了一个不重复的name
}
console.log(stu);//{name: 'sss', age: 20, Symbol(name): 'lisi'}
</script>
</body>