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

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.xdnf.cn/news/207019.html

相关文章:

  • 嵌入式开发面试常见编程题解析:pthread_join 与 pthread_detach 详解
  • 【动手学大模型开发】使用 LLM API:智谱 GLM
  • Java练习6
  • Linux 内核中 TCP 协议的支撑解析
  • 云蝠智能大模型智能呼叫:赋能零售行业服务,助力客户增长
  • 基于PyTorch的Fashion-MNIST图像分类数据集处理与可视化
  • Tauri(2.5.1)+Leptos(0.7.8)开发桌面应用---后台调用Python Matplotlib绘制图形
  • 【计算机架构】CISC(复杂指令集计算机)架构
  • 移远通信LG69T赋能零跑B10:高精度定位护航,共赴汽车智联未来
  • flink cdc 配置
  • 1.5 城镇道路工程安全质量控制
  • Go 1.25为什么要废除核心类型
  • Educational Codeforces Round 178 div2(题解ABCDE)
  • 简化excel校验提高开发效率
  • 精益数据分析(31/126):电商关键指标深度解析与实战策略
  • 51LA使用方法与悟空统计,网站数据分析的双重选择
  • Twitter 工作原理|架构解析|社交APP逻辑
  • 微信小程序封装选择年月日时分秒组件
  • “兴火·燎原”总冠军诞生,云宏信息《金融高算力轻量云平台》登顶
  • uni-app 中封装全局音频播放器
  • 无人机航拍牛只检测数据集VOC+YOLO格式906张1类别
  • Codigger Desktop:重新定义数字工作与生活方式
  • 8.idea创建maven项目(使用Log4j日志记录框架+Log4j 介绍)
  • 如何解决 Xcode 签名证书和 Provisioning Profile 过期问题
  • Linux系统基础:基础指令简介(网络概念部分)
  • AtCoder Beginner Contest 403(题解ABCDEF)
  • PLOT: PROMPT LEARNING WITH OPTIMAL TRANSPORT FOR VISION -LANGUAGE MODELS
  • Vue使用Sortablejs拖拽排序 视图显示与数据不一致、拖拽结束后回跳问题
  • 4.27搭建用户界面
  • PostgreSQL数据库批量删除唯一索引