块级作用域
使用var定义的变量只有全局作用域和函数作用域,块级作用域需要使用let定义变量
一对{},就是一个块级作用域,块级作用域中的变量只在当前{}中生效
// if的花括号内部是块级作用域
if (0 == 0) {
let a = 0
var b = 0
}
console.log(a); // 报错,未声明
console.log(b); // 0
// for的花括号内部是块级作用域
for (let i = 0; i < 10; i++) {
let j = 0
}
console.log(i);// 报错,未声明
console.log(j);// 报错,未声明
// 只要是花括号内部都是块级作用域
{
let c = 0
}
console.log(c);// 报错,未声明
var / let / const 区别
- 块级作用域: 变量{}内部可用,es6新增
- var定义变量: 只有全局作用域和函数作用域,可以重复定义,会声明提前
- let定义变量: 有函数作用域,全局作用域和块级作用域,不可以重复定义,会声明提前(到暂存死区,不可以使用)
- const定义变量: 有函数作用域,全局作用域和块级作用域,不可以重复定义,定义后不可以修改,会声明提前(到暂存死区,不可以使用)
var a = 1;
console.log(a);
function fun() {
a = 2;
console.log(a);
}
fun();
{
let b = 0;
// 重复定义会报错
let b = 1;
}
// 在花括号外访问会报错
console.log(b);
{
const c = 0;
// 修改变量会报错
c = 1;
}
// 在花括号外访问会报错
console.log(c);
解构
解构赋值语法是一种JavaScript表达式. 通过解构赋值,可以将属性/值从对象/数组中取出,赋值给其他变量
结构数组
var foo = ["one", "two", "three"];
var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
忽略某些值
var [a, , b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 3
将剩余数组赋值给一个变量
var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
默认值
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
解构对象
属性名当变量名
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true
给新变量名赋值
var obj = { x: 1, y: 2, z: 3 };
var { x: a, y: b, z: c } = obj;
console.log(a, b, c);//1,2,3
默认值
var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5
给新的变量命名并提供默认值
var {a:aa = 10, b:bb = 5} = {a: 3};
console.log(aa); // 3
console.log(bb); // 5
复杂结构
var obj = {
skills: ["html", "css", "js"],
game: {
name: "红川仙子",
price: 90,
},
};
var {
skills: [skill1, skill2, skill3],
game: { name: gname, price },
} = obj;
console.log(skill1, skill2, skill3, gname, price);
展开
展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开
数组展开
function myFunction(x, y, z) {
console.log(x,y,z);
}
var args = [0, 1, 2];
myFunction(...args);
function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
对象展开
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }
参数增强
默认值
调用函数时,即使不传入实参值,形参变量也有默认值可用,不至于是undefined
function fun1(a, b, c = 0) {
console.log(a, b, c);
}
fun1(1, 2);
剩余参数(rest)
ES6箭头函数中碰到参数个数不确定的情况,都要用剩余参数语法来代替arguments(箭头函数不能使用)
只要使用arguments,都换成剩余参数语法!
function fun(...arr) {
console.log(arr);
};
fun(100, 200, 300, 400);
...
在定义函数时的意思是收集
2.优点:
1). 支持箭头函数
2). 生成的数组是纯正的数组类型,可以使用数组家所有函数
3). 自定义数组名,比arguments简单
3. ...
可以和其它形参配合使用
只获得其它形参不要的剩余参数。
实参值1,实参值2,除实参值1、2之外其余实参
...数组名
收集的是除了前两个形参变量对应的实参值之外的剩余实参值
function fun(a,...arr) {
console.log(a,arr);
};
fun(100, 200, 300, 400);
参数与结构结合使用
function fun1([a, b]) {
console.log(a, b);
};
fun1([1, 2]);
function fun2({ a, b = 2 }) {
console.log(a, b);
};
fun2({ a: 1});
function fun3({ a: aa, b: bb }) {
console.log(aa, bb);
};
fun3({ a: 1, b: 2 });
箭头函数
函数表达式的简化写法,没有this、arguments、不能当做构造函数
箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数
// 简化前
var fun = function () {
console.log('fun');
};
// 简化后
var fun = () => {
console.log('fun');
}
// 简化前
var fun = function (a) {
console.log(a);
};
// 简化后
var fun = a => {
console.log(a);
}
// 简化前
var fun = function (a) {
return a;
};
// 简化后
var fun = a => a;
// 只有一个参数,函数体内有且仅有一句return时
箭头函数中的this指向定义时上层作用域中的this
Class
class本质构造函数和原型的语法糖写法
class
构造函数和原型写法
// 函数写法
function Emp(ename) {
this.ename = ename
}
Emp.prototype.work = function () {
console.log(`I'm ${this.name}`);
}
let emp1 = new Emp('胡桃')
console.log(emp1); //{ename:'胡桃'}
// class写法
class Empolyee {
constructor(ename) {
this.ename = ename
}
work() {
console.log(`I'm ${this.name}`);
}
}
let xdd = new Emp('小叮当')
console.log(xdd); //{ename: '小叮当'}
extends和super
构造函数和原型写法
function Emp(ename) {
this.ename = ename;
}
Emp.prototype.work = function () {
console.log(`I'm ${this.ename}`)
}
function Programmer(ename, skill) {
Emp.call(this, ename);
this.skill = skill;
}
Programmer.prototype.work = function () {
Emp.prototype.work.call(this);
console.log(`我会:${this.skill}`);
}
Object.setPrototypeOf(Programmer.prototype, Emp.prototype);
var ph = new Programmer("胖虎", "JS");
ph.work();
console.log(ph);
extends和super写法
extends:继承父类
super:父类
多态:子类重写父类方法,重写后,调用时可以出现不同的状态
class Emp {
constructor(ename) {
this.ename = ename;
}
work() {
console.log(`I'm ${this.ename}`)
}
}
// 继承父类
class Programmer extends Emp {
constructor(ename, skill) {
//调用父类构造函数
super(ename);
this.skill = skill;
}
//重写work方法
work() {
//调用父类方法
super.work();
console.log(`我会:${this.skill}`);
}
}
var ph = new Programmer("胖虎", "JS");
ph.work();
console.log(ph);
get和set
class Emp {
constructor(ename, eage) {
this.ename = ename;
this.eage = eage;
Object.defineProperty(this, "_eage", {
writable: true,
enumerable: false,
configurable: false
})
}
//eage访问器
get eage() {
console.log('get->eage');
return this._eage;
}
set eage(value) {
if (value >= 1 && value <= 10) {
this._eage = value;
} else {
throw Error("年龄必须介于1~10之间")
}
}
work() {
console.log(`I'm ${this.ename}`)
}
}
var ph = new Emp("胖虎", 5);
console.log(ph);
console.log(ph.eage);
ph.eage = 12;
static
function Emp(ename) {
this.ename = ename;
}
Emp.lazy = function () {
console.log(`I'm lazy`)
}
Emp.lazy();
class Emp {
constructor(ename) {
this.ename = ename;
}
static lazy() {
console.log(`I'm lazy`)
}
}
Emp.lazy();
Promise
回调地狱
多层回调函数嵌套,使代码的可读性、可维护性极差
function GetOne(next) {
setTimeout(function () {
console.log('1->ok');
next();
}, 2000);
}
function GetTwo(next) {
setTimeout(function () {
console.log('2->ok');
next();
}, 2000);
}
function GetThree(next) {
setTimeout(function () {
console.log('3->ok');
}, 2000);
}
GetOne(
function () {
GetTwo(
function () {
GetThree()
}
)
}
);
Promise
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值
它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来
这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个promise,以便在未来某个时候把值交给使用者
一个 Promise 必然处于以下几种状态之一:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝
- 已兑现(fulfilled): 意味着操作成功完成
- 已拒绝(rejected): 意味着操作失败
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用
function GetOne() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('1->ok')
} else {
reject('1->error');
}
}, 3000);
})
}
function GetTwo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('2->ok')
} else {
reject('2->error');
}
}, 2000);
})
}
function GetThree() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('3->ok')
} else {
reject('3->error');
}
}, 1000);
})
}
GetOne()
.then(res => { console.log(res); return GetTwo(); })
.then(res => { console.log(res); return GetThree(); })
.then(res => { console.log(res); })
.catch(err => { console.log(err); });
Promise.all()
Promise.all()将多个 Promise包装成一个新的 Promise
var GetOne = new Promise(function (resolve, reject) {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('1->ok')
} else {
reject('1->error');
}
}, 1000);
});
var GetTwo = new Promise(function (resolve, reject) {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('2->ok')
} else {
reject('2->error');
}
}, 1000);
});
var GetThree = new Promise(function (resolve, reject) {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('3->ok')
} else {
reject('3->error');
}
}, 1000);
});
GetOne.then(res => console.log(res))
GetTwo.then(res => console.log(res))
GetThree.then(res => console.log(res))
Promise.all([GetOne, GetTwo, GetThree])
.then((res) => { console.log(`res=>${res}`) })
.catch((err) => { console.log(`err=>${err}`) });
async 函数
async函数返回一个Promise对象,可以使用then方法添加回调函数
async function testAsync() {
console.log("----testAsync----");
if (1 == 0) {
throw new Error("error");
} else {
return "hello async";
}
}
const result = testAsync();
console.log(result);
testAsync()
.then((res) => {
console.log(`res=>${res}`);
}) // 输出 hello async
.catch((err) => {
console.log(`err=>${err}`);
});
await 等待一个Promise对象,它只能在异步函数async function内部使用
function testAwait() {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log("testAwait");
resolve('ok');
}, 3000);
});
}
async function helloAsync() {
let res = await testAwait();
console.log('helloAsync');
return res;
}
helloAsync().then((res) => console.log(res));
错误处理使用try...catch...
function testAwait() {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (Math.random() < 0.3) {
console.log('testAwait');
resolve('ok');
} else {
reject('error');
}
}, 3000);
});
}
async function helloAsync() {
try {
let res = await testAwait();
console.log('helloAsync');
return res;
} catch (err) {
console.log(`res=>${err}`);
throw new Error('出错了');
}
}
helloAsync();
多个async、await
function GetOne() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('1->ok')
} else {
reject('1->error');
}
}, 3000);
})
}
function GetTwo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('2->ok')
} else {
reject('2->error');
}
}, 2000);
})
}
function GetThree() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.6) {
resolve('3->ok')
} else {
reject('3->error');
}
}, 1000);
})
}
async function GetAll() {
try {
let resOne = await GetOne();
console.log(resOne);
let resTwo = await GetTwo();
console.log(resTwo);
let resThree = await GetThree();
console.log(resThree);
} catch (error) {
console.log(error)
}
}
GetAll();