(一)块级作用域
1. 块级作用域
{
var name = 'why';
console.log(name);
}
console.log(name);
2. 没有块级作用域引起的问题
ES5之前因为If和for都没有块级作用域的概念,所以在很多时候,我们都必须结束语function的作用域来解决应用外面变量的问题
2.1 没有块级作用域引起的问题:iif的块级
var func;
if(true){
var name = 'why';
func = function(){
console.log(name);
}
}
name = 'kobe';
func();
2.2 没有块级作用域引起的问题:ifor的块级
①ES5中的var是没有块级作用域的
var btns = document.getElementsByTagName('button');
for(var i=0 ; i<btns.length ; i++){
btns[i].onclick = function(){
console.log('第' + i + '按钮被点击');
}
// btns[i].addEventListener('click',function(){
// // addEventListener是谷歌dom2级事件写法,相当于onclick
// console.log('第' + i + '按钮被点击');
// })
}
② 可以使用闭包解决问题:函数是一个作用域
var btns = document.getElementsByTagName('button');
for(var i=0 ; i<btns.length ; i++){
(function(num){
btns[i].onclick = function(){
console.log('第' + num + '按钮被点击');
}
})(i)
③ ES6中,加入了let,let他是有if和for的块级作用域
const btns = document.getElementsByTagName('button');
for(let i=0 ; i<btns.length ; i++){
btns[i].onclick = function(){
console.log('第' + i + '按钮被点击');
}
}
(二) let/var
1. 事实上var的设计可以看成JavaScript语言设计上的错误,但是这种错误多半不能修复和移除,以为需要向后兼容
①Brendan Eich就决定修复这个问题,于是他新加了一个关键字:let
2. 块级作用域
①JS中使用var来声明一个变量是,变量的作用域主要是和函数的定义有关
②针对于其他块定义来说是没有作用域的,比如if/for等,这在开发中往往会引起一些问题
(三) const的使用
建议:在开发中,优先使用const,只有需要改变某一个标识符的时候才使用let
1. const关键字
①在很多语言中已经存在,比如C/C++中,主要的作用是将某个变量修饰为常量
②在JavaScript中也是如此,使用const修饰的标识符为常量,不可再次赋值。
2. 什么时候使用const
当修饰符不会被再次赋值时,就可以使用const来保证数据的安全性
3. const的注意
①注意一:一旦给const修饰的标识符被赋值后,不能修改
const a = 20;
a = 30; //错误,不可以修改
②注意二:使用const定义标识符,必须进行赋值
const name; //错误:const修饰的标识符必须赋值
③注意三:常量的含义是指指向的对象(指针不能修改)不能修改,但是可以改变对象内部的属性
const obj = {
name: 'yyy',
age: 18,
height:50
}
obj.age = 40;
(四)ES6对象增强写法
1. ES6中,对对象字面量进行了很多增强
2. 属性初始化简写和方法的简写:
(五)箭头函数的使用和this指向
箭头函数中的this引用的是最近作用域中的this,
箭头函数中的this如何查找:向外层作用域中一层一层查找this,直到有this的定义
const obj = {
aaa() {
setTimeout(function () {
console.log(this) //window
})
setTimeout(() => {
console.log(this) //obj对象
})
}
}
obj.aaa();
例子:
const obj2 = {
ccc() {
setTimeout(function () {
setTimeout(function () {
console.log(this) //window
})
setTimeout(() => {
console.log(this) //window
})
})
setTimeout(() => {
setTimeout(function () {
console.log(this) //window
})
setTimeout(() => {
console.log(this) //obj
})
})
}
}
obj2.ccc()
(六)Promise
1. Promise的介绍和基本使用
1.1 什么是Promise
(1)ES6中一个非常重要和好用的特性就是Promise
但是初次接触Promise会一脸懵逼,这TM是什么东西?
看看官方或者一些文章对它的介绍和用法,也是一头雾水。
(2)Promise到底是做什么的呢?
Promise是异步编程的一种解决方案
(3)那什么时候我们会来处理异步事件呢?
一种很常见的场景应该就是网络请求了
我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样将结果返回
所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去。
如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦。但是,当网络请求非常复杂时,就会出现回调地狱。
口OK,我以一个非常夸张的案例来说明。
1.2 定时器的异步事件
我们先来看看Promise最基本的语法。
这里,我们用一个定时器来模拟异步事件:
假设下面的data是从网络上1秒后请求的数据
console.log就是我们的处理方式2. Promise的三种状态和另外处理方式
// 使用setTimeout
// setTimeout(() => {
// console.log("Hello World")
// },2000)
// 参数 -> 函数(resolve,reject)
// resolve,reject 他们本身又是函数
new Promise((resolve,reject) => {
// 异步操作,第一次网络请求的代码
setTimeout(() => {
reslove()
},2000)
}).then(() => {
// 第一次拿到结果的处理代码
console.log("Hello World");
return new Promise((resolve,reject) => {
// 第二次网络请求的代码
setTimeout(() => {
resolve()
},2000)
})
}).then(() => {
// 第二次拿到结果的处理代码
console.log("Hello Vue.js");
return new Promise((resolve,reject) => {
// 第三次网络请求的代码
setTimeout(() => {
resolve()
},2000)
})
}).then(() => {
// 第三次拿到结果的处理代码
console.log("Hello Python);
})
1.3 Promise 的使用
// 什么情况下用到Promise
// 一般是有异步操作时,使用Promise对异步进行封装
// new -> 构造函数(1.保存了一些状态信息 2.执行传入的函数)
// 在执行传入的回调函数时,会传入两个参数,resolve,reject:本身又是函数
new Promise((resolve,reject) => {
setTimeout(() => {
// 成功时调用resolve
// resolve(data)
// resolve("Hello World")
// 失败时调用reject
reject('error message')
},1000)
}).then((data) => {
// 处理代码
console.log(data);
}).catch(err => { //箭头函数只有一个参数,()可以省略
console.log(err);
})
2. Promise的三种状态
首先,当我们开发中有异步操作时,就可以给异步操作包装一个Promise
异步操作之后会有三种状态
我们一起来看一下这三种状态:
pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。
fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
new Promise((resolve,reject) => {
setTimeout(() => {
// resolve("Hello World")
reject('error message')
},1000)
}).then((data) => {
// 处理代码
console.log(data);
}).catch(err => {
console.log(err);
})
// promise的另外处理形式
new Promise((resolve,reject) => {
setTimeout(() => {
// resolve("Hello World")
reject("error message")
},1000)
}).then(data => {
console.log(data);
},err => {
console.log(err);
})
3.Promise的链式调用
我们在看Promise的流程图时,发现无论是then还是catch都可以返回一个Promise对象。
所以,我们的代码其实是可以进行链式调用的:
这里我们直接通过Promise包装了一下新的数据,将Promise对象返回了
Promise.resovle0:将数据包装成Promise对象,并且在内部回调resolve0函数
Promise.reject0:将数据包装成Promise对象,并且在内部回调reject0函数
new Promise((resolve,reject) => {
setTimeout(() => {
resolve("aaa")
},1000)
}).then(res => {
// 自己处理
console.log(res,"第一层的10行处理代码");
// 对结果 进行第一次处理
return new Promise((resolve,reject) => {
// resolve(res + "111")
reject("error")
})
}).then(res => {
console.log(res,"第二层的10行处理代码")
return new Promise((resolve) => {
resolve(res + "222")
})
}).then(res => {
console.log(res,"第三层的10行处理代码")
}).catch(err => {
console.log(err);
})
new Promise(resolve => resolve(结果)) 简写
new Promise((resolve,reject) => {
setTimeout(() => {
resolve("aaa")
},1000)
}).then(res => {
// 自己处理
console.log(res,"第一层的10行处理代码");
// 对结果 进行第一次处理
// return Promise.reject("error message")
throw "error message" //手动抛出异常
}).then(res => {
console.log(res,"第二层的10行处理代码")
return Promise.resolve(res + "222")
}).then(res => {
console.log(res,"第三层的10行处理代码")
}).catch(err => {
console.log(err);
})
省略掉Promise.resolve
new Promise((resolve,reject) => {
setTimeout(() => {
resolve("aaa")
},1000)
}).then(res => {
// 自己处理
console.log(res,"第一层的10行处理代码");
// 对结果 进行第一次处理
return res + "111"
}).then(res => {
console.log(res,"第二层的10行处理代码")
return res + "222"
}).then(res => {
console.log(res,"第三层的10行处理代码")
})
4. Promise的all方法使用
某个需求需要发送两次请求:
普通方式
let isResult1 = false
let isResult2 = false
// 请求1:
$ajax({
url:'',
success:function () {
console.log('结果1');
isResult1 = true
handleResult()
}
})
// 请求2:
$ajax({
url:'',
success:function () {
console.log('结果2');
isResult2 = true
handleResult()
}
})
function handleResult() {
if (isResult1 && isResult2){
}
}
用Promise的all方法包装两个异步请求:
Promise.all([ //[]数组
new Promise((resolve,reject) => {
$ajax({
url:'url1',
success:function (data) {
resolve(data)
}
})
}),
new Promise((resolve,reject) => {
$ajax({
url:'url2',
success:function (data) {
resolve(data)
}
})
})
]).then(results => { //results数组
console.log(results)
})
用setTimeout模拟网络请求示例:
Promise.all([ //[]数组
// 用setTimeout模拟网络请求
new Promise((resolve,reject) => {
setTimeout(() => {
resolve({name:'yyy',age:18})
},1000)
}),
new Promise((resolve,reject) => {
setTimeout(() => {
resolve('result2')
},2000)
})
]).then(results => { //results数组
console.log(results)
})