ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际。
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。
http://kangax.github.io/compat-table/es6/ 可查看兼容性
以后声明变量使用 let 就对了
对象属性修改和数组元素变化不会出发 const 错误
声明对象类型使用 const,非对象类型声明选择 let
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
//数组的解构赋值
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
console.log(zhang); // 张学友
//对象的解构赋值
const lin = {
name: '林志颖',
tags: ['车手', '歌手', '小旋风', '演员'],
changge: function () {
console.log('我可以唱歌');
}
};
let {name, tags} = lin;
console.log(name); // 林志颖
let {cahngge} = lin;
changge(); // 我可以唱歌
模板字符串(template string)是增强版的字符串,用一对反引号(`)标识
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
name,
slogon,
improve,
change() {
console.log('可以改变你')
}
};
ES6 允许使用「箭头」 =>
定义函数。
ES6 允许给函数参数赋初始值
// 通用写法
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}
// 省略花括号的情况
let fn3 = score => score * 20;
适合与 this 无关的回调 定时器、数组的方法回调
不适合与 this 有关的回调 事件回调、对象的方法
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
...args
/**
* 作用与 arguments 类似
*/
function add(...args){
console.log(args); // [1,2,3,4,5]
}
add(1,2,3,4,5);
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
console.log(a); // 100
console.log(b); // 1
console.log(args); // [2,3,4,5,19]
}
minus(100,1,2,3,4,5,19);
rest 参数非常适合不定个数参数函数的场景
扩展运算符(spread)也是三个点...
。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
数组的合并
const arr1 = [1, 2];
const arr2 = [3, 4];
// const hebing = arr1.concat(arr2); 原先api函数
const hebing = [...arr1, ...arr2]
数组的克隆
const arr1 = [1, 2];
// 注意是 浅克隆
const hebing = [...arr1,]
将伪数组转为真正的数组
const divs = document.querySelectAll('div'); // 伪数组
const divArr = [...divs]
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
// 创建 Symbol
let s = Symbol();
console.log(s, typeof s); // Symbol() "symbol"
let s2 = Symbol('张艺兴'); // 注释作用
let s3 = Symbol('张艺兴');
console.log(s2 === s3); // false
// Symbol.for 创建
let s4 = Symbol.for('张艺兴');
let s5 = Symbol.for('张艺兴');
console.log(s4, typeof s4); // Symbol(张艺兴) "symbol"
console.log(s4 === s5); // true
Symbol['say']: function () {}
USONB (you are so niubility)
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
// 声明一个数组
const xiyou = ['1', '2', '3', '4'];
// 使用 for...of 遍历数组
for (const v of xiyou) {
console.log(v);
}
原生具备 iterator 接口的数据(可用 for of 遍历)
Array
Arguments
Set
Map
String
TypedArray
NodeList
工作原理
let iterator = xiyou[Symbol.iterator]();
// 调用对象的 next 方法
console.log(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}
}
}
}
}
}
// 遍历这个对象
for (const v of banji) {
console.log(v);
}
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,起其实就是一个特殊的函数。
// yield 函数代码的分隔符
function * gen() {
// console.log(111);
yield '一只没有耳朵';
// console.log(222);
yield '一只没有尾巴';
// console.log(333);
yield '真奇怪';
// console.log(444);
}
let iterator = gen();
// 调用 next() 方法才会执行方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
for (const v of gen()) {
console.log(v);
}
function * gen(arg) {
console.log(arg);
let one = yield '一只没有耳朵';
console.log(one);
let two = yield '一只没有尾巴';
console.log(two);
let three = yield '真奇怪';
console.log(three);
}
let iterator = gen('AAA');
// 调用 next() 方法才会执行方法
console.log(iterator.next());
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
…
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
const promise = new Promise(function(resolve, reject) {}
// 实例化 Promise 对象
const p = new Promise(function(resolve, reject) {
setTimeout(function () {
// let data = '数据库中的用户数据'
// resolve(data); // 调用 then 中第一个方法
let err = '数据读取失败';
reject(err); // 调用 then 中第二个方法
}, 1000);
});
// 调用 Promise 对象的 then 方法
p.then(function (value) {
console.log(value); // 数据库中的用户数据
}, function (reason) {
console.log(reason); // 数据读取失败
})
// 引入 fs 模块
const fs = require('fs');
const p = new Promise(function (resolve, reject) {
fs.readFile('./resources/为学.md', 'utf8', (err, data) => {
if (err) reject(err);
// 如果成功
resolve(data);
})
})
p.then(function (value) {
console.log(value);
}, function (reason) {
console.log('读取失败');
})
// 接口地址 http://api.apiopen.top/getJoke
const p = new Promise(function (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) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject()
}
}
}
})
// 指定回调
p.then(function (value) {
console.log(value);
}, function (reason) {
console.log('获取失败');
})
// 创建 promise 对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
// reject('出错啦');
}, 1000);
});
// 调用 then 方法 then方法的返回结果是 Promise 对象,对象状态又回调函数的执行结果决定
// 1. 如果回调函数中返回的结果是一个 非Promise 类型的数据,状态为成功,返回值为对象那个的成功值
const result = p.then(value => {
console.log(value);
// 1. 非 Promise 类型的数据
// return 123;
// 2. 是 Promise 对象
// return new Promise((resolve, reject) => {
// // resolve('ok');
// reject('出错')
// })
// 3. 抛出错误
// throw new Error('出错啦')
}, reason => {
console.warn(reason);
});
console.log(result);
// 链式调用 可以避免回调地狱的形成
p.then(value=>{
},reason=>{
}).then(value=>{
})
另外,then 方法中的两个方法 不一定需要全有
// 引入 fs 模块
const fs = require('fs');
// 之前的方法 - 回调地狱
// fs.readFile('./resources/为学.md', 'utf8', (err, data1) => {
// fs.readFile('./resources/插秧诗.md', 'utf8', (err, data2) => {
// fs.readFile('./resources/观书有感.md', 'utf8', (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', 'utf8', (err, data) => {
resolve(data);
})
})
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./resources/插秧诗.md', 'utf8', (err, data) => {
resolve([value, data]);
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./resources/观书有感.md', 'utf8', (err, data) => {
value.push(data);
resolve(value);
})
})
}).then(value => {
console.log(value.join('\r\n'));
})
不用不影响开发,catch 的作用只是简化,可以只写后面错误的函数,不需要写前面的。
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置 p 对象的状态为失败,并设置失败的值
reject('出错啦!')
}, 1000);
})
p.then(value => {}, reason => {
console.error(reason);
})
p.catch(reason => {
console.warn(reason);
})
ES6 提供了新的数据结构 Set(集合)。
它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。
// 声明一个 Set
let s = new Set();
let s2 = new Set(['大事儿', '小事儿', '好事儿', '坏事儿', '小事儿']);
console.log(s, typeof s);
console.log(s2); // 自动去重 {"大事儿", "小事儿", "好事儿", "坏事儿"}
// 元素的个数
console.log(s2.size); // 4
// 添加新的元素
s2.add('喜事儿');
console.log(s2); // {"大事儿", "小事儿", "好事儿", "坏事儿", "喜事儿"}
// 删除元素
s2.delete('坏事儿');
console.log(s2); // {"大事儿", "小事儿", "好事儿", "喜事儿"}
// 检测
console.log(s2.has('好事儿')); // true
// 清空
s2.clear();
console.log(s2); // {}
// 也可实现 for...of 遍历
for (const v of s2) {
console.log(v);
}
var 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);
// if (s2.has(item)) {
// return true;
// } else {
// return false;
// }
// })
// 简化
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result); // [4, 5]
// 3. 并集
let union = [...new Set([...arr, ...arr2])]
console.log(union); // [1, 2, 3, 4, 5, 6]
// 4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(diff); // [1, 2, 3]
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”
的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。
// 声明 Map
let m = new Map();
// 添加元素
m.set('name', '张艺兴')
m.set('change', function () {
console.log('张艺兴是最帅的');
})
let key = {
school : 'AgoniLay'
}
m.set(key, ['北京', '上海', '深圳'])
// size
console.log(m.size); // 3
// 删除
m.delete('name')
// 获取
// console.log(m.get('change'));
console.log(m.get(key)); // ["北京", "上海", "深圳"]
// 清空
// m.clear();
// 遍历
for (const v of m) {
console.log(v);
}
console.log(m);
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对
象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
// ES5
// 手机
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
// 添加方法
Phone.prototype.call = function () {
console.log('我可以打电话');
}
// 实例化对象
let huawei = new Phone('华为', 5999);
console.log(huawei);
// huawei.call();
class Shouji {
// 构造方法 名字不能修改
constructor (brand, price) {
this.brand = brand;
this.price = price;
}
// 方法必须使用该语法,不能使用 ES5 的对象完整形式
call () {
console.log('我可以打电话');
}
}
let onePlus = new Shouji('1+', 1999);
console.log(onePlus);
class Phone {
// 静态属性
static name = '手机';
static change = function () {
console.log('我可以改变世界');
};
}
let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // 手机
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);
this.color = color;
this.size = size;
}
photo () {
console.log('拍照');
}
playGame () {
console.log('打游戏');
}
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
子类可以进行对父类方法的重写
注:但是不能通过super()
调用父类重名方法
获取时,触发 get 方法
修改赋值时,触发 set 方法
注:set 方法必须有一个参数
class Phone {
get price () {
console.log('价格属性被读取了');
return 111
}
set price (newV) {
console.log('价格属性被修改了');
}
}
// 实例化对象
let s = new Phone();
console.log(s.price); // 111 // 触发 get
s.price = 'free'; // 触发 set
Number.EPSILON 是 JavaScript 表示的最小精度 ε
EPSILON属性的值接近于:2.2204460492503130808472633361816E-16
console.log(0.1 + 0.2 == 0.3); // false
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true
} else {
return false
}
}
console.log(equal(0.1 + 0.2, 0.3)); // true
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
let b = 0b1010; // 二进制
let b = 0o777; // 八进制
let d = 100; // 十进制
let x = 0xff; // 十六进制
用来检查一个数值是否为有限的,返回 boolean
用来检查一个值是否为 NaN,返回 boolean
移植到了 Number 对象下,使用不变,(截取整数,截取浮点数)
用来判断一个数值是否为整数, 返回 boolean
将数字的小数部分抹掉
判断一个数是 正数(1) 负数(-1) 还是 0(0) 括号内为相应的返回值
判断两个值是否完全相等
与全等号 ===
区别:
console.log(Object.is(NaN, NaN)); // true
console.log(NaN === NaN); // false
对象的合并,后面的将前面的覆盖掉
可以用于更新对象
const config1 = {
host: 'localhost',
prot: 3306,
name: 'root',
pass: 'root',
test: 'test'
}
const config2 = {
host: 'http://www.baidu.com',
prot: 33060,
name: 'AgoniLay',
pass: '020316'
}
console.log(Object.assign(config1, config2));
/*
host: "http://www.baidu.com"
name: "AgoniLay"
pass: "020316"
prot: 33060
test: "test"
*/
设置原型对象,一般不使用
console.log(Object.assign(config1, config2));
// Object.setPrototypeof Object.getPrototypeof
const school = {
name: '张艺兴'
}
const cities = {
xiaoqu: ['北京', '上海', '深圳']
}
Object.setPrototypeOf(school, cities)
console.log(Object.getPrototypeOf(school));
console.log(school);
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
模块功能主要由两个命令构成:export 和 import
是 浏览器端 与 服务器端 通用的模块化开发规范
安装工具
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
根目录下新建 babel.config.js 文件 写入:
const presets = [
["@babel/env", {
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
}
}]
]
module.exports = { presets }
执行代码
npx babel-node index.js
export default 默认导出的成员
import 接收名称 from '模块标识符/路径'
注意点:
{}
export let s1 = 10
import { s1 } from '模块标识符/路径'
注意点:
import '模块标识符/路径'
直接执行代码,没有导出。
当前 Web开发 面临的困境:
webpack 是一个流行的前端项目构建工具(打包工具),可以解决当前 web 开发中所面临的困境。
提供了友好的模块化支持,以及代码压缩混淆、处理 js 兼容问题、性能优化等强大的功能,提高了开发效率和项目的可维护性。
npm init -y
命令,进行初始化包管理配置文件 package.jsonnpm install jquery -S
命令, 安装 jQuery运行 npm insatll webpack webpack-cli -D
命令,安装 webpack 相关的包
在项目根目录中,创建名为 webpack.config.js 的 webpack 配置文件
在 webpack 的配置文件中,初始化如下基本配置:
module.exports = {
mode: 'development' // mode 用来指定构建模式
}
注意:开发阶段 mode 值一般设置为 development ,上线时才设置成 production (会进行压缩与混淆,转换时间会更长)
在 package.json 配置文件中的 scripts 节点下,新增 dev 脚本如下:
"scripts": {
"dev": "webpack" // script 节点下的脚本,可以通过 npm run 执行
}
在终端中运行 npm run dev
命令,启动 webpack 进行项目打包。
注意:主页面中导入的应该为打包生成后的 dist 文件夹下的 js 文件
webpack 的 4.x 版本中默认约定:
修改打包的入口(entry)和出口(output),可以在 webpack.config.js 中增加如下配置:
const path = require('path')
module.exports = {
entry: path.join(__dirname, './src/index.js'), // 打包入口文件的路径
output: {
path: path.join(__dirname, './dist'), // 输出文件的存放路径
filename: 'bundle.js' // 输出文件的名称
}
}
运行 npm install webpack-dev-server -D
命令,安装支持项目自动打包的工具
修改 package.json -> scripts 中的 dev 命令如下:
"scripts": {
"dev": "webpack server"
},
将 src -> index.html 中,script 脚本的引用路径,修改为 “/bundle.js”
运行 npm run dev
命令,重新进行打包
在浏览器中访问 http://localhost:8080 地址,查看自动打包效果。
运行 npm install html-webpack-plugin -D
命令,安装生成预览页面的插件
修改 webpack.config.js 文件头部区域,添加如下配置信息:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
})
修改 webpack.config.js 文件中向外暴露的配置对象,新增如下配置节点:
module.exports = {
plugins: [ htmlPlugin ] // plugins 数组时 webpack 打包期间会用到的一些插件列表
}
"scripts": {
"dev": "webpack server --open --host 127.0.0.1 --port 8080"
},
控制台报错:
DevTools failed to load SourceMap: Could not load content for webpack:///node_modules/sockjs-client/
解决:
webpack.config.js 中配置一项
module.exports = {
devtool: 'inline-source-map'
}
运行 npm install style-loader css-loader -D
命令,安装处理 css 文件的 loader
在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:
module: {
rules: [
{test: /\.css$/, use: ['style-loader', 'css-loader']}
]
}
其中,test 表示匹配的文件类型,use 表示对应要调用的 loader
注意:
运行 npm i less-loader less -D
命令,
在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:
module: {
rules: [
{test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader']}
]
}
运行 npm i sass-loader node-sass -D
命令,
运行不通使用:
首先删除 node_modules 中的 sass-loader 和 node-sass 目录
配置淘宝镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
用 cnpm 重新安装一次
cnpm install node-sass -D
cnpm install sass-loader -D
在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:
module: {
rules: [
{test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader']}
]
}
运行 npm i postcss-loader autoprefixer -D
命令,
在项目根目录中创建 postcss 的配置文件 postcss.config.js,并初始化如下配置:
// 导入自动添加前缀的插件
const autoprefixer = require('autoprefixer')
module.exports = {
plugins: [ autoprefixer ] // 挂载插件
}
在 webpack.config.js 的 modeule -> rules 数组中,修改 css 的 loader 规则如下:
module: {
rules: [
{test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader']}
]
}
运行 npm i url-loader file-loader -D
命令,
在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:
module: {
rules: [
{ test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: 'url-loader?limit=32417' },
]
}
注:? 后 limit参数是文件的大小(单位是字节),小于此大小 才会编译为 base64 格式
运行
npm i babel-loader @babel/core @babel/runtime -D
命令,安装 babel 转换器相关的包
运行
npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
命令,安装babel语法插件相关的包
在项目根目录下,创建 babel 配置文件 babel.config.js 并初始化基本配置如下:
module.exports = {
presets: ['@babel/env'],
plugins: ['@babel/plugin-transform-rutime', '@babel/plugin-proposal-class-properties']
}
在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:
// exclude 为排除项,表示 babel-loader 不需要处理 node_modules 中的 js 文件
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
npm 安装不了,就用 cnpm 安装
运行 npm i vue-loader vue-template-compiler -D
命令,
在 webpack.config.js 的 modeule -> rules 数组中,添加 loader 规则如下:
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module: {
rules: [
{ test: /\.vue$/, use: 'vue-loader' }
]
},
plugin: [
new VueLoaderPlugin()
]
}
npm i vue -S
安装 vueipmort Vue from 'vue'
来导入 vue 构造函数index.js
import Vue from 'vue'
// 导入 单文件组件
import App from './components/App.vue'
const vm = new Vue({
el: '#app',
render: h => h(App)
})
报错处理:
Error: Cannot find module ‘@babel/preset-preset.env’
解决:
将 babel.config.js 配置文件中的 preset-env
,改为 env
上线之前需要通过 webpack 将应用进行整体打包,可以通过 package.json 文件配置打包命令:
{
"scripts": {
"build": "webpack"
},
}
Includes 方法用来检测数组中是否包含某个元素,返回 boolean 类型值
在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同
console.log(2 ** 10); // 1024
console.log(Math.pow(2, 10)); // 1024