第一板块
字符串方法
1. str.indexOf() 判断一个字符串在不在某个字符串里面
应用场景:一般用于判断str中是否有某种字符串,如果没有则返回-1,不是-1说明有
2. str.split("&") 分隔字符串:将字符串按照指定的符号分隔,得到一个数组
应用场景:一般用于解析网址
3. str.substr(2,4) 截取字符串 第一个参数:从哪个下标开始截取 第二个参数:截取的长度
应用场景:一般后台返回的数据,不和前端完全匹配的时候需要自己截取一部分
4. str.toLowerCase() 大小写转换 (只有英文才有大小写,中文不存在大小写)
应用场景:输入字母验证码不区分大小写
构造函数(使用new关键字调用的函数)
- 创建空对象
- this指向这个对象
- 对象赋值
- 返回对象
构造函数数据内存原理
注意:这种形式创建的构造函数会造成性能浪费,通过构造函数拿到的eat方法地址是不一样的
拿到地址与拿到数据的关系
原型对象:解决变量污染与性能浪费问题
- 起因:每次调用构造函数,就会堆内存中开辟一个新的函数。(问题:浪费内存资源)
- 使用全局函数解决构造函数方法资源浪费(解决内存资源浪费,问题:全局变量污染)
- 使用对象解决 a.构造函数方法资源浪费 b.全局函数变量污染(问题:obj只是减少全局变量数量,但是并没有从根本上解决问题。)
- 当声明一个函数的时候,编译器会自动帮你创建一个与之对应的对象,称之为原型对象prototype(作用:解决构造函数内存资源浪费 + 全局变量污染,
实例对象可以直接访问原型中的一切成员)
prototype属性 、__proto__属性 、constructor
- prototype属性: 属于构造函数,指向原型对象
- 作用: 解决构造函数资源浪费+变量污染
- __proto__属性:属于实例对象,指向原型对象(调用的时候不能写出来,直接通过实例调用原型对象)
- 作用: 可以让实例对象访问原型中的成员
- constructor: 属于原型对象,指向构造函数
- 作用: 可以让实例对象知道自己被哪一个构造函数创建的
三者的关系
静态成员与实例成员
静态成员 : 属于函数对象的成员
实例成员: 属于实例化对象的成员
获取对象的属性值
补充:Object.keys(对象)能拿到属性名
注意
- 实际开发中,根据需求找功能,尽量先去找有没有封装好的代码或框架,提高效率
第二板块
js面向对象:面向对象三大特征:封装、继承、多态
封装:把代码放入对象的方法中
继承:一个对象拥有另一个对象所有的成员
多态:一个对象在不同情况下的不同状态
注意:js基本上不涉及多态
原型链
-
原型链 : 每一个实例对象都有自己的原型,而原型也是对象,也有自己的原型。以此类推,形成链式结构,称之为原型链。(原型链的终点是null)
-
原型链访问规则 :就近原则
- 对象优先访问自己的成员,自己没有就找原型的,如果原型也没有,就找原型的原型。以此类推,直到原型链终点null. 如果还找不到, 属性则获取undefined,方法则报错undefined is not a function
数组的所有方法放在原型当中(字符串和其他对象同理)
DOM对象的原型链
instanceof关键字(运算符)
- 作用:用于检测右边的构造函数的prototype在不在左边实例对象的原型链中
- 应用:某些函数为了限制你的数据类型,再内部需要用instanceof进行判断是否是正确的数据类型
函数补充
- arguments关键字:获取函数所有的实参(伪数组)
- 应用:一般用户参数数量不限的函数。(例如:arr.push() Math.max()这些函数实参数量不限,底层原理就是使用argumens来接收缩哟的实参)
- 剩余参数(rest参数):获取函数剩余的所有实参
- 语法:function函数名(形参1,...形参2){}
- 特点:(1)只能作为最后一个参数(2)真数组
- 一般情况下,rest参数可以替代arguments
- 函数默认参数:
function 函数名(形参=默认值){}
注意
- 实例的对象能通过原型继承调用内置对象中的方法,因此不会报错( 比如
变量.toString(任何数据类型)) - 所有框架的方法都是放在原型当中
- 有几个特殊对象的原型需要通过
对象.dir来查看(比如function Date) - 伪数组:有数组三要素(元素、下标、长度),但是不能使用数组的方法
暂时没学懂的案例
第三板块
this
this环境对象 : 谁‘调用’我,我就指向谁
-
重点: 与函数声明无关,取决于函数调用
-
(1)普通函数调用: 函数名() -> this指向window
-
(2)对象方法调用: 对象名.方法名() -> this指向对象
-
(3)构造函数调用: new 函数名() -> this指向new创建的实例对象
- 小技巧:没点、没new,this指向window;有点是对象,有new是实例(只用看调用函数的那句代码就行)
上下文调用 : 修改函数中this指向
- 函数名.call(修改的this,参数1,参数2,....)
- 函数名.apply(修改的this, 数组/伪数组 )
- 函数名.bind(修改this)
- bind不会立即执行函数,而是得到一个修改this之后的新函数(一次修改,终生受用)
- 应用场景:一般用于修改:定时器函数、事件处理函数
- 注意: 如果你在bind后面传了函数参数,那么参数也会绑定。之后传参无效
经典面试题:请说说call、apply、bind有什么区别
-
3.1 传参方式不同 : call是一一传参,apply是数组/伪数组传参
-
3.2 执行机制不同 : call、apply会立即执行函数, bind不会立即执行函数
数据类型检测
注意:
- typeOf 不能测出
数组和Null的数据类型,都显示为Object - 利用
Obejct.prototype.toString()返回固定格式字符串[object 数据类型]
求数组最大值
- 用...arr(推荐 )
let arr = [20,30,40,50]
let max3 = Math.max(...arr)
console.log(max3)
- 用apply()
let max2 = Math.max.apply(Math,arr)
console.log(max2);
- 用基础语法循环来做
面试必问:call和apply和bind三者区别
- 相同点:作用一致,修改函数this指向
- 不同点:
- 传参方式不同:call是按照顺序传参,apply是数组/伪数组传参
- 执行机制不同:call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数
闭包(closure)是什么?
-
闭包是一个访问其他函数内部变量的函数
-
闭包 = 函数 + 上下文引用 的组合
总结:形成闭包要有两个条件,缺一不可。 (1)函数 (2)访问其他函数内部变量
作用:解决变量污染(一般用于回调函数)
深拷贝与浅拷贝
- 拷贝与深拷贝:
-
浅拷贝: 拷贝的是地址, 修改拷贝后的数据对原数据有影响
-
深拷贝:拷贝的是数据, 修改拷贝后的数据对原数据没有影响
- 拷贝有两种实现方式
-
推荐使用:json转换 (
JSON.parse(JSON.stringify(obj))) -
递归函数
递归案例
数据
实现代码
补充
slice可以查询数组,默认情况下不传参,这个方法会得到数组本身,slice方法存储在Array.prototype(slice(num1,num2),数组切片,一个参数为从第一个下标到最后,两个参数为第一个到第二个下标,左闭右开)- 实际开发中,将伪数组转为真数组:用
Array.from(伪数组) - 数据类型分为:五种值类型,三种引用类型
注意
- 调用对象中的属性两种方式:
对象.属性名,或者,对象['属性名'] - 函数是数据类型,也可以像其他数据一样直接使用语法
setTimeout(function(){ console.log(this) }.bind({name:'干饭'}),3000)
第四板块
解构赋值(对象和数组解构方式差不多)
- 取出对象的属性 赋值给 变量
- let {name,age,sex} = 对象名
- 取出变量的值 赋值给 对象的属性
- 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'})
注意:在函数传参中对象的解构需要用大括号{}包起来
箭头函数
- 箭头函数语法 : 就是function简写
-
把function单词 替换成 箭头 =>
-
把形参() 移到 箭头的 左边
- 箭头函数其他用法:
-
如果只有一个形参,则可以省略形参小括号
a=>{ return a*2 } -
如果函数体只有一行,则可以省略大括号。此时必须要省略
return变为a=>a*2
箭头函数this
箭头函数this指向 : 箭头函数没有this(箭头函数的this和调用无关,取决于声明位置)
-
箭头函数中使用this,会访问上级作用域this
-
原因(作用域链):箭头函数没有this, 就会往上级作用域找
注意:
- 由于箭头函数没有this,所以箭头函数不能作为构造函数(new会修改this指向,而箭头没有this)
- 箭头函数也无法修改this(call apply bind)对箭头函数是无效的
- 事件处理函数,注意不要用箭头函数
this指向-案例
展开运算符
-
展开运算符 : ...
-
作用: 相当于遍历对象简写
-
应用场景:
-
连接数组(上拉加载下一页):arr1.push(...arr2)
-
求数组最大值 : Math.max(...arr)
数据类型Set(集合)
-
类似于数组,与数组唯一的区别是 :不能存储重复元素
-
应用 : 数组去重
补充:一行代码去重(两种写法):
let newArr = Array.from(new Set(数组))let newArr = [...new Set(arr)]
数组迭代方法
map方法
- map场景 : 映射数组(对数组每一个元素进行映射处理,得到一个全新数组)
- 特点
-
回调执行次数 === 数组长度
-
本身返回值 : 映射之后的新数组
-
回调函数内部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字符串
三个步骤:
- 用map把数组中的数据映射成对应的html字符串
- 拼接字符串
- 替换元素的innerHTML
另一种写法(一句语法生成)
filter方法
- filter场景 : 筛选数组(找出数组中符合条件的元素)
- 特点
- 回调执行次数 === 数组长度
- 本身返回值 : 筛选之后的新数组
- 回调函数内部return
- return true : 满足筛选条件,当前元素放入新数组中
- return false : 不满足筛选条件,当前元素不放入新数组
forEach方法
-
forEach场景 : 遍历数组(一般用在不需要取下标的情况下)
-
forEach方法特点
- 遍历次数 === 数组长度
- 本身返回值:无
- 回调函数内部return:无
some方法
- some场景 : 判断数组中是否
有满足条件的元素
- 例子:判断数组中有没有负数
- some方法特点
-
回调执行次数 != 数组长度
-
本身返回值
- true : 有满足条件的元素
- false: 没有满足条件的元素
- 回调函数内部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方法
-
数组reduce方法 : 给每一个元素执行一次回调
-
应用场景: 数组求和、求数组最大值
-
语法:
let res = arr.reduce((sum,value,index)=>{ return sum+value },0)
- res返回值是最后一次sum的结果
- 注意点: 一定要给初始值,否则reduce遇到空数组就会报错
注意
- 实际开发中,尽量中
const,如果有必要修改的变量,才用let - 定时器的this始终指向window
- map一般用来动态拼接HTML字符串,再封装起来;filter一般用来做条件筛选