当前位置: 首页 > news >正文

前端——JS基础

定义变量:let / var

字符串

字符串拼接:+

字符串和数字拼:'您....' + 25 ; 这个25会转成字符串再拼接

字符串和数组拼:'10以内的质数有:' + [2,3,5,7]  => 10以内的质数有:2,3,5,7

字符串长度:length

str.length / '刘总你好'.length

函数

定义函数关键字:function

console.log(); //打印到界面上

指定缺省值:

function func (p1,p2 = '白月黑羽'){console.log('第1参是' + p1)console.log('第2参是' + p2)
}func(1)

变量的有效范围:

{} 代码块

const、let :只在代码块里有效

var:有效范围是代码块所在的区域

function run(){/*ccc整个函数内部有效*/{var ccc = 'hhhh'}console.log(ccc)
}
run()
/*函数外定义,全局有效*/
{var ccc = 'hhhh'}function run(){console.log(ccc)
}
run()

 

判断语句
对象
数组
字符串、数字对象
循环
类和继承

类的定义和实例化

// 定义类
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)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 第五章 继承、多态、抽象类与接口 (1)
  • 连续时间,离散频率 傅里叶
  • UVA-225 黄金图形 题解答案代码 算法竞赛入门经典第二版
  • Vue路由配置、网络请求访问框架项目、element组件介绍学习
  • 数据在内存中的存储方式
  • 测试-Gatling 与性能测试
  • 达梦数据库对象管理(一):分区表、外部表、临时表
  • Big Data 流处理框架 Flink
  • 【LeetCode】每日一题 2024_9_16 公交站间的距离(模拟)
  • 进程监控与管理详解
  • 华为HarmonyOS地图服务 -- 如何实现地图呈现?-- HarmonyOS自学8
  • Ubuntu24.04部署docker
  • xtu oj 锐角三角形
  • PowerShell install 一键部署Oracle23ai
  • js中【argument】知识点详解
  • [译]如何构建服务器端web组件,为何要构建?
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【笔记】你不知道的JS读书笔记——Promise
  • C++类中的特殊成员函数
  • Java,console输出实时的转向GUI textbox
  • java概述
  • JSDuck 与 AngularJS 融合技巧
  • laravel with 查询列表限制条数
  • Meteor的表单提交:Form
  • Next.js之基础概念(二)
  • ng6--错误信息小结(持续更新)
  • Python爬虫--- 1.3 BS4库的解析器
  • React Native移动开发实战-3-实现页面间的数据传递
  • 给Prometheus造假数据的方法
  • 诡异!React stopPropagation失灵
  • 技术:超级实用的电脑小技巧
  • 坑!为什么View.startAnimation不起作用?
  • 前端学习笔记之观察者模式
  • 驱动程序原理
  • 使用SAX解析XML
  • 微信小程序实战练习(仿五洲到家微信版)
  • 详解移动APP与web APP的区别
  • 硬币翻转问题,区间操作
  • 在Unity中实现一个简单的消息管理器
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • # include “ “ 和 # include < >两者的区别
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (六)激光线扫描-三维重建
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十六)Flask之蓝图
  • (四)React组件、useState、组件样式
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (四)图像的%2线性拉伸