JavaScript进阶
循环语句
-
for循环// 类似python中的for i in range(20) for(let i=0; i<20; i++){ console.log(i) } -
while循环const MAX_TIMES = 20; let cur = 0 while (cur < MAX_TIMES){ cur++; console.log(cur) } -
do whiledo { cur ++; console.log(cur); }while (cur < MAX_TIMES)-
和
while循环有什么区别?do while一定先执行一遍代码块的表达式;
-
-
for in遍历对象的属性
let myObj = {a: 1, b:2, c:3, d:4} for (let e in myObj){ console.log(e, myObj[e]); } -
for of遍历可迭代对象的元素
let myArray = [1, 2, 3, 4, 5] for (let e of myArray){ console.log(e); }-
常见的可迭代对象有哪些?
-
Array
-
Set
-
Map
-
String
-
arguments
function foo(a, b){ console.log(arguments); } foo(1, 2)
-
-
-
forEachlet myArray = [1, 2, 3, 4, 5] myArray.forEach(function (e){ console.log(e * e); })
条件语句
-
一个简单的判断语句
for(let i=0; i<100; i++){ if (i%2===0){ console.log("偶数", i) }else if(i < 0){ console.log("负数不判断") }else{ console.log("奇数", i) } } -
逻辑运算符
-
==对比操作数是否相同, 操作数会尝试进行类型转换后的比较, 不推荐做为比较符号.
'1' == 1 > true false == 0 > true -
===严格等于
'1' === 1 > false false === 0 > false -
!逻辑取反
for(let i=0; i<100; i++){ // 注意运算优先级的问题, 不能写成!i%2 if (!(i%2)){ console.log("偶数", i) }else if(i < 0){ console.log("负数不判断") }else{ console.log("奇数", i) } } -
&&和||&&表示AND||表示OR
-
选择语句
-
switch casefunction foo(arg){ switch (arg){ case 'a': console.log(arg, 1); break; case 'b': console.log(arg, 2); break; case 'c': console.log(arg, 3); break; default: console.log('default') } } foo('e')
异常处理
try{
表达式
}catch (e){
表达式
}finally{
表达式
}
-
一个基本的异常捕获
function foo(){ try{ throw TypeError('test'); }catch (e){ console.log('Error', e); }finally{ console.log('Done!') } } foo() -
处理具体的异常
处理具体的异常, 只能通过if条件语句来进行类型判断
function foo(){ try{ throw TypeError('test'); }catch (e){ if (e instanceof TypeError){ console.log("TypeError") }else{ console.log('Error', e); } }finally{ console.log('Done!') } } foo() -
抛出异常
throw可以抛出任意对象, 让catch去捕获function foo(){ try{ throw {'a':1}; }catch (e){ if (e instanceof TypeError){ console.log("TypeError") }else{ console.log('Error', e); } }finally{ console.log('Done!') } } foo()
对象和类
js当中其实没有明确的类的概念, js当中的类只是创建对象的模板. 它的本质还是一个特殊的函数
class关键字只是一层封装了原型链的语法糖, 但是方便我们理解.
-
声明类
class Rectangle { constructor(height, width) { this.name = 'ractangle'; this.height = height; this.width = width; } } -
创建对象/实例
let rectangle = new Rectangle(2, 5); console.log(rectangle) -
类方法
-
构造方法
constructor是一种用来创建和初始化class创建的对象; -
实例方法
class Rectangle { constructor(height, width) { this.name = 'ractangle'; this.height = height; this.width = width; } getArea(){ return this.height * this.width; } } -
静态方法
static staticMethod(){ console.log("calling static method") } -
getter和setterget area(){ return this.getArea() } set area(value){ this._value = value }
-
-
类继承
class Square extends Rectangle { constructor(a) { super(a, a); this.name = 'square' } } let suqare = new Square(10) console.log(suqare.area) -
私有方法和属性
通过
#来声明一个私有方法或者属性, 只允许类内部调用class Square extends Rectangle { // 私有属性需要事先进行声明 #new_name constructor(a) { super(a, a); this.#new_name = 'square' } get new_name(){ return this.#getName() } #getName(){ return this.#new_name } }
构造函数和this
在JS中通过构造函数来创建对象的场景更多, 而不是通过class
-
声明一个构造函数
function Rectangle(height, width){ this.name = 'rectangle'; this.width = width; this.height = height; this.getArea = function (){ return this.height * this.width } } -
创建对象/实例
let rectangle = new Rectangle(10, 2) console.log(rectangle.getArea()) -
通过
call方法继承第一个参数是要绑定的对象, 其他参数代表调用函数的参数.
call方法将Rectangle下的属性和方法绑定到this上去这里的this指代的就是实例化的square对象
function Square(a){ Rectangle.call(this, a, a); this.name = 'square' }-
apply
和
call方法几乎没有区别, 只是传入的参数的方式不同function Square(a){ Rectangle.apply(this, [a, a]); this.name = 'square' }
-
-
this
不能简单地认为
this指向的就是实例对象.可以简单地认为谁调用该函数,
this就指向谁.
原型链式继承
在传统面向对象编程中, 我们继承的实现方式都是在创建实例时, 将类中定义的属性和方法都复制到实例中去.
但是JS中继承是在对象/实例和它的构造器之间创立一个链接, 这个链接就是__proto__
-
原型链
在
js中每个构造函数拥有一个原型对象prototype, 对象从原型继承方法和属性. 而当前对象继承的原型对象可能也有原型, 这样就形成了一条原型链square.__proto__.__proto__.__proto__-
__proto__和prototype的区别?__proto__是每个对象/实例都有的属性, 而prototype只是构造函数的属性.
-
-
原型链式继承
当前对象/实例square找不到getArea方法时, 会继续在原型链中寻找.
function Square(a){ this.height = a; this.width = a; this.name = 'square' } Square.prototype = new Rectangle() let square = new Square(10) console.log(square.getArea())
异步JS
JS引擎只是浏览器中的一个线程, 所以在JS当中没有线程和进程的概念.JS的高性能是通过一个基于事件循环的异步并发模型来完成.
-
事件循环
在页面环境中, 我们移动鼠标, 点击页面元素或者执行一段JS, 都可以认为当前是一个消息. 当前的消息会被丢进一个无限循环的消息队列当中, 每一个消息都关联着用来处理这个消息的回调函数
document.addEventListener("click", function(e){console.log(e)})-
事件循环的伪代码
while(queue.waitForMessage()){ queue.processNextMessage(); } -
消息的执行
- JS在执行同步消息任务时, 会执行至完成.
- JS在执行异步消息任务时, 遇到异步操作, 会将该消息丢回消息队列, 等待下一次调度执行.
-
callbacks(异步回调)
最常见于浏览器的监听事件, 本质就是将回调函数做为参数传递给后台执行的其他函数, 其他函数在执行完毕后自动调用回调函数
document.addEventListener("click", function(e){console.log(e)})
-
回调地狱
// 银行转账的伪代码 transferAccount(cash, dealCash(cash, function(cash_status){ authAccount(cash_status, function(order){ transferStart(order, function(status){ sendSMS(status) }, transferExceptionCallback) }, authExceptionCallback) }, cashExceptionCallback) )
Promise
Promise是一个对象, 它代表了一个异步操作的最终完成或者失败的结果.

-
声明一个简单的
promise对象let promiseOjb = new Promise((resolve, reject) => { setTimeout(() => { resolve("success"); reject("failed"); }, 3*1000) }).then(result => {console.log("result => ", result)}) console.log(promiseOjb) -
promise的状态-
pending
初始状态, 表示未接收到结果
-
fullfill
已兑现, 表示操作成功完成
-
reject
已拒绝, 表示操作失败
-
-
在使用
promise时, 需要注意以下约定- 回调函数时在当前事件循环结束后自动调用的;
- 通过
then添加的回调函数不管异步操作是否成功都会执行; - 通过调用多次
then可以添加多个回调函数, 他们按插入顺序依次执行, 这个方式就叫做链式调用;
-
在
promise中处理异常-
声明一个简单的xhr请求
function xhrRequest(url){ return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function(){resolve(xhr.responseText)}; xhr.onerror = () => reject(xhr.status); xhr.send() }).then(result=>{console.log("SUCCESS", result)}) .catch(error=>{console.log("FAILURE", error)}) } xhrRequest("http://www.baidu.com") xhrRequest("https://www.baidu.com") xhrRequest("https://www.baidu.com/asdfasdf/")- 当前环境下, 客户端请求到达了服务端, 服务端也正常地返回了结果. 那么不管状态码是200还是404, 都算是一次成功的请求, 所以结果由
then回调进行处理, 而不是catch. 如果有需要可以自己通过状态码判断后执行不同的流程.
- 当前环境下, 客户端请求到达了服务端, 服务端也正常地返回了结果. 那么不管状态码是200还是404, 都算是一次成功的请求, 所以结果由
-
链式调用
function xhrRequest(url){ return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function(){resolve(xhr.responseText)}; xhr.onerror = () => reject(xhr.status); xhr.send() }).then(result=>{console.log("SUCCESS", result); return result}) .then(result=>{console.log("SUCCES 2", result)}) .catch(error=>{console.log("FAILURE", error)}) }- 不管当前链式调用有多长, 异常都会进到
catch回调函数当中.catch也可以进行链式调用, 但是一般一个函数只有一个catch回调函数.
- 不管当前链式调用有多长, 异常都会进到
-
async/await
async本质就是将函数转换为promise
-
通过
async和await等待完成结果function xhrRequest(url){ return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function(){resolve(xhr.responseText)}; xhr.onerror = () => reject(xhr.status); xhr.send() }) } async function requestBaidu(url){ let result = await xhrRequest(url); console.log("DONE!", result) } -
异常处理
function xhrRequest(url){ return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function(){resolve(xhr.responseText)}; xhr.onerror = () => reject(xhr.status); xhr.send() }) } async function requestBaidu(url){ try{ let result = await xhrRequest(url); console.log("DONE!", result) }catch (e){ console.log("FAILURE", e) } }



















