2.1 let 关键字用来声明变量
使用 let 声明的变量有几个特点:
- 不允许重复声明
- 块儿级作用域:只能在代码块里面有效
- 不存在变量提升:不允许在声明这个变量之前使用这个变量
- 不影响作用域链:
{
let school = '深圳大学';
function fun() {
console.log(school);
}
fun();
// 运行结果:正常输出“深圳大学”
// 虽然函数fun的作用域里面没有school这个变量
// 但是不影响作用域链,fun()从上一级里面去寻找这个school变量
}
2.1.1 let 实践案例
<script>
// 获取div元素对象
let items = document.getElementsByClassName('item');
// 遍历并绑定事件
for(let i = 0; i < items.length; i++) {
items[i].onclick = function() {
// 修改当前元素的背景颜色
// this.style.background = 'pink';
items[i].style.background = 'pink';
}
}
</script>
- 如果for循环里面不用let的话,var相当于在全局变量中存储
- 即var i,i此时遍历2次后再自增则为3,但是items里面只有三个元素,下标只到2,所以就会报错
2.1.2 应用场景
- 以后声明变量使用 let 就对了
2.2 const 关键字
const 关键字用来声明常量,const 声明有以下特点:
- 声明必须赋初始值
- 标识符一般为大写,如:
let SCHOOL = '深圳大学' - 不允许重复声明
- 值不允许修改
- 块儿级作用域
注意: 对象属性修改和数组元素变化不会出发 const 错误,如下:
const TEAM = ['123','456','789'];
TEAM.push = ('666')
// 常量所指向的地址没有发生变化,所以不会报错
应用场景:声明对象类型使用 const,非对象类型声明选择 let
2.3 变量的解构赋值
- ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
2.3.1 数组的解构
const F4 = ['小沈','刘无','赵四','宋三'];
let [xiao, liu, zhao, song];
// 相当于
let xiao = '小沈', liu = '刘无', zhao = '赵四', song = '宋三';
2.3.2 对象的解构
- 在对象的解构赋值中,解构的对象变量名要和被解构的变量名一致
// 1. 对象的解构赋值
const ZHAO = {
name: '赵三三',
age: '不详',
xiaopin: function () {
console.log("我可以说相声")
}
}
let {name, age, xiaopin} = ZHAO;
// 相当于
let name = ZHAO.name;
let age = ZHAO.age;
let xiaopin = ZHAO.xiaopin();
// 2. 频繁使用对象方法
const ZHAO = {
xiaoping: function () {
console.log("我可以说相声");
}
}
ZHAO.xiaoping(); // 一般调用
// 解构调用
let {xiaopin} = ZHAO;
xiaopin();
2.4 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
- 字符串中可以出现换行符
let str = `<ul>
<li>赵毅</li>
<li>赵三</li>
<li>赵二</li>
<li>赵五</li>
</ul>`;
- 可以使用 ${xxx} 形式输出变量
let star = '王某';
let result = `${star}在前几年离开了开心麻花`;
- 注意:当遇到字符串与变量拼接的情况使用模板字符串
2.5 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = '向上';
let slogon = '永远追求行业更高标准';
let improve = function () {
console.log('可以提高你的技能');
}
//属性和方法简写
let xiang = {
name,
slogon,
improve,
change () { // 这里简写了,change = function () {}
console.log('可以改变你');
}
};
- 注意:对象简写形式简化了代码,所以以后用简写就对了
2.6 箭头函数
ES6 允许使用「箭头」(=>)定义函数。
// 通用写法
// 声明一个函数
let fn = (a, b) => {
return a + b;
}
// 调用函数
let result = fn(1, 2);
console.log(result);
2.6.1 this的指向
this是静态的,this始终指向函数声明时所在作用域下的this的值
// 声明普通函数
function getName () {
console.log(this.name);
}
// 声明箭头函数
let getName2 = () = > {
console.log(this.name);
}
// 设置window对象的name属性
window.name = '深圳大学';
const school = {
name: "SZU"
}
// 直接调用,this指向window
getName(); // 控制台打印“深圳大学”
getName2(); // 控制台打印“深圳大学”
// call方法调用(call方法可以改变函数内部this的值)
getName.call(school); // 此时this指向school,所以控制台打印“SZU”
getName2.call(school); // 此时this依旧指向window,所以控制台打印“深圳大学”
2.6.2 不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('xiao', 30);
console.log(me);
// 报错:Person is not a constructor
2.6.3 不能使用arguments变量
let fn = () = > {
console.log(arguments);
}
fn(1, 2, 3);
// 报错:arguments is not defined
2.6.4 箭头函数的简写
// 1. 省略小括号,当形参有且只有一个的时候
let add = n => {
return n + n;
}
// 2. 省略花括号,当代码体只有一条语句的时候,此时return必须省略
// 而且语句的执行结果就是函数的返回值
let pow = n => n * n;
- 注意:箭头函数不会更改this指向,用来指定回调函数会非常合适
2.6.5 箭头函数的实践
2.6.5.1 需求1
点击div 2s后颜色变成“粉色”
// 获取元素
let ad = document.getElementById('ad');
// 绑定事件
ad.addEventListener("click", function() {
// 保存this的值
// let _this = this;
// 定时器
setTimeout(() => {
// 修改背景颜色 this
// 此时箭头函数this指向ad元素,因为是在ad下定义的箭头函数
// _this.style.background = 'pink';
this.style.background = 'pink';
}, 2000);
});
2.6.5.2 需求2
从数组中返回偶数的元素
const arr = [1, 6, 9, 10, 100, 25];
// 一般方法
const result = arr.filter(function(item) {
if(item % 2 === 0) {
return true;
} else {
return false;
}
});
// 箭头函数方法
const result = arr.filter(item => item % 2 === 0);
2.6.6 箭头函数总结
- 箭头函数适合与this无关的回调:定时器,数组的方法回调
- 箭头函数不适合与this有关的回调:事件回调,对象的方法
2.7 函数参数的默认值设置
- ES6允许给函数参数赋值初始值
2.7.1 形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
function add(a, b, c = 10) {
return a + b + c;
}
let result = add(1, 2);
console.log(result); // 控制台输出13
2.7.2 与解构赋值结合
function connect({host = "127.0.0.1", username, password, port}) {
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'baidu.com',
username: 'root',
password: 'root',
port: 3306
})
2.8 rest 参数
ES6 引入rest参数,用于获取函数的实参,用来代替arguments
// ES5 获取实参的方式
function data() {
console.log(arguments);
}
data('白纸', '阿娇', '思慧');
// 控制台输出为一个对象
// rest参数
function data(...args) {
console.log(args);
}
data('白纸', '阿娇', '思慧');
// 控制台输出为一个数组,可以用数组的api如:filter some every map等
// rest 参数必须要放到参数最后
function fn(a, b, ...args) {
console.log(a);
console.log(b);
console.log(args);
}
fn(1, 2, 3, 4, 5, 6);
// 控制台输出:1, 2, [3, 4, 5, 6]
2.9 spread 扩展运算符
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
/**
* 展开数组
*/
let tfboys = ['盖文','赵信','皇子'];
function fn(){
console.log(arguments);
}
fn(...tfboys)
// 控制台输出为:'盖文','赵信','皇子'
2.9.1 数组的合并
const kuaizi = ['a', 'b'];
const fengh = ['c', 'd'];
const zuhe = [...kuaizi, ... fengh];
console.log(zuhe);
// 控制台输出:['a', 'b', 'c', 'd']
2.9.2 数组的克隆
const szh = ['E', 'G', 'M'];
const syc = [...szh];
console.log(syc);
// 控制台输出:['E', 'G', 'M']
2.9.3 将伪数组转为真正的数组
const divs = document.querySelectorAll('div'); // 这里拿到的div是object
const divArr = [...divs]; // 这里转为了真正的数组
console.log(divArr);
2.10 Symbol
2.10.1 Symbol 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题
- Symbol 值不能与其他数据进行运算
- Symbol 定义 的 对象属 性 不能 使 用 for…in 循环遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名
// 创建Symbol
let s2 = Symbol('水果干');
let s3 = Symbol('水果干');
console.log(s2 === s3);
// 控制台打印:false(因为编码不同)
// Symbol.for 创建(for获取唯一值,所以这里s4等于s5)
let s4 = Symbol.for('水果干');
let s5 = Symbol.for('水果干');
console.log(s4 === s5);
// 控制台打印:true
JavaScript数据类型记忆方法:USONB
- u: undefined
- s: string, symbol
- o: object
- n: null, number
- b: boolean
注: 遇到唯一性的场景时要想到 Symbol
2.10.2 对象添加Symbol类型的属性
向对象中添加方法 up down,但是该对象中的属性很多,你不确定有没有已经有up 和 down的方法,这个时候可以用Symbol来添加唯一的方法,就不会重复了
let game = {...
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function() {
console.log("我可以改变形状");
}
game[methods.down] = function() {
console.log("我可以快速下降!!");
}
console.log(game);
- 另外一个方法
let youxi = {
name: "狼人杀",
[Symbol('say')]: function() {
console.log("我可以发言")
},
[Symbol('zibao')]: function() {
console.log("我可以说话")
}
}
2.10.3 Symbol的内置属性
指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
| 方法 | 描述 |
|---|---|
| Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 |
| Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。 |
| Symbol.species | 创建衍生对象时,会使用该属性 |
| Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。 |
| Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.search | 当该对象被 str.search (myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.split | 当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.iterator | 对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器 |
| Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
| Symbol. toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值 |
| Symbol. unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with环境排除。 |
2.11 迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
2.11.1 ES6 创造了一种新的遍历命令
for...of 循环,Iterator 接口主要供 for...of 消费
- for...of遍历键值 for...in遍历键名
// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
// 使用 for...in 遍历数组输出键名
for (let v in xiyou) {
console.log(v);
}
// 输出:0,1,2,3
// 使用 for...of 遍历数组输出键值
for (let v of xiyou) {
console.log(v);
}
// 输出:唐僧, 孙悟空, 猪八戒, 沙僧
2.11.2 原生具备 iterator 接口的数据(可用 for of 遍历)
- Array、Arguments、Set、Map、String、TypedArray、NodeList
- 对象里面有Symbol.iterator属性就可以进行遍历了
2.11.3 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
// 原理
let iterator = xiyou[Symbol.iterator]();
// 调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
注: 需要自定义遍历数据的时候,要想到迭代器。
- 例子:
// 迭代器案例:遍历这个自定义对象
// 声明一个对象
const banji = {
name: "终极一班",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[Symbol.iterator]() {
// 索引变量
let index = 0;
//
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = { value: _this.stus[index], done: false };
// 下标自增
index++;
// 返回结果
return result;
} else {
return {value: undefined, done: true};
}
}
};
}
}
2.12 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
yield '真奇怪';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
代码说明:
- “ * ”的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到yield 语句后的值
- yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码
- next 方法可以传递实参,作为 yield 语句的返回值,默认返回yield后面的值
2.12.1 整体传参与next方法传参
2.12.2 定时器案例
异步编程:1s 后控制台输出111 ,2s后输出222 , 3s后输出333
// 回调地狱:回调函数里面套回调函数
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000);
}, 2000);
}, 1000);
// 下面用生成器函数完成异步编程
function one() {
setTimeout(() => {
console.log(111);
iterator.next(); // 往下执行
}, 1000)
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000)
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000)
}
function * gen() {
yield one();
yield two();
yield three();
}
// 调用生成器函数
let iterator = gen();
iterator.next();
2.12.3 模拟获取数据
模拟获取用户的数据,然后获取用户对应的订单数据,然后获取订单对应的商品数据
function getUsers() {
setTimeout(() => {
let data = '用户数据';
// 调用next方法,并且将数据传入
iterator.next(data);
}, 1000);
}
function getOrders() {
setTimeout(() => {
let data = '订单数据';
iterator.next(data);
}, 1000);
}
function getGoods() {
setTimeout(() => {
let data = '商品数据';
iterator.next(data);
}, 1000);
}
function * gen() {
let users = yield getUsers();
let orders = yield getOrders();
let goods = yield getGoods();
}
// 调用生成器函数
let iterator = gen();
iterator.next();
2.13 Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
- Promise 构造函数: Promise (excutor) {}
- Promise.prototype.then 方法
- Promise.prototype.catch 方法
2.13.1 Promise的基本使用
// 实例化 Promise 对象
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
//
// let data = '数据库中的用户数据';
// resolve
// resolve(data);
let err = '数据读取失败';
reject(err);
}, 1000);
});
// 调用 promise 对象的 then 方法
p.then(function (value) {
// 成功调用第一个value
console.log(value);
}, function (reason) {
// 失败调用第二个reason
console.log(reason);
})
2.13.2 Promise 封装读取文件
// 1. 引入 fs 模块
const fs = require('fs');
// 2. 调用方法读取文件
fs.readFile('./resources/为学.md', (err, data) => {
// 如果失败
if (err) throw err;
// 如果没有出错,则输出内容
console.log(data.toString());
});
// 3. 使用 Promise 封装
const p = new Promise(function(resolve, reject) {
fs.readFile("./resources/为学.md", (err, data) => {
// 判断如果失败
if(err) {
// 调用reject,修改promise的状态为失败
reject(err);
}
// 如果成功
// 调用resolve,修改promise的状态为成功
resolve(data);
});
});
// 通过then方法来处理失败或成功的结果
p.then(function(value){
console.log(value.toString());
}, function(reason) {
console.log("读取失败!!");
});
2.13.3 Promise 封装AJAX请求
const p = new Promise((resolve, reject) => {
// 1. 创建对象
const xhr = new XMLHttpRequest();
// 2. 初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");
// 3. 发送
xhr.send();
// 4. 绑定事件,处理响应结果
xhr.onreadystatechange = function () {
// 判断
if (xhr.readyState === 4) {
// 判断响应状态码 200-299(成功)
if (xhr.status >= 200 && xhr.status < 300) {
// 表示成功
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
});
// 指定回调
p.then(function(value){
// 成功则输出返回的数据
console.log(value);
}, function(reason){
// 失败则输出报错的信息
console.error(reason);
});
2.13.4 Promise.prototype.then方法
- 调用then方法,then方法的返回结果是Promise对象,对象状态由回调函数的执行结果决定
-
- 如果回调函数中返回的结果是非Promise类型的属性,状态为成功,返回值为对象的成功的值
// 创建 promise 对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
// reject('出错啦');
}, 1000)
});
const result = p.then(value => {
console.log(value);
// 1. 非Promise类型的属性
// return 'iloveyou';
// 2. 是Promise对象
// return new Promise((resolve, reject) => {
// // resolve('ok');
// reject('error');
// });
// 3. 抛出错误
// throw new Error('error');
throw '出错啦';
}, reason => {
console.warn(reason);
});
// 因为then方法返回一个Promise对象的特性,then方法是可以链式调用的
// 链式调用
p.then(value => {
}).then(value => {
});
// 链式调用一形成,杜绝回调地狱
console.log(result);
2.13.5 Promise实践练习 - 多个文件内容获取
获取多个文件内容,将他们合在一起并输出
// 引入fs模块
const fs = require("fs");
// 回调地狱写法
// fs.readFile('./resources/为学.md', (err, data1) => {
// fs.readFile('./resources/插秧诗.md', (err, data2) => {
// fs.readFile('./resources/观书有感.md', (err, data3) => {
// let result = data1 + '\r\n' +data2 + '\r\n' + data3;
// console.log(result);
// });
// });
// });
// 使用Promise实现
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
resolve([value, data]);
});
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
// 压入
value.push(data);
resolve(value);
});
})
}).then(value => {
console.log(value.join('\r\n'));
});
2.13.6 Promise对象catch方法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置p对象的状态为失败,并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
// 只需要一个错误的参数即可,相当于then方法的语法糖
p.catch(function(reason) {
console.warn(reason);
});
2.14 Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的(重复会自动去重),集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:
- size:返回集合的元素个数
- add:增加一个新元素,返回当前集合
- delete:删除元素,返回 boolean 值
- has:检测集合中是否包含某个元素,返回 boolean 值
- clear:清空集合,返回 undefined
2.14.1 集合方法实践
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s1 = new Set([1, 2, 3, 1, 2, 3]);
//集合属性与方法
//返回集合的元素个数
console.log(s1.size);
//添加新元素
console.log(s1.add(4));
//删除元素
console.log(s1.delete(1));
//检测是否存在某个值
console.log(s1.has(2));
//清空集合
console.log(s1.clear());
2.14.2 集合案例实践
// 实际案例
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
// 1. 数组去重
let result = [...new Set(arr)];
console.log(result);
// 2. 交集
let arr2 = [4, 5, 6, 5, 6];
let result = [...new Set(arr)].filter(item => {
let s2 = new Set(arr2); // 4 5 6
if (s2.has(item)) {
return true;
} else {
return false;
}
});
// 简写
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);
// 3. 并集
let union = [...new Set([...arr, ...arr2])];
console.log(union);
// 4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
2.15 Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。
Map 的属性和方法:
- size:返回 Map 的元素个数
- set:增加一个新元素,返回当前 Map
- get:返回键名对象的键值
- has:检测 Map 中是否包含某个元素,返回 boolean 值
- clear:清空集合,返回 undefined
2.15.1 Map方法实例
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
['name', '333'],
['slogon', '不断提高行业标准']
]);
// 添加元素
m2.set('change', function () {
console.log("我们可以改变你!")
});
// 声明一个对象
let key = {
school: 'abc'
};
m2.set(key, ['a', 'b', 'c']);
//属性和方法
//获取映射元素的个数
console.log(m2.size);
//添加映射值
console.log(m2.set('age', 6));
//获取映射值
console.log(m2.get('age'));
//检测是否有该映射
console.log(m2.has('age'));
//清除
console.log(m2.clear());
2.16 Class 类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
- class 声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
2.16.1 class介绍与constructor实例
// ES5 写法
// 手机
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
// 添加方法:通过原型对象去添加方法,这样子来做到重用
Phone.prototype.call = function() {
console.log("我可以打电话");
}
// 实例化对象
let Huawei = new Phone('华为', 5999);
Huawei.call();
console.log(Huawei);
// ES6 写法
class Shouji {
// 构造方法 名字不能修改
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 方法必须使用该语法,不能使用ES5的对象完整形式
call() {
console.log("我可以打电话!!");
}
}
let onePlus = new Shouji("1+", 1000);
console.log(onePlus);
2.16.2 class 静态成员
- 实例对象与函数对象的属性是不相通的
- 函数对象的属性是属于函数对象的,并不属于实例对象,这样的属性我们称为静态成员
function Shouji() {
}
Shouji.name = '手机';
Shouji.change = function() {
console.log("222");
}
Phone.prototype.size = '5.5inch';
let mamba = new Shouji();
console.log(mamba.name); // 打印:undefined
mamba.change(); // 报错:未定义该函数
console.log(mamba.size); // 打印:5.5inch
- 对于类来说,静态属性是属于类的,并不属于实例对象
class Phone {
// 静态属性
static name = '手机';
static change() {
console.log("111");
}
}
let nokia = new Phone();
console.log(nokia.name); // 打印:undefined
console.log(Phone.name); // 打印:手机
2.16.3 ES5构造函数继承
// 手机
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function() {
console.log("我可以");
}
// 智能手机
function SmartPhone(brand, price, color, size) {
// 改变this指向为SmartPhone
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone;
// 再做一个矫正(可加可不加,不影响)
SmartPhone.prototype.constructor = SmartPhone;
// 声明子类的方法
SmartPhone.prototype.photo = function() {
console.log("拍照");
}
SmartPhone.prototype.playGame = function() {
console.log("玩游戏");
}
const chuizi = new SmartPhone('锤子', 2222, '黑色', '5.5inch');
console.log(chuizi);
2.16.4 class的类继承
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 父类的成员属性
call() {
console.log("打电话");
}
}
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size) {
// 调用父类的构造方法
super(brand, price); // Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// 方法
photo() {
console.log("拍照");
}
playGame() {
console.log("玩游戏");
}
}
const xiaomi = new SmartPhone('小米', 3333, '黑色', '4,7inch');
console.log(xiaomi);
xiaomi.photo();
xiaomi.playGame();
xiaomi.call();
2.16.5 子类对父类方法的重写
- 在js中的class类方法中,子类是不能够直接去调用这个父类的同名方法的
- 可以通过重写去调用父类的同名方法
class Phone {
// 构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 父类的成员属性
call() {
console.log("打电话");
}
}
class SmartPhone extends Phone {
// 构造方法
constructor(brand, price, color, size) {
// 调用父类的构造方法
super(brand, price); // Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// 方法
photo() {
console.log("拍照");
}
playGame() {
console.log("玩游戏");
}
// 重写父类同名方法
call() {
console.log("视频通话");
}
}
const xiaomi = new SmartPhone('小米', 3333, '黑色', '4,7inch');
console.log(xiaomi);
xiaomi.photo();
xiaomi.playGame();
xiaomi.call(); // 这里调用的是子类的call方法
2.16.6 class中getter和setter设置
- 当值被获取时,执行get对应的函数
- 当值被修改时,执行set对应的函数
// get 和 set
class Phone {
// 类可以没有构造函数
get price() {
console.log("价格属性被读取了");
return 'hello';
}
set abb(newVal) {
console.log('价格属性被修改了');
}
}
// 实例化对象
let s = new Phone();
// 因为s.price被获取了,所以执行get对应的函数;控制台打印:价格属性被读取了,并且返回'hello'
console.log(s.price);
// 因为s.price值被修改了,所以执行set对应的函数;控制台打印:价格属性被修改了
s.price = 'free';
2.17 数值扩展
- Number.EPSILON 是js表示的最小精度
- EPSILON 属性的值接近于 2.220446...
应用:
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(0.1 + 0.2 === 0.3); // false
console.log(equal(0.1 + 0.2, 0.3)); // true
2.17.1 二进制和八进制
- ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
2.17.2 Number.isFinite() 与 Number.isNaN()
- Number.isFinite() 用来检查一个数值是否为有限的:
console.log(Number.isFinite(100));
- Number.isNaN() 用来检查一个值是否为 NaN:
console.log(Number.isNaN(123));
2.17.3 Number.parseInt() 与 Number.parseFloat()
- ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
console.log(Number.parseInt('131234神奇')); // 打印:131234
console.log(Number.parseFloat('1.31234神奇')); // 打印:1.31234
2.17.4 Number.isInteger
- Number.isInteger() 用来判断一个数值是否为整数
console.log(Number.isInteger(5)); // 打印:true
console.log(Number.isInteger(2.5)); // 打印:false
2.17.5 Math.trunc
- 用于去除一个数的小数部分,返回整数部分。
console.log(Math.trunc(2.3)); // 打印:2
2.17.6 Math.sign
- 用来判断一个数到底是为正数(1)、负数(-1)还是0(0)
console.log(Math.sign(100)); // 打印 1
console.log(Math.sign(0)); // 打印 0
console.log(Math.sign(-100)); // 打印 -1
2.18 对象扩展
ES6 新增了一些 Object 对象的方法
2.18.1 Object.is
- 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
console.log(Object.is(NaN, NaN)); // 打印:true
console.log(NaN === NaN); // 打印:false
2.18.2 Object.assign
- 对象的合并,将源对象的所有可枚举属性,复制到目标对象
- 如果参数名相同,后者对象属性值覆盖前者
const config1 = {
host: 'localhost',
port: 3306,
name: 'root'
};
const config2 = {
host: '111',
port: 222
};
console.log(Object.assign(config1, config2));
// 打印:{host: "111", port: 222, name: "root"}
2.18.3 Object.setPrototypeOf 设置原型对象
__proto__、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型- Object.getPrototypeOf
const school = {
name: 'ab大学'
};
const cities = {
xiaoqu: ['11', '22', '33', '44']
};
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
2.19 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
2.19.1 模块化的好处
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
2.19.2 模块化规范产品
ES6 之前的模块化规范有:
- CommonJS => NodeJS、Browserify
- AMD => requireJS
- CMD => seaJS
2.19.3 ES6 模块化语法
模块功能主要由两个命令构成:export 和 import。
2.19.3.1 export 命令用于规定模块的对外接口
- 如果需要被引用,那就export暴露数据
- 分别暴露
// m1.js 文件下
// 分别暴露
export let school = '111';
export function teach() {
console.log(222);
}
- 统一暴露
// m2.js 文件下
// 统一暴露
let school = '234';
function findJob() {
console.log("找工作");
}
// 导出要暴露的数据
export {school, findJob};
- 默认暴露
// m3.js 文件下
// 默认暴露
export default {
school: '555',
change: function() {
console.log('changer');
}
}
2.19.3.2 import 命令用于输入其他模块提供的功能
- 通用的导入方式
<script type="module">
// 1. 通用的导入方式
// 引入 m1.js 模块内容
import * as m1 from "./src/js/m1.js";
console.log(m1);
// 引入m2.js 模块内容
import * as m2 from "./src/js/m2.js";
console.log(m2);
// 引入m3.js 模块内容
import * as m2 from "./src/js/m3.js";
console.log(m3);
m3.default.change();
</script>
- 解构赋值形式
<script type="module">
// 2. 解构赋值形式
import {school, teach} from "./src/js/m1.js";
import {school as guigu, findJob} from "./src/js/m2.js"; // 变量命名冲突,设置别名
import {default as m3} from "./src/js/m3.js"; // 导入默认对象,必须使用别名
</script>
- 简便形式(针对默认暴露)
<script type="module">
// 3. 简便形式 针对默认暴露
import m3 from "./src/js/m3.js";
console.log(m3);
</script>
2.19.4 浏览器使用ES6模块化方式二
- 先建一个入口文件
// app.js
// 入口文件
// 模块引入
import * as m1 from "./m1.js";
import * as m2 from "./m2.js";
import * as m3 from "./m3.js";
console.log(m1);
console.log(m2);
console.log(m3);
- 在html里面引用这个入口文件
// html
<script src="./src/js/app.js" type="module"></script>
2.19.5 babel对ES6模块化代码转换
- html文件引入
<!--
1. 安装工具 babel-cli babel-preset-env browserify(webpack)
2. npx babel src/js -d dist/js
3. 打包 npx browserify dist/js/app.js -o dist/bundle.js
-->
<script src="dist/bundle.js"></script>
- 命令行指令
1. 安装工具
npm init --yes
npm i babel-cli babel-preset-env browserify -D
// 局部安装选择npx
// 2. 选择文件路径,命令行传参
npx babel -d dist/js --presets=babel-preset-env
// 3. 打包到bundle.js,进行文件转换
npx browserify dis/js/app.js -o dist/bundle.js // 文件转换
// 全局安装选择babel
babel
2.19.6 ES6模块化引入NPM包
- 使用npm包
// app.js 文件
// 修改背景颜色为粉色
import $ from 'jquery'; // const $ = require("jquery");
$('body').css('background', 'pink');
// 安装jquery
npm i jquery
// 打包
npx babel -d dist/js --presets=babel-preset-env
// 重新打包
npx browserify dis/js/app.js -o dist/bundle.js