一、...运算符【重点】
1.1 扩展运算符(spread)
1、扩展运算符的语法: ...
2、扩展运算符的功能: 展开数据、收集数据
1.1.1函数传参
<script> //收集数据 //function demo(x, y, z) { function demo(...y) { //收集数据 console.log(y, arguments); // fn(y[0],y[1],y[2]); fn(...y); //展开数据 } function fn(m, n, z) { console.log(m, n, z); } demo(2, 8, 9); </script>
1.1.2实现浅拷贝
<script> let arr = [1, 2, 3, 6, { "a": 11, "b": 99 }]; let arr2 = [8, 9, ...arr]; //展开数据(浅拷贝) arr2[6].b = 100; console.log(arr2, arr, 66666); </script>
1.1.3数组合并/伪数组转数组
<script> let arr = [1, 2, 3, 6, { "a": 11, "b": 99 }]; let arr2 = [8, 9, ...arr]; //展开数据(浅拷贝) arr2[6].b = 100; console.log(arr2, arr, 66666); //应用: let [s, p, ...t] = [5, 6, 8, 9]; console.log(s, p, t); let str = "yesok"; // let arr3 = [str]; let arr3 = [...str]; console.log(arr3); </script>
1.1.4展开对象小技巧( 加薪优化 )
<script> let obj = { "x": 11, "y": 99 }; let obj2 = { fn: function() { console.log('fn方法'); } }; let obj3 = { "data": {...obj }, "method": {...obj2 } }; console.log(obj3); </script>
1.2 rest参数(剩余参数)
代码案例:
<script> //rest参数(剩余参数): function test(x, ...y) { console.log(x, y); } test(1, 3, 9); </script>
二、函数扩展
2.1 箭头函数基础用法【重点】
1、箭头函数的语法: (形参1,形参2...)=>{函数体}
2、箭头函数的作用:箭头函数一般用于回调函数,而回调函数通常是匿名函数。
3、箭头函数的特点:【重点】
1)、箭头函数不同于一般函数:
(1)、一般函数可以先调用后定义,而箭头函数只能先定义后调用;
(2)、一般函数有arguments,而箭头函数没有arguments,但可以使用rest参数(剩余参数);
(3)、一般函数可以当作构造函数,而箭头函数不能当作构造函数,因为箭头函数没有自己的this;
<script> demo(3, 8, 9); function demo() { console.log(arguments, 'demo....'); } let obj = new demo(); // fn(); //而箭头函数只能先定义后调用 let fn = (...y) => { console.log(y); //箭头函数没有arguments // console.log(arguments); //arguments is not defined console.log('fn'); } fn(4, 5, 6); //箭头函数不能当作构造函数 // new fn(); // fn is not a constructor </script>
2)、箭头函数的简写形式:
(1)、箭头函数只有一个形参时可以省略圆括号;
(2)、当箭头函数只有一条语句并且该语句会作为返回值返回时,可以省略花括号及return关键词;
<script> // let test = (x) => { // let test = x => { // console.log(x, 11111); // } // let test = x => { // return x * 3; // } let test = x => x * 3; let y = test(66); console.log(y); </script>
3)、箭头函数中的this指向依赖外层函数中的this指向,箭头函数中的this指向不绑定当前调用者;
<script> function test() { // console.log(this, 111); setTimeout(function() { console.log(this, 22); }, 2000); setTimeout(() => { console.log(this, 333); }, 3000); } // test(); // window window // new test(); // window {} var brand = "联想"; let obj = { "brand": "华为", fn: function() { // console.log(this, 1111); setTimeout(function() { console.log(this.brand, 222); }, 2000); setTimeout(() => { console.log(this.brand, 333); }, 3000); } }; // obj.fn(); //联想 华为 var goods = '苹果'; let obj2 = { "goods": "梨", fn: () => { console.log(this, 11); setTimeout(function() { console.log(this.goods, 222); }, 2000); setTimeout(() => { console.log(this.goods, 333); }, 3000); } }; // obj2.fn(); //苹果 苹果 let test2 = () => { setTimeout(() => { console.log(this, 111); }, 2000); } // test2(); //window // test2.call(new Object); //window function test3() { console.log(this, 111); setTimeout(() => { console.log(this, 222); }, 3000); } test3.call(new Object); // {} </script>
2.3 箭头函数的不适用的场景
1、对象中的方法不能使用箭头函数;
2、给DOM绑定事件时不能使用箭头函数;
<body> <button>按钮1</button> <script> let btns = document.getElementsByTagName('button'); // btns[0].addEventListener('click', function() { // console.log(this, 666); // }); btns[0].addEventListener('click', () => { console.log(this, 666); }); //对象中的方法不能使用箭头函数 let obj = { "usr": "李四", fn: () => { console.log(this.usr); } } obj.fn(); // undefined </script> </body>
2.4 函数形参默认值
注意:设置了默认值的形参要放在所有形参的最右边
<script> // jsq(3, 9, '*'); console.log(jsq(3, 9)); //定义函数:实现计算器功能 // function jsq(m, flg = '+', n) { //**注意:设置了默认值的形参要放在所有形参的最右边** function jsq(m, n, flg = '+') { let total = 0; switch (flg) { case '+': total = m + n; break; case '-': total = m - n; break; case '*': total = m * n; break; case '/': total = m / n; break; } return total; } </script>
三、类class
3.1 面向对象编程
3.1.1 概念
面向对象是一种以对象为中心的编程思想。面向对象是相对于面向过程来讲的,面向对象把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模。
3.1.1.1 面向过程
面向过程思想强调的是步骤,当碰见问题时,思考的是“我该怎么做”,分析出解决问题所需要的步骤,一步步的去实现。 例如:想吃蛋炒饭(面向过程方式来实现:相当于自己亲自做饭),首先想到的是我要如何做,包括哪些步骤。比如:起锅烧油,加入鸡蛋,加入米饭,加入调料,翻炒,装盘等。
3.1.1.2 面向对象
面向对象思想强调的是对象,当碰见问题时,思考的是“我该让谁来做”。这个“谁”其实就是对象。找合适的对象做合适的事情。而对象如何去做(采用什么样的步骤)我们就不关心了,最终把问题解决掉就可以了。
例如:还是想吃蛋炒饭(面向对象方式来实现:相当于点外卖),首先想到的是让谁来帮我做蛋炒饭,比如找厨师来帮我做蛋炒饭。具体厨师如何去做这个蛋炒饭,做饭的步骤是怎么样的我们并不关心。只要最终把蛋炒饭做好就可以了。
在实现面向对象方式编程时不同的编程语言采用的方式是不一样的,比如:像java、php、python等采用"类"的方式来现实现,而javascript采用构造函数方式来实现。
3.1.2 类与对象【重点】
什么是类?
类是具有相同属性和方法的一类事务的集合。比如:人类、电脑等;
什么是对象?
对象是类中某一个具体的个体。比如:张三这个人、我的电脑等;
3.2 class的基本使用
class(类)的语法:
class 类名{
//属性
//方法
}
代码示例:
<script> //定义类:人类 class People { //属性 //注意:定义属性时前面不用带let/var xingming; //姓名 age; //年龄 email; //邮箱 //方法 //注意:定义方法时前面不用带function eat() { console.log(`${this.xingming} ${this.age} ${this.email}正在吃饭`); } work() { console.log(`${this.xingming} ${this.email}正在工作...`); } } //实例化类: let zhangsan = new People(); zhangsan.xingming = '张三'; zhangsan.age = 20; zhangsan.email = 'zhangsan@qq.com'; zhangsan.eat(); zhangsan.work(); let lisi = new People(); lisi.xingming = '李四'; lisi.age = 21; lisi.email = 'lisi@qq.com'; lisi.eat(); </script>
对比ES5和ES6实现对象/类:
代码案例:
3.2.1 构造函数方式定义属性【重点】
<script> //定义类:人类 class People { //属性 // xingming; // age; // email; //方法 //注意:构造方法在类实例化时会自动被调用,通常用来初始化 constructor(xm, ages, emails) { //console.log('Hello WEB'); this.xingming = xm; this.age = ages; this.email = emails; } eat() { console.log(`姓名:${this.xingming} 年龄:${this.age} 邮箱:${this.email} 正在吃饭`); } work() { console.log(`${this.xingming} ${this.email} 正在工作。。。`); } } let lisi = new People('李四', 19, 'lisi@sohu.com'); // console.log(lisi.xingming); lisi.eat(); lisi.work(); let zhangsan = new People('张三', 20, 'zhangsan@qq.com'); zhangsan.eat(); zhangsan.work(); </script>
3.3 成员属性和成员方法【重点】
在实例化类时会把类中基本的属性和方法拷贝一份到对象上,每个对象都具有类中基本的属性和方法,这些基本属性和方法称为成员属性和方法,成员属性和成员方法归对象所有。
3.4 静态属性和静态方法【重点】
静态属性和静态方法归类所有,全局只有一份,在类的内部要通过静态方法来访问静态属性,而静态方法则要通过类名来直接访问。
代码示例:
<script> //定义类:人类 class People { //属性 // xingming; // age; // email; //静态属性 static ptype = '人类'; //类的名称 //方法 //注意:构造方法在类实例化时会自动被调用,通常用来初始化 constructor(xm, ages, emails) { //console.log('Hello WEB'); this.xingming = xm; this.age = ages; this.email = emails; } //静态方法 static getType() { console.log(`类名称为:${this.ptype}`); } //成员方法 eat() { //注意:成员方法中不能访问静态属性 // console.log(`类名称为:${this.ptype}`); console.log(`姓名:${this.xingming} 年龄:${this.age} 邮箱:${this.email} 正在吃饭`); } work() { console.log(`${this.xingming} ${this.email} 正在工作。。。`); } } //注意:静态方法可以通常类名称来直接调用 People.getType(); console.log(People.ptype); let lisi = new People('李四', 19, 'lisi@sohu.com'); // lisi.getType(); //lisi.getType is not a function // console.log(lisi.xingming); lisi.eat(); lisi.work(); let zhangsan = new People('张三', 20, 'zhangsan@qq.com'); zhangsan.eat(); zhangsan.work(); </script>
静态属性和静态方法的应用:
<script> class News { static ntypes = ['军事', '体育', '社会', '娱乐']; static creatOption() { let arr = this.ntypes; let opt = ''; for (let i = 0; i < arr.length; i++) { opt += `<option value="${arr[i]}">${arr[i]}</option>`; } document.write(`<select>${opt}</select>`); } } News.creatOption(); </script>
3.5 继承
Class 可以通过extends
关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
为什么要使用类的继承?
通过类的继承可以把公共的属性和方法快速继承下来而不需要重复定义这些公共的属性和方法,提高开发效率及代码的重用度。
类的继承要注意的事项:【重点】
1)、如果子类没有定义构造方法则默认使用父类的构造方法,若子类中定义了构造方法则使用子类自己的构造方法;
2)、如果子类中定义了构造方法则要先调用super()方法,super()方法可以把父类中的this继承下来的同时也可以给父类中的属性设置属性值;
3)、方法重构/重写
(1)、为什么要进行方法重构/重写?
当父类的方法在子类中满足不了需求时则需要对父类中的方法进行重构/重写。
(2)、什么是方法重构/重写?
在子类中定义一个和父类同名的方法即可实现方法重构/重写。
4)、super既可以当作方法也可以当作对象来使用,super当作对象使用时通常用来调用父类中的方法;
5)、静态的属性和方法也可以被继承下来;
3.5.1 继承基本语法【重点】
class 类名 extends 类名{
}
代码案例:
<script> //定义类:人类 class People { static types = '人类'; constructor(xm, ages) { // console.log('hello...'); this.xingming = xm; this.age = ages; } eat() { console.log(`${this.xingming} ${this.age}正在吃饭`); } work() { console.log(`${this.xingming} 正在工作...`); } } //定义类:工人类 class Worker extends People { } <script>
3.5.2 super的用法
代码案例:
<script> //定义类:人类 class People { static types = '人类'; constructor(xm, ages) { // console.log('hello...'); this.xingming = xm; this.age = ages; } eat() { console.log(`${this.xingming} ${this.age}正在吃饭`); } work() { console.log(`${this.xingming} 正在工作...`); } } //定义类:工人类 class Worker extends People { } console.log(Worker.types, 7777); //静态的属性和方法也可以被继承下来 let laoliang = new Worker(); laoliang.eat(); //定义类:学生类 class Students extends People { constructor(xh, xingmings, nianling) { //注意:super()方法可以把父类中的this继承下来的同时也可以给父类中的属性设置属性值 super(xingmings, nianling); //调用 this.xuehao = xh; //属性: 学号 } eat() { console.log(`${this.xingming} ${this.age} 正在大口大口地吃饭...`); } homework() { this.work(); super.work(); //注意: super当作对象使用时通常用来调用父类中的方法 // console.log(super.xingming, 999); console.log(`学号:${this.xuehao} 姓名:${this.xingming} 正在写作业!`); } } // let xiaoming = new Students('小明', 19); let xiaoming = new Students('X001', '小明', 20); xiaoming.eat(); xiaoming.homework(); </script>
3.6 面向对象的应用场景
3.6.1 封装工具原理
代码案例:
<script> class JS { constructor(v) { this.version = v; } Math() { return { ceil: function() { console.log('ceil...'); }, max: function() { } } } Array() { return { map() { }, forEach() { } } } } let jsObj = new JS('1.0.0'); let Math = jsObj.Math(); console.log(Math); Math.ceil(); </script>
3.6.2 Jquery使用原理
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script> $() </script>
四、iterator 迭代器
4.1 简介
Iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制, 遍历器, 因为现在有Array / String/arguments / Set / Map 5种结构, 所以ES6 加入了Iterator遍历器, 只要拥有这个Iterator遍历器, 就都可以使用for...of进行遍历 【重点】
4.2 作用
-
为各种数据结构,提供一个统一的、简便的访问接口
-
使得数据结构的成员能够按某种次序排列
-
ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of使用
-
Iterator是一个抽象的概念, 具体的实现 for...of / Symbol.iterator
4.3 for...of用法【重点】
代码案例:
<script> let arr = [1, 2, 5, 6, 9]; // console.log(arr); //iterator接口本身调用的方式【了解】: let ite = arr[Symbol.iterator](); // console.log(ite); // let obj = ite.next(); // console.log(obj, obj.value); // console.log(ite.next()); // console.log(ite.next()); // console.log(ite.next()); // console.log(ite.next()); // console.log(ite.next()); //for...of是iterator接口的语法糖: for (let x of arr) { console.log(x); } </script>
注意事项:在使用for...of遍历数据时, 要确保被遍历的数据, 拥有Iterator功能
for...of与forEach的区别?
forEach中不能使用break、continue,而for...of中则可以使用。
for...of与for...in的区别?
for...in通常用来遍历对象,for...of用来遍历具有iterator接口的数据类型。
4.4 数组和Iterator
代码案例:
<script> let arr = [1, 2, 5, 6, 9]; // console.log(arr); //iterator接口本身调用的方式【了解】: let ite = arr[Symbol.iterator](); console.log(ite); let obj = ite.next(); console.log(obj, obj.value); console.log(ite.next()); console.log(ite.next()); console.log(ite.next()); console.log(ite.next()); console.log(ite.next()); //for...of是iterator接口的语法糖: for (let x of arr) { console.log(x); } </script>
原理分析:
<script> let stu = { "usr": "张三", "age": 20, "sex": "男" }; //给指定的数据类型部署iterator接口:记住格式即可 stu[Symbol.iterator] = function() { let kArr = Object.keys(stu); let ind = 0; return { next: function() { if (ind < kArr.length) { return { value: stu[kArr[ind++]], done: false }; } else { return { value: undefined, done: true }; } } } } // let stuObj = stu[Symbol.iterator](); // console.log(stuObj.next()); // console.log(stuObj.next()); // console.log(stuObj.next()); // console.log(stuObj.next()); for (let y of stu) { console.log(y); } </script>
4.5 为对象部署iterator接口【重点】
代码案例:
//给指定的数据类型部署iterator接口:记住格式即可 stu[Symbol.iterator] = function() { }