javascript<——>进阶

一、作用域:变量可以被访问的范围

1.局部作用域

1.1函数作用域

在函数内部声明的变量,在函数内部被访问的,外部无法直接访问。

总结:1、函数内部声明的变量,在函数外部无法直接访问

2、函数的参数也是函数内部的局部变量

3、不同函数内部声明的变量无法互相访问

4、函数执行完毕后,函数内部的变量事件被清空

1.2块作用域

有“{}”的包裹的代码称为代码块,内部声明的变量外部将【有可能】无法被访问

###let /const声明的变量产生块作用域,var声明的不会产生块级作用域

2.全局作用域

写在<script>标签的或者写在js文件的,尽可能少声明全局作用域,防止全局变量被污染

3.作用域链

本质是底层的变量查找机制:(1)函数执行时,优先查找当前函数作用域中查找

                                               (2)查不到则依次逐级查找父级作用域直到全局作用域

###子作用域可以访问父作用域,但是父作用域无法访问子作用域

###相同作用域链按从小到大规则查找变量

4.js垃圾回收机制(GC)

4.1内存生命周期

(1)分配内存:声明变量、函数、对象时,系统自动分配内存

(2)内存使用:读写内存,使用函数,变量

(3)内存回收:使用完毕,垃圾回收机制自动回收不在使用的内存

###全局变量一般不会回收(关闭页面回收),

(4)内存泄漏:程序中分配的内存由于某种原因,程序无法释放或者未释放。

❤️算法说明:

1.栈(操作系统):由操作系统自动分配释放函数的参数值,局部变量等,基本数据类型放到栈里面

2.堆(操作系统):一般由程序员分配释放,不释放,则垃圾回收机制回收。复杂数据类型放到堆里面

4.2垃圾回收算法

(1)引用计数法

跟踪记录被引用的次数,引用一次则记录一次,多次引用会累加++,减少一次引用就--

次数为0,回收

缺点:嵌套使用。两个对象相互引用,尽管它们不再使用,GC不会进行回收,内存泄漏

(2)标记清除法

核心:1.将“不再使用的对象”定义为“无法达到的对象”。

           2.从根部出发定时扫描内存中的对象。凡是从根部到达的对象,都是还需要使用的。

           3.无法触及的对象被标记为不再使用,稍后进行回收。

5.闭包

一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数作用域,会产生内存泄漏

闭包=内层函数+外层函数的变量

<script>
function outer(){let a = 1function fn(){console.log(a)}return fn
}
const fun = outer()
fun()
</script>
//外层函数可以访问内层函数的变量
//const fun = outer() = fn = function fn(){}
//调用fun()

作用:闭包的应用:实现数据的私有,封闭数据。做个统计函数调用次数,调用一次就++

外部可以访问函数内部的变量

问题:内存泄漏

<script>function count(){let i = 0function fn(){i++console.log(`函数被调用了${i}次`)  }return fn
}
const fun = count()</script>

6.变量提升

把var声明的变量提升到 当前作用域的最前面。

只提升声明,不提升赋值

总结:

  1. 变量在未声明即被访问时会报语法错误

  2. 变量在声明之前即被访问,变量的值为 undefined

  3. let 声明的变量不存在变量提升,推荐使用 let

  4. 变量提升出现在相同作用域当中

  5. 实际开发中推荐先声明再访问变量

<script>
function(){console.log(num)var num = 10
}
fun()等价于
function(){var numconsole.log(num)num = 10
}
fun()
</script>

二、函数进阶

1.函数提升(只提升声明,不提升调用)

声明之前调用

函数表达式 必须先声明和赋值,后调用,否则报错。

总结:1、函数提升能够使函数的声明调用更灵活

2、函数表达式不存在提升的现象

3、函数提升出现在相同作用域当中

2.函数参数

###默认值

总结:1、声明函数时为形参赋值即为参数的默认值

2、如果参数未自定义默认值时,参数的默认值为undefined

3、调用函数时没有差引入对应实参时,参数的默认值被当做实参传入

2.1动态参数

arguments是一个伪数组 只存在于 函数里面

作用是动态的获取函数的实参

可以通过for循环依次得到传递过来的参数

2.2剩余参数

(1)...是语法符号,置于最末函数形参之前,用于获取多余的实参

(2)借助...获取的剩余参数,是个真数组

  <script>function getSum(a,b,...arr){console.log(arr);}getSum(2,3,4,5,6,7)getSum(1,2,3,4,5,6,7,8,9)</script>

##使用场景:用于获取多余的实参

##和动态参数的区别是什么?

        动态参数是伪数组;

        剩余参数是真数组

❤️展开运算符【数组中使用】:将数组的数字全展开

      const arr = [1,2,3,4,5]console.log(...arr)console.log(Math.max(...arr));//求最大值console.log(Math.min(...arr));//求最小值

合并数组:

      const arr1 = [1,2,3]const arr2 = [4,5,6]const arr3 = [...arr1,...arr2]console.log(arr3);// [1,2,3,4,5,6]

3.箭头函数

(1)基本语法

const fn=()=>{

}

##只有一个形参时,可以省略小括号

const fn = x=>{


}

##只有一行代码时,可以省略大括号和return

const fn = (x,y) =>x+y

console.log(fn(1,2))

##箭头函数可以直接返回同一个对象

const fn1 = uname=>({uname:name})

console.log('刘德华')

总结:

1、箭头函数属于表达式函数,因此不存在函数提升

2、箭头函数只有一个参数时可以省略圆括号()

3、箭头函数函数体只有一行时代码可以省略花括号{},并自动作为返回值被返回

(2)箭头函数参数

只有剩余参数,没有动态参数arguments

(3)箭头函数this

箭头函数不会创建自己的this,从自己的作用域链的上一层沿用this

三、解构赋值

1.数组解构 :

将数组的单元值快速批量赋值给一系列变量的简介语法

<script>// 以下代码是否会正常执行,如果不会,如何改正const [min, avg, max] = [100,200,300];//必须加分号(function() {console.log(min);})();</script>
<script>const arr = [60,100,80]const [max,min avg] = arr
//将按照顺序赋值给变量console.log(max)
</script>

交换变量

<script>
let a = 1
let b = 2;
const [b,a]=[a,b]
console.log(a,b)
</script>
<script>1. 变量多, 单元值少 , undefinedconst [a, b, c, d] = [1, 2, 3]console.log(a) // 1console.log(b) // 2console.log(c) // 3console.log(d) // undefined2. 变量少, 单元值多const [a, b] = [1, 2, 3]console.log(a) // 1console.log(b) // 23.  剩余参数 变量少, 单元值多const [a, b, ...c] = [1, 2, 3, 4]console.log(a) // 1console.log(b) // 2console.log(c) // [3, 4]  真数组4.  防止 undefined 传递const [a = 0, b = 0] = [1, 2]const [a = 0, b = 0] = []console.log(a) // 1console.log(b) // 25.  按需导入赋值const [a, b, , d] = [1, 2, 3, 4]console.log(a) // 1console.log(b) // 2console.log(d) // 4const arr = [1, 2, [3, 4]]console.log(arr[0])  // 1console.log(arr[1])  // 2console.log(arr[2])  // [3,4]console.log(arr[2][0])  // 3// 多维数组解构const [a, b, [c, d]] = [1, 2, [3, 4]]console.log(a) // 1console.log(b) // 2console.log(c) // 3console.log(d) // 4</script>

2.对象解构

<script>// 对象解构const obj = {uname: 'pink老师',age: 18}obj.unameobj.age //const uname = 'red老师'解构的语法const { uname, age } = {age: 18, uname: 'pink老师' }// 等价于 const uname =  obj.uname//要求属性名和变量名必须一致才可以
</script>

3.多级对象解构

<script>const pig = {name: '佩奇',family: {mother: '猪妈妈',father: '猪爸爸',sister: '乔治'},age: 6}// // 多级对象解构const { name, family: { mother, father, sister } } = pig
</script>

4.多级数组对象解构

 <script>//多级对象数组解构const person = [{name: '佩奇',family: {mother: '猪妈妈',father: '猪爸爸',sister: '乔治'},age: 6}]const [{ name, family: { mother, father, sister } }] = personconsole.log(name)console.log(mother)console.log(father)console.log(sister)</script>

5.多级对象解构案例

 <script>// 1. 这是后台传递过来的数据const msg = {"code": 200,"msg": "获取新闻列表成功","data": [{"id": 1,"title": "5G商用自己,三大运用商收入下降","count": 58},{"id": 2,"title": "国际媒体头条速览","count": 56},{"id": 3,"title": "乌克兰和俄罗斯持续冲突","count": 1669},]} // 需求1: 请将以上msg对象  采用对象解构的方式 只选出  data 方面后面使用渲染页面const {data} = msgconsole.log(data) // 需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做参数传递给 函数function render({data}){console.log(data)}render(msg)// 需求3, 为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为 myDatafunction render({data:myData}){console.log(myData)}
</script>

###forEach()方法

用于调用数组的每个元素,并将元素传递给回调函数

注意:

1、forEach主要是遍历数组

2、参数当前数组元素使必须要写的,索引号可选。

  <script>// forEach 就是遍历  加强版的for循环  适合于遍历数组对象const arr = ['red', 'green', 'pink']const result = arr.forEach(function (item, index) {console.log(item)  // 数组元素 red  green pinkconsole.log(index) // 索引号})// console.log(result)</script>

###筛选数组filter方法

filter()方法创建的一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素

使用场景:筛选数组符合条件的元素,并返回筛选之后元素的新数组

语法:

  <script>const arr = [10, 20, 30]// const newArr = arr.filter(function (item, index) {//   // console.log(item)//   // console.log(index)//   return item >= 20// })// 返回的符合条件的新数组const newArr = arr.filter(item => item >= 20)console.log(newArr)</script>

###渲染商品案例

 <script>// 2. 初始化数据const goodsList = [{id: '4001172',name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',price: '289.00',picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',},{id: '4001594',name: '日式黑陶功夫茶组双侧把茶具礼盒装',price: '288.00',picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',},{id: '4001009',name: '竹制干泡茶盘正方形沥水茶台品茶盘',price: '109.00',picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',},{id: '4001874',name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',price: '488.00',picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',},{id: '4001649',name: '大师监制龙泉青瓷茶叶罐',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',},{id: '3997185',name: '与众不同的口感汝瓷白酒杯套组1壶4杯',price: '108.00',picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',},{id: '3997403',name: '手工吹制更厚实白酒杯壶套装6壶6杯',price: '99.00',picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',},{id: '3998274',name: '德国百年工艺高端水晶玻璃红酒杯2支装',price: '139.00',picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',},]function render(arr) {let str = ''arr.forEach(item => {const { name, price, picture } = itemstr += `<div class="item"><img src="${picture}" alt=""><p class="name">${name}</p><p class="price">${price}</p></div>`});document.querySelector('.list').innerHTML = str}render(goodsList)document.querySelector('.filter').addEventListener('click', e => {const { tagName, dataset } = e.targetif (tagName == 'A') {//console.log(11);let arr = goodsListif (dataset.index === '1') {arr = goodsList.filter(item => item.price > 0 && item.price < 100)} else if (dataset.index === '2') {arr = goodsList.filter(item => item.price >= 100 && item.price < 300)} else if (dataset.index === '3') {arr = goodsList.filter(item => item.price >= 300)}render(arr)}})</script>

四、构造函数与数据常用函数

1.深入对象

1.1创建对象三种方式

(1)利用对象字面量创建对象

const 0 = {

        name : 'abc'

}

(2)利用new Object创建对象

const 0 = new Object({name:'abc'})

(3)利用构造函数创建对象

1.2构造函数

一种特殊的函数,主要用来初始化对象。

##使用new关键字的调用函数行为被称为实例化

##实例化构造函数时没有参数可以省略

##构造函数内部无需写return,返回值即新创建的对象

##构造函数内部的return返回值无效,所以不要写return

##new Object()new Date()也是实例化构造函数

两个约定:

<1>命名大写字母开头

<2>它们只能由“new”操作符来执行

<script>function Pig(uname,age){this.uname = unamethis.age = age
}const p = new Pig('peiqi',6)const q = new Pig('qiaozhi',3)console.log(p,q)
</script>

❤️实例化执行过程

(1)创建新对象

(2)构造函数this指向新对象

(3)执行函数构造代码,修改this,添加新属性

(4)返回新的对象

1.3实例成员和静态成员

1.3.1实例成员

通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和实例方法)

1.3.2静态成员

构造函数的属性和方法被称为静态成员

<script>function Pig(name){this.name = name
}
Pig.eyes = 2//静态属性
Pig.sayHi = function(){//静态方法console.log(this)
}
Pig.sayHi()
console.log(Pig.eyes)//2
</script>

说明:

1.静态成员只能构造函数来访问

2.静态方法中的this指向构造函数

2.内置构造函数

1.Object

.keys(obj):返回所有属性名

.values(obj):获得所有的属性值【返回的是数组】

 const o = { uname: 'pink', age: 18 }// 1.获得所有的属性名console.log(Object.keys(o))  //返回数组['uname', 'age']// 2. 获得所有的属性值console.log(Object.values(o))  //  ['pink', 18]

.assign(new,old):对象拷贝

 // 3. 对象的拷贝const o = { uname: 'pink', age: 18 }// const oo = {}// Object.assign(oo, o)// console.log(oo)//对象中添加属性Object.assign(o, { gender: '女' })console.log(o)

2.Array

方法作用说明
filter过滤数组返回新数组,返回的是筛选满足条件的数组与数组元素
forEach遍历数组不返回数组,经常用于查找遍历数组元素
map迭代数组返回新数组,返回的是处理后的数组元素,想要使用返回的新数组
reduce累计器返回累计处理的结果,经常用于求和等

join

拼接数组元素拼接成字符串,返回字符串
find查找元素返回符合测试条件的第一个数组,如果没有符合条件的则返回undefined
every检测数组所有元素是否都符合指定条件如果都符合,返回true,否则返回false
sort排序对原数组单元值进行排序
from伪数组转换为真数组返回真数组

<script>const arr =  [1,3,5,7,9]const result = arr.reduce((a,b)=>(a+b),10)console.log(result)//35
</script>

(1)reduce(function(prev,curret){return prev+curret},start)

prev:代表初始值

curret:代表累加的值

start:初始值具体数字

###

1.如果没有初始值,则上一次的值以数组的第一个数组元素的值。

2.每一次循环,把返回值给作为 下一次循环的上一次值。

3.如果有初始值,则起始值作为上一次值。

  <script>const arr = [{name: '张三',salary: 10000}, {name: '李四',salary: 10000}, {name: '王五',salary: 20000},]const money = arr.reduce((prev, item) => prev + item.salary * 1.3, 0)console.log(money)</script>

包装类型:

字符串、数值、布尔类型数据是js底层使用Object构造函数“包装”来的,即为包装类型

3.String

.split【‘分隔符’】:把字符串转换成数组(和join相反)

.substring【第一个索引,最后一个索引】截取字符串

.startsWith(检测字符串,【检测位置的索引号】),检测是否以某字符开头

.includes(搜索的字符串,检测的字符串位置索号),判断一的字符串是否包含在另一个字符串中,根据情况返回true或false

.replace(代替字符串)

4.Number

.toFixed:设置保留小数位的长度,四舍五入。

3.综合案例

五、深入面向对象

1.编程思想

(1)面向过程

分析解决问题的步骤,然后用函数一步一步地实现,使用的时候调用

优点:性能高

缺点:没有面向易维护,复用,扩展

(2)面向对象(oop)

优点:易维护、复用、扩展,使系统更加易于维护,更加灵活

缺点:性能低

分解为一个个对象,然后对象之间分工和合作。

###特性:

【1】封装性:封装代码,js面向对象可以通过构造函数实现的封装,同时将变量和函数组合到一起并能通过this实现数据的共享,所不同的是借助构造函数创建出来的实例对象之间互相不影响。

总结:

1、构造函数体现了面向对象的封装特性

2、构造函数实例创建的对象彼此独立,互不影响。

【2】继承性:继承接口

【3】多态性

2.构造函数

存在浪费内存的问题

3.原型对象

构造函数通过原型分配的函数是所有对象所共享的

###js规定,每一个构造函数都有一个prototype属性,指向另一个对象,所以我们也称为原型对象

###这个对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存

###我们可以把那些不变的方法,直接定义为prototype对象上,这样所有对象的实例就可以共享这些方法

###构造函数和原型对象中的this都指向实例化的对象

原型作用:
(1)共享方法

(2)可以把那些不变的方法,直接定义在prototype对象上

构造函数和原型里面的this指向谁?

指向实例化对象

constructor 属性

在哪里? 每个原型对象里面都有个constructor 属性(constructor 构造函数)

作用:该属性指向该原型对象的构造函数, 简单理解,就是指向我的爸爸,我是有爸爸的孩子

使用场景:

如果有多个对象的方法,我们可以给原型对象采取对象形式赋值.

但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了

此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

对象原型

构造函数创建实例对象和含有原型对象(prototype),实例对象的__proto__指向原型对象,实例对象的__protype__和原型对象的constructor指向构造函数。

对象都会有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype

原型对象的属性和方法,就是因为对象有__proto__ 原型的存在。

注意:

  • __proto__是JS非标准属性

  • [[prototype]]和__proto__意义相同

  • 用来表明当前实例对象指向哪个原型对象prototype

  • __proto__对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数

原型继承

继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript 中大多是借助原型对象实现继承

的特性。

龙生龙、凤生凤、老鼠的儿子会打洞描述的正是继承的含义。

<body><script>// 继续抽取   公共的部分放到原型上// const Person1 = {//   eyes: 2,//   head: 1// }// const Person2 = {//   eyes: 2,//   head: 1// }// 构造函数  new 出来的对象 结构一样,但是对象不一样function Person() {this.eyes = 2this.head = 1}// console.log(new Person)// 女人  构造函数   继承  想要 继承 Personfunction Woman() {}// Woman 通过原型来继承 Person// 父构造函数(父类)   子构造函数(子类)// 子类的原型 =  new 父类  Woman.prototype = new Person()   // {eyes: 2, head: 1} // 指回原来的构造函数Woman.prototype.constructor = Woman// 给女人添加一个方法  生孩子Woman.prototype.baby = function () {console.log('宝贝')}const red = new Woman()console.log(red)// console.log(Woman.prototype)// 男人 构造函数  继承  想要 继承 Personfunction Man() {}// 通过 原型继承 PersonMan.prototype = new Person()Man.prototype.constructor = Manconst pink = new Man()console.log(pink)</script>
</body>

原型链(查找规则)

基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链

<body><script>// function Objetc() {}console.log(Object.prototype)console.log(Object.prototype.__proto__)function Person() {}const ldh = new Person()// console.log(ldh.__proto__ === Person.prototype)// console.log(Person.prototype.__proto__ === Object.prototype)console.log(ldh instanceof Person)console.log(ldh instanceof Object)console.log(ldh instanceof Array)console.log([1, 2, 3] instanceof Array)console.log(Array instanceof Object)</script>
</body>

① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。

② 如果没有就查找它的原型(也就是__ proto__指向的 prototype 原型对象)

③ 如果还没有就查找原型对象的原型(Object的原型对象)

④ 依此类推一直找到 Object 为止(null)

⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

六、深浅拷贝

只针对引用数据类型

1.浅拷贝

拷贝的是地址

常见方法:

(1)拷贝对象:Object.assgin()/展开运算符{…obj}拷贝对象

(2)拷贝数组:Array/ptotype.concat()或者{…arr}

2.深拷贝

拷贝的是对象,不是地址

2.1递归实现深拷贝

1.深拷贝实现拷贝出来的新对象不会影响旧对象 ,通过函数递归实现

2.普通拷贝的话直接赋值就可以,遇到数组再次调用这个递归函数

3.如果遇到对象,就调用递归函数解决对象,【先array,后对象】  

<body><script>const obj = {uname: 'pink',age: 18,hobby: ['乒乓球', '足球'],family: {baby: '小pink'}}const o = {}// 拷贝函数function deepCopy(newObj, oldObj) {debuggerfor (let k in oldObj) {// 处理数组的问题  一定先写数组 在写 对象 不能颠倒if (oldObj[k] instanceof Array) {newObj[k] = []//  newObj[k] 接收 []  hobby//  oldObj[k]   ['乒乓球', '足球']deepCopy(newObj[k], oldObj[k])} else if (oldObj[k] instanceof Object) {newObj[k] = {}deepCopy(newObj[k], oldObj[k])}else {//  k  属性名 uname age    oldObj[k]  属性值  18// newObj[k]  === o.uname  给新对象添加属性newObj[k] = oldObj[k]}}}deepCopy(o, obj) // 函数调用  两个参数 o 新对象  obj 旧对象console.log(o)o.age = 20o.hobby[0] = '篮球'o.family.baby = '老pink'console.log(obj)console.log([1, 23] instanceof Object)// 复习// const obj = {//   uname: 'pink',//   age: 18,//   hobby: ['乒乓球', '足球']// }// function deepCopy({ }, oldObj) {//   // k 属性名  oldObj[k] 属性值//   for (let k in oldObj) {//     // 处理数组的问题   k 变量//     newObj[k] = oldObj[k]//     // o.uname = 'pink'//     // newObj.k  = 'pink'//   }// }</script>
</body>

2.2js库lodash里面cloneDeep

<body><!-- 先引用 --><script src="./lodash.min.js"></script><script>const obj = {uname: 'pink',age: 18,hobby: ['乒乓球', '足球'],family: {baby: '小pink'}}const o = _.cloneDeep(obj)console.log(o)o.family.baby = '老pink'console.log(obj)</script>
</body>

2.3JSON序列化

<body><script>const obj = {uname: 'pink',age: 18,hobby: ['乒乓球', '足球'],family: {baby: '小pink'}}// 把对象转换为 JSON 字符串// console.log(JSON.stringify(obj))const o = JSON.parse(JSON.stringify(obj))console.log(o)o.family.baby = '123'console.log(obj)</script>
</body>

七、异常处理

异常处理指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行

throw抛异常

1、throw抛出异常信息后,程序也会终止执行

2、throw后面跟的是错误提示信息

3、Error对象配合throw使用,能够设置更详细的错误信息

<script>function counter(x, y) {if(!x || !y) {// throw '参数不能为空!';throw new Error('参数不能为空!')}return x + y}counter()
</script>

try/catch捕获错误信息

  1. try...catch 用于捕获错误信息

  2. 将预估可能发生错误的代码写在 try 代码段中

  3. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息

<script>function foo() {try {// 查找 DOM 节点const p = document.querySelector('.p')p.style.color = 'red'} catch (error) {// try 代码段中执行有错误时,会执行 catch 代码段// 查看错误信息console.log(error.message)// 终止代码继续执行return}finally {//不管代码报不报错误,仍然执行该行代码alert('执行')}console.log('如果出现错误,我的语句不会执行')}foo()
</script>

debugger

八、处理this

1.普通函数this指向

谁调用就指向谁

严格模式下指向undefined

2.箭头函数this指向

箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量

总结:1.函数内部不存在this,沿用上一级的this

2.不适用:构造函数、原型函数、dom事件函数等

3.适用:需要使用上层的this的地方

4.如果正确的话,它会在很多地方带来方便。

3.改变this指向

(1)call

<script>// 普通函数function sayHi() {console.log(this);}let user = {name: '小明',age: 18}let student = {name: '小红',age: 16}// 调用函数并指定 this 的值sayHi.call(user); // this 值为 usersayHi.call(student); // this 值为 student// 求和函数function counter(x, y) {return x + y;}// 调用 counter 函数,并传入参数let result = counter.call(null, 5, 10);console.log(result);
</script>

总结:

  1. call方法能够在调用函数的同时指定 this 的值

  2. 使用 call 方法调用函数时,第1个参数为 this 指定的值

  3. call 方法的其余参数会依次自动传入函数做为函数的参数

(2)apply

总结:

  1. apply 方法能够在调用函数的同时指定 this 的值

  2. 使用 apply 方法调用函数时,第1个参数为 this 指定的值

  3. apply 方法第2个参数为数组,数组的单元值依次自动传入函数做为函数的参数

call和apply的区别是?

都是调用函数,都能够改变this指向。但它们的参数不一样,apply传递的必须是数组

(3)bind

不会调用函数,但是能改变this的指向

返回值是个函数,但是这个函数里面的this是更改过的obj

主要应用场景:

call调用函数并且可以传递参数

apply经常跟数组有关系,比如借助数学对象实现求最大值和最小值

bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向

九、防抖节流

防抖(debounce):

单位时间内,频繁触发事件,只执行最后一次

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间

使用场景:输入手机号,邮箱验证输入检测

节流(throttle):

单位时间内,频繁出发事件,只执行一次

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数

使用场景:鼠标移动mousemove,页面尺寸缩放resize、滚动条滚动scroll

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

驱动开发硬核特训 · Day 25 (附加篇):从设备树到驱动——深入理解Linux时钟子系统的实战链路

一、前言 在嵌入式Linux开发中&#xff0c;无论是CPU、外设控制器&#xff0c;还是简单的GPIO扩展器&#xff0c;大多数硬件模块都离不开时钟信号的支撑。 时钟子系统&#xff08;Clock Subsystem&#xff09;&#xff0c;作为Linux内核中基础设施的一部分&#xff0c;为设备…

并发设计模式实战系列(7):Thread Local Storage (TLS)

&#x1f31f; 大家好&#xff0c;我是摘星&#xff01; &#x1f31f; 今天为大家带来的是并发设计模式实战系列&#xff0c;第七章Thread Local Storage (TLS)&#xff0c;废话不多说直接开始~ 目录 一、核心原理深度拆解 1. TLS内存模型 2. 关键特性 二、生活化类比&a…

时序数据库 TDengine × Perspective:你需要的可视化“加速器”

你有没有遇到这样的场景&#xff1a;数据已经写进数据库&#xff0c;图表却总是“慢半拍”&#xff1f;或是操作界面太卡&#xff0c;光是一个排序就能让你等到喝完一杯咖啡&#xff1f;当数据量越来越大、响应时间却越来越长&#xff0c;开发者和用户都不禁要问一句——就没有…

前端面试每日三题 - Day 19

这是我为准备前端/全栈开发工程师面试整理的第十一天每日三题练习&#xff0c;涵盖 JavaScript中WeakMap与内存管理的底层机制、Redux Toolkit的事件以及系统设计中的企业级表单引擎构建。通过这三道题&#xff0c;你将对现代前端开发中的关键概念有更深入的理解&#xff0c;并…

Antd Modal Drawer 更改默认项

当项目比较大使用了非常多的 Modal 和 Drawer 要是有需求一次性全部调整就会比较麻烦&#xff0c;目前 Antd 的 ConfigProvider 暂不支持&#xff08;也有可能我没找到&#xff0c;待大佬指证&#xff09;就比如由于默认 Modal Drawer 的遮罩层是可以点击关闭的&#xff0c;但是…

硬件工程师面试常见问题(8)

第三十六问&#xff1a;基尔霍夫定理的内容是什么&#xff1f; 基尔霍夫电流定理&#xff1a; 1. 内容&#xff1a;电路中任意一个节点上&#xff0c;在任意时刻&#xff0c;流入节电的电流之和等于流出节点的电流之和。 2. 表达式&#xff1a;根据上图写出节点电流定律的数学…

Elasticsearch 内存使用指南

作者&#xff1a;来自 Elastic Valentin Crettaz 探索 Elasticsearch 的内存需求以及不同类型的内存统计信息。 Elasticsearch 拥有丰富的新功能&#xff0c;帮助你为你的使用场景构建最佳搜索解决方案。浏览我们的示例笔记本了解更多信息&#xff0c;开始免费云试用&#xff0…

硬件工程师面试常见问题(9)

第四十一问&#xff1a;色环电阻的颜色表示什么&#xff1f; 各环表示的意思&#xff1a; 4色环的&#xff1a;前两位表示有效位&#xff1b;第三环表示倍乘&#xff1b;最后一环表示误差&#xff1b; 5色环的&#xff1a;前三位表示有效位&#xff1b;第四环表示倍乘&#…

PyTorch 深度学习实战(23):多任务强化学习(Multi-Task RL)之扩展

之前的PyTorch 深度学习实战&#xff08;23&#xff09;&#xff1a;多任务强化学习&#xff08;Multi-Task RL)总结扩展运用代码如下&#xff1a; import torch import torch.nn as nn import torch.optim as optim import numpy as np from torch.distributions import Norm…

前端——CSS1

一&#xff0c;概述 CSS&#xff08;Cascading Style Sheets&#xff09;&#xff08;级联样式表&#xff09; css是一种样式表语言&#xff0c;为html标签修饰定义外观&#xff0c;分工不同 涉及&#xff1a;对网页的文字、背景、宽、高、布局进行修饰 分为内嵌样式表&…

赋能航天教育:高校卫星仿真教学实验平台解决方案

​​​​​​ 随着全球航天事业的飞速发展&#xff0c;对高素质航天人才的需求日益增长。如何在高校阶段提前锻炼学生的航天工程实践能力&#xff0c;成为教育界的重要命题。作为领先的通信与网络技术供应商&#xff0c;IPLOOK基于自身在5G核心网、卫星通信及仿真平台领域的深…

Python爬虫(10)Python数据存储实战:基于pymongo的MongoDB开发深度指南

目录 一、为什么需要文档型数据库&#xff1f;1.1 数据存储的范式变革1.2 pymongo的核心优势 二、pymongo核心操作全解析2.1 环境准备2.2 数据库连接与CRUD操作2.3 聚合管道实战2.4 分批次插入百万级数据&#xff08;进阶&#xff09;2.5 分批次插入百万级数据&#xff08;进阶…

Springboot 手搓 后端 滑块验证码生成

目录 一、效果演示 二、后端滑块验证码生成思路 三、原理解析 四、核心代码拿走 滑块验证码react前端实现&#xff0c;见我的这篇博客&#xff1a;前端 React 弹窗式 滑动验证码实现_react中使用阿里云滑块验证码2.0前端接入及相关视觉-CSDN博客 一、效果演示 生成的案例…

关于flink两阶段提交高并发下程序卡住问题

先抛出代码 package com.dpf.flink;import com.dpf.flink.sink.MysqlSink; import org.apache.flink.api.common.serialization.SimpleStringSchema; import org.apache.flink.api.common.typeinfo.Types; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.…

html css js网页制作成品——HTML+CSS+js美甲店网页设计(5页)附源码

美甲店 目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&a…

LeetCode[347]前K个高频元素

思路&#xff1a; 使用小顶堆&#xff0c;最小的元素都出去了&#xff0c;省的就是大&#xff0c;高频的元素了&#xff0c;所以要维护一个小顶堆&#xff0c;使用map存元素高频变化&#xff0c;map存堆里&#xff0c;然后输出堆的东西就行了 代码&#xff1a; class Solution…

2024年网站开发语言选择指南:PHP/Java/Node.js/Python如何选型?

2024年网站开发语言选择指南&#xff1a;PHP/Java/Node.js/Python如何选型&#xff1f; 一、8大主流Web开发语言技术对比 1. PHP开发&#xff1a;中小型网站的首选方案 最新版本&#xff1a;PHP 8.3&#xff08;2023年11月发布&#xff09;核心优势&#xff1a; 全球78%的网站…

从数据结构说起(一)

1 揭开数据结构神奇的面纱 1.1 初识数据结构 在C的标准库模板&#xff08;Standard Template Library,STL&#xff09;课程上&#xff0c;我初次结识了《数据结构》。C语言提供的标准库模板是面向对象程序设计与泛型程序设计思想相结合的典范。所谓的泛型编程就是编写不依赖于具…

JAVA--- 关键字static

之前我们学习了JAVA 面向对象的一些基本知识&#xff0c;今天来进阶一下&#xff01;&#xff01;&#xff01; static关键字 static表示静态&#xff0c;是JAVA中的一个修饰符&#xff0c;可以修饰成员方法&#xff0c;成员变量&#xff0c;可用于修饰类的成员&#xff08;变…

4.27比赛总结

文章目录 T1T2法一&#xff1a;倍增求 LCA法二&#xff1a;Dijkstra 求最短路法三&#xff1a;dfs 求深度 T3T4总结 T1 一道非常简单的题&#xff0c;结果我因为一句话没写挂了 80pts…… 题目中没写 a a a 数组要按照 b b b 数组的顺序&#xff0c;所以对于最大方案&#x…