函数this三种指向:
环境对象this:
谁调用我,this就指向谁
普通函数:
函数名() this - window
对象方法:
对象名.方法名() this - 对象
构造函数:
new 函数名() this - 实例对象
小技巧:
有new就是实例对象,有点就是左边的对象,无new就是window
函数上下文调用:
call()调用函数:
函数名.call(修改后的this,形参1,形参2...)
注意点:
函数体内部不能重新赋值,因为进入函数体,就形成了上下文,函数内部的this不能被修改,所以需要在外部使用call修改
万能检测数据类型:
Object.prototype.toString.call(检测的数据)
基本检测数据类型(typeof)的时候不严谨,null和数组检测不出来,这个时候我们需要使用数据链根据数据链的就近原则发现他会去找自己,他原本就有一个tostring
所以我们就使用object点上原型里面的prototype,但是这个时候我们需要精准找数据类型,所以我们要使用call进行检测,因为call是修改this的指向,如果不加call,那就默认寻找object.prototype.tostring的thisObject.prototype.toString.call(检测的数据)
场景1:伪数组转真数组
伪数组:有数组三要素(下标,元素,长度),但是没有数组的方法伪数组本质是对象
如果希望伪数组也可以调用数组的方法(排序,拼接),就需要把伪数组转成真数组
1.slice可以查询数组,默认情况下不传参这个办法会的得到数组本身
2.但是伪数组由于原型不是Array,所以无法调用slice
3.slice方法存储在哪里?:Array.prototype
实际开发中,ES6新增语法用于伪数组转真数组:Array.from(伪数组)
很久以前,伪数组转真数组需要借助call
1.数组.slice()会得到一个与自身元素一样的真数组
2.但是伪数组本质是对象,无法通过原型链找到slice的
3.不找原型链,直接Array.prototype.slice()
4.直接用原型中的方法,就需要修改this
apply()调用函数:
函数名.apply(修改后的this,[数组/伪数组])
apply会自动帮你遍历数组,然后按照顺序逐一传参
apply和call的区别:
1.共同点:都是修改this指向
2.不同点:apply传的参数必须是一个数组/伪数组 有多个参数的时候可以使用apply来传,会自动遍历数组,按照顺序逐一传参,call传的参数可以是多个,参数列表(参数1,参数2...)
let weiArr = { 0:10, 1:11, 2:12, 3:13, length:4 } let arr = [] //这里需要修改this,所以apply第一个参数写arr,保持原先的this不变 //使用apply主要就是借助他的传参特点,多个参数可以直接放入数组穿进去 arr.push.apply(arr.weiArr) console.log(arr)
bind()调用函数:
函数名.bind(修改后的this)
bind不会立即执行函数,而是返回一个修改this之后的新函数
一般不会({},)后面写值,因为写了就会把内容固定死,无法修改
const fn1 = fn.bind({ name: '王五' })
fn1(5, 10)
1.call 和 apply 和 bind 三者区别
相同点 :
作用一致,修改函数this指向
不同点 :
传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参
执行机制不同 : call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数
2.函数传参的时候,如果值类型和引用类型有什么区别
值类型 简单数据类型 引用类型 复杂数据类型
3.函数传参的时候,如果传值类型和引用类型有什么区别?
如果是值类型:实参是把数据拷贝给形参,在函数内部修改形参,对实参没有影响.
如果是引用类型:实参是把地址拷贝给形参,在函数内部修改形参,实参也会修改(如果在函数内部修改形参的堆地址的数据)
闭包closure是什么 :
闭包是访问了另一个函数局部变量的函数 闭包是组合 = 函数 + 上下文引用 闭包就是JavaScript中的空气,它无处不在
闭包作用 : 解决变量污染
垃圾回收机制:
1.垃圾回收机制:GC 浏览器会自动回收多余的内存 2.谷歌浏览器垃圾回收:标记清除法 当变量引用数据的时候,这个时候数据所在的内存空间就会被标记.如果变量重新赋值了,原先的旧值就会清除标记过一段时间,谷歌内核就会自动扫描内存,保留被标记的内存,清除没有标记
递归:
递归函数: 一个函数在内部调用自己
递归作用和循环类似的,也需要有结束条件,不然就会死循环
浅拷贝与深拷贝
1.浅拷贝:引用类型只拷贝地址,不拷贝数据,修改拷贝后的数据对原数据有影响. a.直接赋值 b.object.assign(目标对象,源对象) 2.深拷贝:拷贝的是数据,修改拷贝后的数据对原数据没有影响 a.json转换 b.loadsh库 c.递归
深递归:
浅拷贝与深拷贝 : 方式一(推荐) : JSON方式实现
let newObj = JSON.parse( JSON.stringify( obj ) )
方式二(递归) : 了解
lodash库实现深拷贝
<script src="./lodash.js"></script> const obj1 = _.cloneDeep( obj ) • obj1.hobby[0] = '敲代码' • console.log(obj,obj1)
递归实现:
使用递归函数 • 创建一个空对象,然后深拷贝 • newObj是拷贝后的对象,obj是要深拷贝的对象 • function cloneDeep(newObj, obj) { • 遍历对象属性,拷贝赋值 • for (let key in obj) { • 1.如果是数组,则声明一个空的数组,然后遍历数组,逐一拷贝元素 • if (obj[key] instanceof Array) { • 声明空数组 •newObj[key]=[] • 递归 cloneDeep(newObj[key],obj[key])}else if(obj[key]instanceof Object){ 声明空数组 newObj[key] = {} 递归 cloneDeep(newObj[key],obj[key])}else{ newObj[key] = obj[key] } • } • }