您的位置:首页 > 文旅 > 旅游 > 前端——JS基础

前端——JS基础

2025/1/8 18:55:02 来源:https://blog.csdn.net/m0_73557953/article/details/142186735  浏览:    关键词:前端——JS基础
字符串
函数
判断语句
对象
数组
字符串、数字对象
循环
类和继承

类的定义和实例化

// 定义类
class Car {    type = '汽车' //知道的属性hasTire = trueconstructor(price, owner) {//构造函数;不知道的属性,需要参数传进来this.price = pricethis.owner = owner}showInfo(){//类的方法;类里面定义的函数(包括constructor)可以叫类的方法,都不需要function关键字声明console.log(`车型 :${this.type} -  车主 : ${this.owner} - 售价 : ${this.price} `)}
}   // 创建实例对象
var myCar1 = new Car(300000, '白月黑羽')
var myCar2 = new Car(350000, '白月黑羽')console.log(myCar1.type, myCar1.hasTire,myCar1.price,myCar1.owner)
console.log(myCar2.type, myCar2.hasTire,myCar2.price,myCar2.owner)myCar1.showInfo()
myCar2.showInfo()
instanceof关键字

用于判断前面的对象是否为后面对象的一个具体实例

extend关键字

类的继承,🔺js中子类会自动拥有父类的一切属性和方法

super关键字 

当子类的 初始化代码 有一部分和父类相同,这时就可以用super(注意是初始化代码)直接调用父类的constructor代码

class Car {    type = '汽车'hasTire = trueconstructor(price, owner) {this.price = pricethis.owner = owner}showInfo(){console.log(`车型 :${this.type} -  车主 : ${this.owner} - 售价 : ${this.price} `)}
}class ElectricCar extends Car {static type = '电动车'static hasBattery = truestatic hasEngine  = falseconstructor(price, owner, batteryCap) {// 调用父类的构造函数super(price, owner)this.batteryCap = batteryCap}}

当然super不仅可以调用父类的构造函数方法,也可以调用父类的其他方法

class Car {    type = '汽车'hasTire = trueconstructor(price, owner) {this.price = pricethis.owner = owner}showInfo(){console.log(`车型 :${this.type} -  车主 : ${this.owner} - 售价 : ${this.price} `)}
}class ElectricCar extends Car {type = '电动车'hasBattery = truehasEngine  = falseconstructor(price, owner, batteryCap) {// 调用父类的构造函数super(price, owner)this.batteryCap = batteryCap}showInfo(){super.showInfo()console.log(`电池容量 :${this.batteryCap}`)}}var myCar1 = new ElectricCar(300000, '白月黑羽', 200)
myCar1.showInfo()
错误捕获
抛出错误 —— 关键字throw

关键字throw后需要跟一个错误对象

var miles,fmiles,km
miles = prompt('请输入英里数:')
fmiles = parseFloat(miles)
if(isNaN(fmiles))//这里是直接使用Error构造函数创建了一个新对象;Error构造函数的参数会作为error对象的message属性,用来描述此处具体的错误信息,比如原因。执行完throw抛出异常的代码后,后续的代码不会再执行throw new Error('输入的必须是数字')
km = fmiles * 1.6
console.log(`${miles} 英里等于 ${km}公里`)

throw 抛出的不一定非得是Error类型的对象,也可以是TypeError,Error类型的子对象 ,也可以是自定义的对象

if (isNaN(fmiles))throw {code : 401,info : '输入的必须是数字'}
捕获错误 —— try ... catch ...

在编码时,预料到了某些代码在运行时可能会出现某些错误,如果这些错误不至于必须结束程序,就可以使用try ... catch ...

正常情况下:

var stockTable = {sh : {华远地产 : '600743',中天科技 : '600522',},sz : {深南股份 : '002417',中兴通讯 : '000063',},
}
while(true){ let input = prompt('请输入股市代码-股票进行查询:')let [stock, corp] = input.split('-')let code = stockTable[stock][corp]console.log(`${stock} ${corp} 股票代码是 ${code}`)
}

捕获错误:

while (true){ let input = prompt('请输入股市代码-股票进行查询:')try{if(input==='exit') breaklet [stock, corp] = input.split('-')let code = stockTable[stock][corp]console.log(`${stock} ${corp} 股票代码是 ${code}`)} catch (e){//一旦try里的代码执行错误,就会捕获这个错误,并执行catch里的代码;catch引导的代码段就是对错误 的一种处理;这里的e是错误对象console.log(e.name,e.message)   console.error('请输入有效的股市代码')   }
}

Case1.当预估某个代码段中可能出现好几种类型的错误,可以使用 instanceof 判定错误类型,并进行相应的处理。

myCar1 instanceof Car

=> true

判断前面对象是否为后面对象的一个具体实例 

while (true){ let input = prompt('请输入股市代码-股票进行查询:')try{if(input==='exit') breaklet [stock, corp] = input.split('-')let code = stockTable[stock][corp]console.log(`${stock} ${corp} 股票代码是 ${code}`)} catch (e){if (e instanceof TypeError) {console.error('请输入有效的股市代码')} else if (e instanceof RangeError) {console.error(e)}// 未知类型错误,继续抛出else {console.log('未知类型错误')throw e //在catch代码块中,如果发现当前代码没法处理这个异常,可以使用throw继续往上抛出}}
}

Case2.嵌套捕获

当内层代码抛出异常,优先会被内层的catch 捕获, 不会执行到外层的 catch 代码块中;当内层catch代码发现不适合处理,又 throw 抛出, 才会被外层的 catch 捕获进行处理。

try{var inNum = 401try {if (inNum === 401)throw {code : 401,info : '输入的是401!'}else throw {code : 500,info : '输入的是其它!'}} catch (e) {if (e.code === 401) console.log('401 错误处理')else {console.log('未知类型错误')throw e}}
}
catch (e) {console.log('处理内层代码不适合处理的错误')
}

Case3.在函数调用里面产生错误

优先使用当前函数里面捕获处理错误的 try catch ;如果没有捕获到(比如没有 try catch),就会把错误对象抛到 调用该函数的外层代码 处, 查看是否有相应的 try catch 

function throwError(inNum) {if (inNum === 401)throw {code : 401,info : '输入的是401!'}else throw {code : 500,info : '输入的是其它!'}
}try {//这行代码是被try catch保护处理的,异常会被捕获,所以函数里面抛出的异常,在函数外面的catch被捕获处理了throwError(401); // 500
} 
catch (e) {if (e.code === 401) {console.log('401 错误处理')} else {console.log('未知类型错误')throw e}
}
console.log('后续代码执行')
捕获错误 —— try ... catch ... finally

不管try里面有无错误抛出,都要执行finally代码块里的代码

特别是在没有catch的时候有用:

try {throw {code : 401,info : '输入的必须是数字'}
} 
finally {console.log('不管有无错误,都要做的处理')
}
console.log('后续代码')
3个点操作符

剩余参数:前有3个点的参数,称之为剩余参数

场景:实现一个printAge,它的参数是一些学生的姓名;这个函数需要打印这些输入的学生的年龄

常规做法:定义一个数组

var studentInfo = {'张飞' :  18,'赵云' :  17,'许褚' :  16,'典韦' :  18,'关羽' :  19,
}function  printAge(students){for (let student of students) {console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);}
}printAge(['张飞', '典韦', '关羽'])
printAge(['赵云'])

使用可变参数:

var studentInfo = {'张飞' :  18,'赵云' :  17,'许褚' :  16,'典韦' :  18,'关羽' :  19,
}function  printAge(...students){for (let student of students) {console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);}
}printAge('张飞', '典韦', '关羽')//执行函数时,js解释器创建一个数组赋值给这个students,里面存放了 '张飞', '典韦', '关羽' 三个字符串对象作为元素
printAge('赵云')

var studentInfo = {'张飞' :  18,'赵云' :  17,'许褚' :  16,'典韦' :  18,'关羽' :  19,
}function  printAge(...students){console.log(students)for (let student of students) {console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);}
}printAge('张飞', '典韦', '关羽')

运行结果

[ '张飞', '典韦', '关羽' ]
学生:张飞 , 年龄 18
学生:典韦 , 年龄 18
学生:关羽 , 年龄 19

注意:剩余参数往往不单独出现在函数参数中,通常和其他参数一起出现

var studentInfo = {'张飞' :  18,'赵云' :  17,'许褚' :  16,'典韦' :  18,'关羽' :  19,
}function  printAge(prefix, ...students){console.log(students)for (let student of students) {console.log(`${prefix} 学生:${student} , 年龄 ${studentInfo[student]}`);}
}printAge('-->', '张飞', '典韦', '关羽')//prefix固定参数,优先匹配,剩下的都是剩余参数的
printAge('==>', '张飞', '典韦', '关羽')

应用:

调用函数时

var onebatch = ['张飞', '典韦', '关羽']
printAge(...onebatch)//等价于printAge (onebatch[0], onebatch[1], onebatch[2])

构建新数组时

var batch1 = ['张飞', '典韦', '关羽']
var batch2 = [...batch1, '赵云', '马超']
console.log(batch2)

构建新对象

var studentInfo1 = {'张飞' :  18,'赵云' :  17,'许褚' :  16,'典韦' :  18,'关羽' :  19,
}var studentInfo2 = {...studentInfo1,'黄忠' :  78,'张辽' :  39,
}

注意一点:

1.在使用多次数据展开时,就比如在实现多个Object 的合并时,其中重复的数据会被后面的Object里面的值替换

var studentInfoAll = {...studentInfo1,...studentInfo2
}

 2.赋值1:studentInfoAll_clone1 只是对象的新变量名, 和 studentInfo 对应的是同一个数据对象;赋值2:studentInfoAll_clone2 对应的则是一个新的对象,里面是studentInfo里面的内容。

var studentInfo = {'黄忠' :  78,'张辽' :  39
}// 赋值1
var studentInfoAll_clone1 = studentInfo// 赋值2
var studentInfoAll_clone2 = { ...studentInfo}
回调函数
同步&异步

同步:一起走,等完成后再继续

import time
print('这里是等待2s前的代码')
time.sleep(2)//等待2s;一直在这儿等着
print('这里是等待2s后的代码')

异步:不搁这儿等着,继续往后执行,到2s后立即执行 taskAfter2Second

function taskAfter2Second(){console.log("这里是等待2s的后续代码");
}
setTimeout( taskAfter2Second , //要执行要回调函数的函数名2000 //2000毫秒,2s
)console.log("这里是等待2s的后续代码");
何为回调函数

先定义,等事情完成,回头再调用

回调函数中的this指代问题

首先前面说过:通过哪个对象调用了这个函数,函数里的this对应的就是这个对象

情景1:这里的this对应的就是car1

class Car {    constructor(price, owner) {this.price = pricethis.owner = owner}showInfo(){console.log(`车辆信息如下:`)console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)}}car1 = new Car(230000,'白月黑羽')
car1.showInfo()

情景2:这里的this对应的就是obj1

这里相当于给car1.showInfo又起了个anotherShowInfo

class Car {    constructor(price, owner) {this.price = pricethis.owner = owner}showInfo(){console.log(`车辆信息如下:`)console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)}}car1 = new Car(230000,'白月黑羽')let obj1 = {price: '3333',owner: '张三',anotherShowInfo : car1.showInfo
}obj1.anotherShowInfo()

情景3:这里的this对应的就是obj2;但输出的是undefinded,undefinded,因为obj2没有price、owner这俩属性

class Car {    constructor(price, owner) {this.price = pricethis.owner = owner}showInfo(){console.log(`车辆信息如下:`)console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)}}car1 = new Car(230000,'白月黑羽')let obj2 = {anotherShowInfo : car1.showInfo
}obj2.anotherShowInfo()

🔺情景4:这里的this对应的就是window;输出undefinded,undefinded

setTimeout这个函数是由js引擎实现的,由于它内部的回调函数function,调用时没有xxx.这样的前缀,js中调用函数没有前缀就等于是通过全局对象window调用。

而window没有price、owner这两个属性,所以都是undefinded。

class Car {    constructor(price, owner) {//构造函数this.price = pricethis.owner = owner}showInfo_Delay1Sec(){//this.owner 要是在这里this对应的就是car1//1s后通过回调函数打印this.owner和this.pricesetTimeout(function(){//console.log(this === window)console.log(`车辆信息如下:`)console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)},1000)}}car1 = new Car(230000,'白月黑羽')car1.showInfo_Delay1Sec()

如何解决回调函数中this对应的window而不是car1这样的问题呢

法一:设一个中间变量,保存this到其他变量比如self中

class Car {    constructor(price, owner) {//构造函数this.price = pricethis.owner = owner}showInfo_Delay1Sec(){let self = thissetTimeout(function(){console.log(`车辆信息如下:`)console.log(`车主 : ${self.owner} - 售价 : ${self.price} `)},1000)}}car1 = new Car(230000,'白月黑羽')
car1.showInfo_Delay1Sec()

法二:使用箭头函数

箭头函数中的this具有特殊性:即它对应的是 包含该箭头函数的函数 的执行环境

简单来说就是看 :=> 这个箭头函数出现在哪个函数定义里面

注意这里不是setTimeout,而是showInfo_Delay1Sec;它只是作为setTimeout这个函数的参数。

this关键字在方法中,那它对应的就是那个方法所属的对象

class Car {    constructor(price, owner) {//构造函数this.price = pricethis.owner = owner}showInfo_Delay1Sec(){setTimeout(()=>{console.log(`车辆信息如下:`)console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)},1000)}}car1 = new Car(230000,'白月黑羽')
car1.showInfo_Delay1Sec()

 若箭头函数没有包含函数,那么里面的this对应的就是全局对象,在浏览器中就是window

var price = 1000
var owner = '白月黑羽'setTimeout(()=>{ console.log(`车主 : ${this.owner} - 售价 : ${this.price} `)},1000
)
匿名函数

由于前面taskAfter2Second只被用1次,起名较为麻烦,所以引入匿名函数

上面代码可改为:

setTimeout( //直接定义函数,不用起名function(){console.log("这里是等待2s的后续代码");}2000 //2000毫秒,2s
)console.log("这里是等待2s的后续代码");
let add100 = function(a) { return a+100 ;}
箭头函数

eg. (a) => {return a+100 ;}

相当于把function换成了=>

注意两点:1.当箭头函数只有一个参数时,()也可省       a => {return a+100 ;}

                  2.当箭头函数体内只有一行代码且返回一个值时, {}、return均可省   a => a+100

通过结合前面的匿名函数和箭头函数对下面的代码进行简化

const array1 = [1,4,9,16];
function square(x) {return x**2}
const map1 = array1.map(square);
console.log(map1);
const array1 = [1,4,9,16];
console.log(array1.map(x => x**2));

本文参考自:Javascript 简介 - 白月黑羽 (byhy.net)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com