JS高级 板块重点总结

213 阅读12分钟

第一板块

字符串方法

1. str.indexOf() 判断一个字符串在不在某个字符串里面

应用场景:一般用于判断str中是否有某种字符串,如果没有则返回-1,不是-1说明有

2. str.split("&") 分隔字符串:将字符串按照指定的符号分隔,得到一个数组

应用场景:一般用于解析网址

3. str.substr(2,4) 截取字符串 第一个参数:从哪个下标开始截取 第二个参数:截取的长度

应用场景:一般后台返回的数据,不和前端完全匹配的时候需要自己截取一部分

4. str.toLowerCase() 大小写转换 (只有英文才有大小写,中文不存在大小写)

应用场景:输入字母验证码不区分大小写

构造函数(使用new关键字调用的函数)

  1. 创建空对象
  2. this指向这个对象
  3. 对象赋值
  4. 返回对象

构造函数数据内存原理

image.png 注意:这种形式创建的构造函数会造成性能浪费,通过构造函数拿到的eat方法地址是不一样的

拿到地址与拿到数据的关系

image.png

原型对象:解决变量污染与性能浪费问题

  1. 起因:每次调用构造函数,就会堆内存中开辟一个新的函数。(问题:浪费内存资源)
  2. 使用全局函数解决构造函数方法资源浪费(解决内存资源浪费,问题:全局变量污染)
  3. 使用对象解决 a.构造函数方法资源浪费 b.全局函数变量污染(问题:obj只是减少全局变量数量,但是并没有从根本上解决问题。)
  4. 当声明一个函数的时候,编译器会自动帮你创建一个与之对应的对象,称之为原型对象prototype(作用:解决构造函数内存资源浪费 + 全局变量污染,实例对象可以直接访问原型中的一切成员

prototype属性 、__proto__属性 、constructor

  1. prototype属性: 属于构造函数,指向原型对象
  • 作用: 解决构造函数资源浪费+变量污染
  1. __proto__属性:属于实例对象,指向原型对象(调用的时候不能写出来,直接通过实例调用原型对象)
  • 作用: 可以让实例对象访问原型中的成员
  1. constructor: 属于原型对象,指向构造函数
  • 作用: 可以让实例对象知道自己被哪一个构造函数创建的

三者的关系

image.png

image.png

静态成员与实例成员

静态成员 : 属于函数对象的成员

实例成员: 属于实例化对象的成员

image.png

获取对象的属性值

image.png

补充:Object.keys(对象)能拿到属性名

注意

  1. 实际开发中,根据需求找功能,尽量先去找有没有封装好的代码或框架,提高效率

第二板块

js面向对象:面向对象三大特征:封装、继承、多态

封装:把代码放入对象的方法中

继承:一个对象拥有另一个对象所有的成员

多态:一个对象在不同情况下的不同状态

注意:js基本上不涉及多态

原型链

  1. 原型链 : 每一个实例对象都有自己的原型,而原型也是对象,也有自己的原型。以此类推,形成链式结构,称之为原型链。(原型链的终点是null)

  2. 原型链访问规则 :就近原则

  • 对象优先访问自己的成员,自己没有就找原型的,如果原型也没有,就找原型的原型。以此类推,直到原型链终点null. 如果还找不到, 属性则获取undefined,方法则报错undefined is not a function

数组的所有方法放在原型当中(字符串和其他对象同理)

image.png

DOM对象的原型链

image.png

instanceof关键字(运算符)

  1. 作用:用于检测右边的构造函数的prototype在不在左边实例对象的原型链中
  2. 应用:某些函数为了限制你的数据类型,再内部需要用instanceof进行判断是否是正确的数据类型 image.png

函数补充

  1. arguments关键字:获取函数所有的实参(伪数组)
  2. 应用:一般用户参数数量不限的函数。(例如:arr.push() Math.max()这些函数实参数量不限,底层原理就是使用argumens来接收缩哟的实参)
  3. 剩余参数(rest参数):获取函数剩余的所有实参
  • 语法:function函数名(形参1,...形参2){}
  • 特点:(1)只能作为最后一个参数(2)真数组
  1. 一般情况下,rest参数可以替代arguments
  2. 函数默认参数:function 函数名(形参=默认值){}

注意

  1. 实例的对象能通过原型继承调用内置对象中的方法,因此不会报错( 比如变量.toString(任何数据类型)
  2. 所有框架的方法都是放在原型当中
  3. 有几个特殊对象的原型需要通过 对象.dir来查看(比如function Date)
  4. 伪数组:有数组三要素(元素、下标、长度),但是不能使用数组的方法

暂时没学懂的案例

截屏2022-03-09 下午4.24.55.png

第三板块

this

this环境对象 : 谁‘调用’我,我就指向谁

  • 重点: 与函数声明无关,取决于函数调用

  • (1)普通函数调用: 函数名() -> this指向window

  • (2)对象方法调用: 对象名.方法名() -> this指向对象

  • (3)构造函数调用: new 函数名() -> this指向new创建的实例对象

  • 小技巧:没点、没new,this指向window;有点是对象,有new是实例(只用看调用函数的那句代码就行)

上下文调用 : 修改函数中this指向

  1. 函数名.call(修改的this,参数1,参数2,....)
  2. 函数名.apply(修改的this, 数组/伪数组 )
  3. 函数名.bind(修改this)
  • bind不会立即执行函数,而是得到一个修改this之后的新函数(一次修改,终生受用)
  • 应用场景:一般用于修改:定时器函数、事件处理函数
  • 注意: 如果你在bind后面传了函数参数,那么参数也会绑定。之后传参无效

经典面试题:请说说call、apply、bind有什么区别

  • 3.1 传参方式不同 : call是一一传参,apply是数组/伪数组传参

  • 3.2 执行机制不同 : call、apply会立即执行函数, bind不会立即执行函数

数据类型检测

image.png 注意:

  1. typeOf 不能测出数组Null的数据类型,都显示为Object
  2. 利用Obejct.prototype.toString()返回固定格式字符串[object 数据类型]

求数组最大值

  1. 用...arr(推荐 )
let arr = [20,30,40,50]
let max3 = Math.max(...arr)
console.log(max3)
  1. 用apply()
let max2 = Math.max.apply(Math,arr)

console.log(max2);
  1. 用基础语法循环来做

面试必问:call和apply和bind三者区别

  1. 相同点:作用一致,修改函数this指向
  2. 不同点:
    • 传参方式不同:call是按照顺序传参,apply是数组/伪数组传参
    • 执行机制不同:call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数

闭包(closure)是什么?

  1. 闭包是一个访问其他函数内部变量的函数

  2. 闭包 = 函数 + 上下文引用 的组合

总结:形成闭包要有两个条件,缺一不可。 (1)函数 (2)访问其他函数内部变量

作用:解决变量污染(一般用于回调函数)

深拷贝与浅拷贝

  1. 拷贝与深拷贝:
  • 浅拷贝: 拷贝的是地址, 修改拷贝后的数据对原数据有影响

  • 深拷贝:拷贝的是数据, 修改拷贝后的数据对原数据没有影响

  1. 拷贝有两种实现方式
  • 推荐使用:json转换 (JSON.parse(JSON.stringify(obj)))

  • 递归函数

递归案例

数据

image.png

实现代码

image.png

补充

  1. slice可以查询数组,默认情况下不传参,这个方法会得到数组本身,slice方法存储在Array.prototype(slice(num1,num2),数组切片,一个参数为从第一个下标到最后,两个参数为第一个到第二个下标,左闭右开)
  2. 实际开发中,将伪数组转为真数组:用Array.from(伪数组)
  3. 数据类型分为:五种值类型,三种引用类型

注意

  1. 调用对象中的属性两种方式:对象.属性名,或者,对象['属性名']
  2. 函数是数据类型,也可以像其他数据一样直接使用语法
    setTimeout(function(){
    
        console.log(this)
    
    }.bind({name:'干饭'}),3000)
    

第四板块

解构赋值(对象和数组解构方式差不多)

  1. 取出对象的属性 赋值给 变量
  • let {name,age,sex} = 对象名
  1. 取出变量的值 赋值给 对象的属性
  • let 对象名 = {name,age,sex}

对象的解构

//今后的开发中,很多函数的参数是对象类型

function fn( {uname,pword} ){// {uname,pword} = {uname:'admin',pword:'123456'}

//函数参数进行解构赋值

// let {uname,pword} = obj

console.log( uname,pword )

}

fn({uname:'admin',pword:'123456'})

注意:在函数传参中对象的解构需要用大括号{}包起来

箭头函数

  1. 箭头函数语法 : 就是function简写
  • 把function单词 替换成 箭头 =>

  • 把形参() 移到 箭头的 左边

  1. 箭头函数其他用法:
  • 如果只有一个形参,则可以省略形参小括号

    a=>{ return a*2 }

  • 如果函数体只有一行,则可以省略大括号。此时必须要省略return 变为

    a=>a*2

箭头函数this

箭头函数this指向 : 箭头函数没有this(箭头函数的this和调用无关,取决于声明位置)

  • 箭头函数中使用this,会访问上级作用域this

  • 原因(作用域链):箭头函数没有this, 就会往上级作用域找

注意:

  1. 由于箭头函数没有this,所以箭头函数不能作为构造函数(new会修改this指向,而箭头没有this)
  2. 箭头函数也无法修改this(call apply bind)对箭头函数是无效的
  3. 事件处理函数,注意不要用箭头函数

this指向-案例

image.png

展开运算符

  1. 展开运算符 : ...

  2. 作用: 相当于遍历对象简写

  3. 应用场景:

  • 连接数组(上拉加载下一页):arr1.push(...arr2)

  • 求数组最大值 : Math.max(...arr)

数据类型Set(集合)

  1. 类似于数组,与数组唯一的区别是 :不能存储重复元素

  2. 应用 : 数组去重

补充:一行代码去重(两种写法):

  1. let newArr = Array.from(new Set(数组))
  2. let newArr = [...new Set(arr)]

数组迭代方法

map方法

  1. map场景 : 映射数组(对数组每一个元素进行映射处理,得到一个全新数组)
  2. 特点
  • 回调执行次数 === 数组长度

  • 本身返回值 : 映射之后的新数组

  • 回调函数内部return

  • map()括号中可以用箭头函数,如果是处理数组,箭头函数中可以传两个参数,固定写法,第一个为数组的数据,第二个为数组的下标

    let arr = [88,100,90,66,50]
    
    let newArr = arr.map((value,index)=>{
    
        console.log(index,value)//下标 元素
    
        return value*2
    
    })
    console.log(newArr)
    

注意:如果不写return, 新数组每一个元素都变成undefined

应用场景:利用 map 拼接HTML字符串

三个步骤:

  1. 用map把数组中的数据映射成对应的html字符串
  2. 拼接字符串
  3. 替换元素的innerHTML image.png 另一种写法(一句语法生成)

image.png

filter方法

  1. filter场景 : 筛选数组(找出数组中符合条件的元素)
  2. 特点
  • 回调执行次数 === 数组长度
  • 本身返回值 : 筛选之后的新数组
  • 回调函数内部return
  • return true : 满足筛选条件,当前元素放入新数组中
  • return false : 不满足筛选条件,当前元素不放入新数组

forEach方法

  1. forEach场景 : 遍历数组(一般用在不需要取下标的情况下)

  2. forEach方法特点

  • 遍历次数 === 数组长度
  • 本身返回值:无
  • 回调函数内部return:无

some方法

  1. some场景 : 判断数组中是否有满足条件的元素
  • 例子:判断数组中有没有负数
  1. some方法特点
  • 回调执行次数 != 数组长度

  • 本身返回值

    • true : 有满足条件的元素
    • false: 没有满足条件的元素
  1. 回调函数内部return
  • true : 循环立即结束。并且some方法本身返回true
  • false : 循环继续执行。如果全部遍历结束还是false,则some方法默认返回false

every方法(和some方法相反,就不写了)

场景:判断数组是否全部满足条件

经典场景:开关法

findIndex与indexOf方法

findIndex只能检测引用类型,有则拿到下标 indexOf只能检测值类型,有则拿到下标

  • 应用场景: 与 indexOf() 类似 . 但是findIndex一般用于对象数组

findIndex方法特点

(1)遍历次数 != 数组长度

(2)本身返回值

有元素: 元素下标

没有元素: 固定值-1

(3)回调函数内部return

return true: 找到了,循环立即结束。并且findIndex方法本身返回当前index

return false: 没找到,循环继续。如果全部遍历完还是没找到,则得到默认返回值-1

reduce方法

  1. 数组reduce方法 : 给每一个元素执行一次回调

  2. 应用场景: 数组求和、求数组最大值

  3. 语法:let res = arr.reduce((sum,value,index)=>{ return sum+value },0)

  • res返回值是最后一次sum的结果
  1. 注意点: 一定要给初始值,否则reduce遇到空数组就会报错

注意

  1. 实际开发中,尽量中const,如果有必要修改的变量,才用let
  2. 定时器的this始终指向window
  3. map一般用来动态拼接HTML字符串,再封装起来;filter一般用来做条件筛选