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 while
do {
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)
forEach
let 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||
表示ORswitch case
function 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
和setter
get 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
}
}
在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, 都可以认为当前是一个消息. 当前的消息会被丢进一个无限循环的消息队列当中, 每一个消息都关联着用来处理这个消息的回调函数
document.addEventListener("click", function(e){console.log(e)})
事件循环的伪代码
while(queue.waitForMessage()){
queue.processNextMessage();
}
消息的执行
最常见于浏览器的监听事件, 本质就是将回调函数做为参数传递给后台执行的其他函数, 其他函数在执行完毕后自动调用回调函数
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
对象
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/")
then
回调进行处理, 而不是catch
. 如果有需要可以自己通过状态码判断后执行不同的流程.链式调用
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
本质就是将函数转换为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)
}
}