let 和 const
创建变量的新语法,替换原来的 var
var num = 10;
console.log(num); // 控制台输出10
let num1 = 10;
console.log(num1); // 控制台输出10
const num2 = 10;
console.log(num2); // 控制台输出10
let const 与 var 的区别
- 自带块级作用域 {} 代表块
if (5 > 3) {
var num = 100;
}
console.log(num); // 控制台输出: 100
if (5 > 3) {
let num = 100;
console.log(num); // 控制台输出: 100
}
console.log(num); // 控制台报错: num is not defined
- 没有变量声明提升
console.log(a); // 控制台输出: undefined
var a = 0;
console.log(b); // 控制台报错: Cannot access 'b' before initialization
let b = 1;
- 不允许重复声明
var a = 0;
var a = 50;
console.log(a); // 控制台输出: 50
let a = 0;
let a = 50;
console.log(a); // 控制台报错: Identifier 'a' has already been declared
- const 适用于创建常量,不可修改 比如:圆周率的 π
const num2 = 10;
num2++;
console.log(num2);
// 控制台报错提示 : Assignment to constant variable.
- 定义的变量不属于顶层对象(window)的属性
var a = 1;
console.log(window.a); // 控制台输出: 1
let b = 1;
console.log(window.b); // 控制台输出: undefined
变量的解构赋值
- 数组的结构赋值 数组的结构赋值要注意位置对应
let arr = [131, 182, 156];
// 定义变量取出数组内容
let num1 = arr[0];
let num2 = arr[1];
let num3 = arr[2];
console.log(num1, num2, num3); // 控制台输出 131 182 156
// 变量的结构赋值
let [num1, num2, num3] = arr;
console.log(num1, num2, num3); // 控制台输出 131 182 156
- 对象的结构赋值 对象的结构赋值要注意名字对应
let obj = {
username: "小黑",
userage: 20,
};
let username = obj.username;
let userage = obj.userage;
console.log(username, userage); // 控制台输出:小黑 20
// 对象的解构赋值
// 可以换名字 使用 :
// 可以换名也可以设置默认值
let { username, userage: age, sex = "男" } = obj;
console.log(username, age, sex); // 控制台输出:小黑 20 男
如果要将一个已经声明的变量用于解构赋值:
let obj = {
username: "小黑",
userage: 20,
};
let username;
let age;
let sex;
let { username, userage: age, sex = "男" } = obj;
console.log(username, age, sex); // 控制台报错: Unexpected token ':'
({ username, userage: age, sex = "男" } = obj);
console.log(username, age, sex); // 控制台输出:小黑 20 男
- 字符串的结构赋值
let str = "hello";
let [a, b, c, d, e] = str;
console.log(a, b, c, d, e); // 控制台输出 h e l l o
- 函数参数的结构赋值
let obj = {
username: "大白",
};
function say(obj) {
const str = "我叫" + obj.username;
console.log(str); // 控制台输出 我叫大白
}
say(obj);
// 函数参数的结构赋值
function say({ username }) {
const str = "我叫" + username;
console.log(str); // 控制台输出 我叫大白
}
say(obj);
字符串的扩展
- 模板字符串 (高级字符串拼接)
let goods = {
goodsName: "iphone12",
price: 10000,
};
// 字符串拼接
let htmlStr =
"<div><h4>" +
goods.goodsName +
"</h4></span>" +
goods.price +
"</span></div>";
console.log(htmlStr);
// 控制台输出:<div><h4>iphone12</h4></span>10000</span></div>
// 模板字符串
let htmlStr1 = `<div><h4>${goods.goodsName}</h4></span>${goods.price}</span></div>`;
console.log(htmlStr1);
// 控制台输出:<div><h4>iphone12</h4></span>10000</span></div>
- padEnd padStart 填充
let str = "hello";
let newStr = str.padEnd(8, "a");
// 8 填充到的长度 'a' 用 a 填充
console.log(str); // 后台输出:helloaaa
console.log(newStr); // 后台输出:helloaaa
新增数据类型
-
标准数据类型 数字(Number) 字符串(String) 布尔值(Boolean) Undefined Null Object
-
新增 BigInt(大整数) 为了与 Number 类型区别,BigInt 类型的数据必须添加后缀 n。
1234; // 普通整数
1234n; // BigInt
// BigInt 的运算
1n + 2n; // 3n
- 新增 Symbol(表示独一无二的值) Symbol()接收一个字符串作为参数,表示对 Symbol 的描述
let sym = Symbol("KK");
console.log(sym); // 控制台输出: Symbol(KK)
typeof sym; // 控制台输出:"symbol"
// 字符串参数相同,两个 Symbol 也不行等
let sym1 = Symbol("kk");
sym === sym1; // 控制台输出: false
数组的扩展
-
flat() flatMap() 数组的扁平化处理
flat()变成一维的数组,该方法返回一个新数组,不改变原数组。
let arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat()); // 控制台输出:(5) [1, 2, 3, 4, Array(2)]
// flat 默认扁平一次
console.log(arr.flat().flat()); // 控制台输出:(6) [1, 2, 3, 4, 5, 6]
console.log(arr.flat(2)); // 控制台输出:(6) [1, 2, 3, 4, 5, 6]
// flat(次数) 扁平化次数
console.log(arr.flat(Infinity)); // 控制台输出:(6) [1, 2, 3, 4, 5, 6]]
// flat(Infinity)用Infinity关键字作为参数,数组全部拉平
flatMap()方法对原数组的每个成员执行一个函数,然后对返回值组成的数组执行 flat()方法,该方法不改变原数组。
let arr = [1, 2];
// 数组的 map() 方法
let newArr = arr.map(function (ele) {
return [ele, ele * 2];
});
console.log(newArr); // 控制台输出:(2) [Array(2), Array(2)]
// 数组的 flatMap() 方法 相当于先对数组进行 map() 然后再进行一层 flat()
let arr1 = [1, 2];
let newArr1 = arr1.flatMap(function (ele) {
return [ele, ele * 2];
});
console.log(newArr1); // 控制台输出:(4) [1, 2, 2, 4]
- fill() 根据指定的数据对数组进行初始化 此方法会修改原数组
let arr = [1, 2, 3];
console.log(arr.fill(100)); // 控制台输出:(3) [100, 100, 100]
console.log(arr.fill(7, 1, 2)); // 控制台输出:(3) [1, 7, 3]
对象的扩展
- 属性的简洁表示法 创建对象的时候属性值所代表的变量名和属性名重复可以省略,方法函数可以省略: function
// let name = "大白";
// let age = 10;
// let obj = {
// name: name,
// age: age,
// say: function () {
// console.log(this.name);
// },
// };
let name = "大白";
let age = 10;
let obj = {
name,
age,
say() {
console.log(this.name);
},
};
obj.say();
扩展运算符 ...
扩展运算符用于拷贝的话只能实现浅拷贝
- 数组的扩展
let arr = [1, 2, 3, 4, 5];
let arr1 = [...arr];
arr1.push(6);
console.log(arr); // (5) [1, 2, 3, 4, 5]
console.log(arr1); // (6) [1, 2, 3, 4, 5, 6]
console.log(arr1 === arr); // false
- 对象的扩展
let obj = {
a: 10,
b: 20,
};
let obj1 = { ...obj };
obj1.a = 100;
console.log(obj); // {a: 10, b: 20}
console.log(obj1); // {a: 100, b: 20}
- 函数的扩展
- 函数参数的默认值
// 函数参数默认值 设置了默认值 调用函数不传参数 显示结果 function add(x = 10, y = 20) { return x + y; } // 传了参数 覆盖默认值 let res = add(2); console.log(res); // 22
- rest 参数 rest 剩余参数
function fun(a, ...rest) { // rest 剩余参数 必须写在最后面 console.log(rest); } fun(1, 2, 3, 4); // (3) [2, 3, 4]
- 函数的新写法 箭头函数
箭头函数没有 function 不能使用 function 创建,只能写在变量中
- 箭头函数分为箭头左侧和右侧
- 左侧是参数部分,默认使用 () 包裹,当只有一个参数的是有可以省略 () ,直接写参数(没有参数写一个空的 () )
- 右侧是执行部分,默认使用 {} 包裹,当函数右侧只有返回值的时候可以省略 {} 直接写返回值也不需要 return
- 当函数只返回对象的时候可以直接 ({object})
箭头函数和普通函数的 this 指向问题:let add = (x, y = 20) => x + y; // let add = (x, y = 20) => { // x = x * 2; // return x + y; // }; let res = add(10); console.log(res);
- 普通函数的 this 指向,谁调用了就指向谁
let obj = { a: 10, fun: function () { console.log(this); }, }; obj.fun(); // {a: 10, fun: ƒ} let fun1 = obj.fun; fun1(); // Window
- 箭头函数的 this 创建的是有就定义好了
对象内定义方法的时候,如果方法内部使用了 this ,那么这个方法不能使用箭头函数定义
let obj = { a: 10, fun: () => { console.log(this); }, }; obj.fun(); // window let fun1 = obj.fun; fun1(); // window
- 在类里面可以使用箭头函数 正确的 this 指向
class Point { constructor(x, y) { this.x = x; this.y = y; } // sayPoint() { // console.log(this.x, this.y); // } // 类里面的箭头函数 = sayPoint = () => { console.log(this.x, this.y); }; } let p = new Point(10, 100); p.sayPoint(); // 10 100
Set 数据结构(构造函数)
Set 内部不允许出现重复的成员
const s = new Set();
// add 是 set 数据结构的一个方法,该方法的作用是向内部添加新的成员
// size 属性返回 Set 的个数(相当于数组的 length)
// delete 方法
// has 方法
// clear 方法
// forEach 方法
[2, 3, 5, 4, 5, "2", 2].forEach(function (ele) {
s.add(ele);
});
console.log(s); // 控制台输出:Set(5) {2, 3, 5, 4, "2"}
// 新建 Set 内部要传递数组
let newS = new Set([1, 2, 3, 4,1]);
console.log(newS); // Set(4) {1, 2, 3, 4}
// Set 通过扩展运算符实现数组去重
let arr = [1, 2, 33, 4, 2, 2, 6, 8, 67, 76, 34, 23, 1, 6, 76];
console.log([...new Set(arr)]); // (10) [1, 2, 33, 4, 6, 8, 67, 76, 34, 23]
Map 数据结构
Map 数据结构 类似于对象,也是键值对的集合,可以把各种类型的值(包括对象)当作键。
// 正常对象结构如果用数字表示'键'
let obj = {
1: 200,
};
console.log(obj.1); // 会报错
Class(类)
- 构造函数回顾
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return `(${this.x},${this.y})`;
};
var p = new Point(1, 2);
console.log(p); // Point {x: 1, y: 2}
console.log(p.toString()); // (1,2)
- 创建类
- 类的内部默认只能写方法
- 类的内部必须存在 constructor 函数,当 new 的时候 constructor 函数被触发,该方法默认返回实例对象(this)
- 除了 constructor 函数之外的函数都相当于公有方法
- 类 完全可以看作构造函数的另一种写法
- 实例的属性除非显式定义在其本身(this) 否则都是定义在原型上
- get 和 set 关键字
let _color = "red";
class Point {
// z = 50; // 属性的新写法 想到与字constructor内 this.z=50
constructor(x, y) {
this.x = x;
this.y = y;
console.log("constructor 执行了"); // 下面 出现 new 的时后 输出
}
// get color 属性定义初始值
get color() {
return _color;
}
// set 给 color 属性设置值,该函数会在修改 color 属性时触发
set color(new_value) {
_color = new_value;
}
toString() {
return `(${this.x},${this.y})`;
}
// 静态方法
// 只有类本身可以访问,不会生成到类的实力上,只能通过类访问
static sayHello() {
console.log("hello");
}
}
let p = new Point(1, 2);
console.log(p); // Point {x: 1, y: 2}
console.log(p.toString()); //(1,2)
typeof Point; // "function"
Point === Point.prototype.constructor; // true
// 给类添加新的方法:
Point.prototype.say = function () {
console.log("我是坐标"); // 我是坐标
};
p.say();
// Point {x: 1, y: 2}
// color: "red"
// x: 1
// y: 2
p.color = "blue";
console.log(p.color); // blue
// Point {x: 1, y: 2}
// color: "blue"
// x: 1
// y: 2
// p.sayHello(); // p.sayHello is not a function
Point.sayHello(); // hello
class 的继承
类的继承使用关键字 extends
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
sayPoint() {
console.log(`我是坐标(${this.x},${this.y})`);
}
}
let p = new Point(100, 20);
console.log(p); // Point {x: 100, y: 20}
p.sayPoint(); // 我是坐标(100,20)
class ColorPoint extends Point {
// 需要继承 Point 内的所有内容
// color = "red";
// 上面是默认的 color 下面传参 color
constructor(x, y, color) {
// 当继承的类内部创建了 constructor 函数,那么该函数内部必须使用 super 方法调用父类的 constructor
super(x, y);
this.color = color;
}
}
let colorP = new ColorPoint(100, 200, "red");
console.log(colorP); // ColorPoint {x: 100, y: 200, color: "red"}
colorP.sayPoint(); // 我是坐标(100,200)
Module 模块
ES6 模块是通过 export
命令显式指定输出的代码,再通过 import
命令输入。
模块简单理解就是在一个 js 内部可以引用另外一个 js 的内容。
// 模块 es6.js
export var firstName = "Michael";
export var lastName = "jackson";
export var year = 1958;
// index.js 使用模块内容
import { firstName } from "./js/es6.js";
console.log(firstName); // Cannot use import statement outside a module
// 直接这样用浏览器并不支持,需要运行在 node 环境中,或者通过 wabpack 编译
Windows10 安装 Node.js
-
进入 Node 官网下载安装包(nodejs.org/zh-cn/) 建议下载长期支持版
-
双击打开安装,直接下一步至安装完毕就可以,无需修改, win10 会自动加入环境变量
-
安装完成后打开命令行工具
-
命令输入
node -v
显示 node 版本号即安装成功
打包编译
- 打包工具 webpack
- 使用 npm 下载
- npm 设置国内淘宝镜像,命令行输入
npm config set registry https://registry.npm.taobao.org
- npm 显示安装进度,命令行输入
npm config set loglevel=http
- 在需要编译的项目文件夹,新建 webpack 存放文件夹,在这个文件夹下打开命令行工具执行:
npm init -y
完成之后会在文件夹生成 package.json 文件。 该命令的作用是将这个文件夹变成 node 项目,从而可以让这个项目使用 npm 下载对应的包- 安装 webpack 执行
npm install webpack webpack-cli --save-dev
完成后文件夹内出现 node_modules 文件夹和 package-lock.json 文件 - 在项目的根目录下新建
index.html
src/index.js
a.js
在 a.js 内写一些 es6 模块代码(导出变量)
// a.js // 模块导出了一个变量 firstName export var firstName = "zhang";
- 在 index.js 导入
// index.js // 导入 a.js 模块导出的变量 // 当导入模块的时候,如果模块是 js 文件可省略后缀 import { firstName } from "./a"; console.log(firstName);
- 接下来,命令行工具执行
npx webpack
,该命令的默认作用是将项目下的 src 文件夹下的 index.js 打包编译到dist
下的main.js
,然后 index.html 引入打包好之后的 js 文件,在浏览器中查看 - 如果
更改了 index.js 以及 a.js
需要重新执行npx webpack
模块的导出和导入
-
命名导出 关键字 export 可以导出多次(可使用多次 export)
export var firstName = "zhang"; let lastName = "san"; // export { lastName }; export { lastName as laName }; // 导出换名 lastName=>laName
let a = 10; let b = 20; let c = 30; export { a, b, c };
-
命名导入 导入的名称和导出的名称必须一致
import { firstName, laName } from "./a"; console.log(firstName, laName); // zhang san
// * 表示导出的所有 | as 是换名字 import * as all from "./a"; console.log(all.a); // 10 console.log(all.b); // 20 console.log(all.c); // 30
-
默认导出 关键字 export default 只能使用一次
let a = 10; let b = 20; let c = 30; export { a, b, c }; export default d;
-
默认导入 导入的时候随意命名
// * 包含所有(命名导出和默认导出) import * as all from "./a"; import x from "./a"; console.log(all.a); // 10 console.log(all.b); // 20 console.log(all.c); // 30 console.log(all.default); // 10000 console.log(x); // 10000
-
es6 模块全部由独立作用域 任何导入形式都会执行导入的 js
// b.js let add = (a, b) => a + b; let res = add(1, 2); console.log(res);
// 导入 b.js // 只是执行了 b.js 拿不到里面任何变量 import "./b"; // b.js 内 console.log(res) 执行 console.log(add); // add is not defined