本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
this指向
三种this指向
环境对象this : 谁调用'我',我就指向谁(this的指向取决于函数的调用,与声明无关)
- 普通函数 : 函数名() this指向window
- 对象方法 对象名.方法名() this指向对象
- 构造函数 new 函数名() this指向new创建的那个实例对象
this的指向只有这三种情况
平时我们判断this的指向就是三选一
技巧:
(1)先看有没有点. 有点无脑this指向对象
(2)再看有没有new ,有new就是指向实例对象
(3)以上两种都不是就是window
修改this指向
如果我们不手动修改this的指向,那么它是由上下文确定的,不会改变的,但我们在特殊的情况下可能需要修改this的指向
上下文调用:修改函数内this的指向
- 函数名.call(修改this, 参数1 , 参数2 ...)
- 函数名.apply(修改this,[数组])
- 函数名.bind(修改this)
call()
call()方法可以传入多个参数,第一个参数写this指向的对象,剩下的写参数
伪数组转为真数组的三种方式
-
数组.slice(start,end)
slice方法不传参数的话会默认返回真数组自身,但伪数组中却没有真数组的slice方法,那么我们可以将数组的构造函数的原型对象的方法指向伪数组,相当于伪数组调用了这个方法,就会使用slice方法,返回为一个真数组
let obj = { 0:88, 1:60, 2:90, length:3 } let arr = Array.prototype.slice.call(obj); console.log( arr ); -
ES6: Array.from(伪数组);
ES6为我们提供了一个伪数组转真数组的固定语法 Array.from
-
第三种使用apply()方法 在下面讲
apply()
这个方法和call()的用法都一样,但是apply的参数要放在一个数组中,apply方法会自动遍历这个数组
接上使用apply将数组转为真数组
let obj = {
0:88,
1:60,
2:90,
length:3
}
let arr = [];
//第一个参数传arr目的 : 让push方法中的this不变
arr.push.apply(arr,obj);
使用apply求数组最大值
let arr = [10,12,12,451,4,854,51,21];
//使用Math.max方法
let max = Math.max.apply(Math,arr);
//这样的话apply就会依次调用arr里面的值和函数的返回值进行比较,直到比较完,那么就是最大的了
//ES6 有一种更方便的做法 ..是ES6新增的一个运算符, 作用与apply类似,会自动遍历数组然后逐一传参
Math.max(...arr);
bind()
这个方法有点不一样,上边的call和apply都是立即执行,而bind只会修改this的指向返回一个修改后的新函数等待调用 且 新函数的this无法被修改(call,apply都无效),如果传入了其他参数,参数也无法修改,固定住了
由于bind()的特点,所以实际开发中主要也用于和它特点相同的场景,比如定时器
let fn = function(){
console.log( this )
}
//修改fn的this
let newFn = fn.bind({name:'张三'})
// newFn : 变量取值语法 newFn() : 函数调用,得到返回值
//修改定时器的指向
setTimeout( function(){
console.log(this)
}.bind({name:'李四'}) , 1000)
call,apply,bind三者的区别
1.call、apply、bind三者区别
(1)相同点 : 作用一致,都是修改函数的this
(2)不同点 :
a.传参方式不同 : call()是逐个传参,apply()是数组/伪数组传参
b.执行机制不同 : call()、apply() 立即执行函数,bind()不会立即执行而是得到修改this后的新函 数
闭包
闭包就是一个函数有权访问另一个函数内部变量的函数
mdn官方给的解释是
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合
个人理解:函数+上下文引用
闭包无处不在
function fn(){
let num = 10
// fn1函数 + num引用 形成闭包
function fn1(){
console.log(num) //使用了fn里面的局部变量num 所以形成了闭包 closure
}
fn1();
}
fn();
闭包可以延长局部变量的生命周期
function fn(){
let num = 10
// fn1函数 + num引用 形成闭包
return function(){
num++;
console.log(num);
}
}
let newfn = fn();
newfn(); //11
newfn(); //12
newfn(); //13
newfn(); //14
//销毁
newfn = null;
递归
一个函数内部自己调用自己(递归要有结束条件,否则会死循环)
递归算是一种算法,时间复杂度高,用于遍历树形结构
深拷贝与浅拷贝
浅拷贝 : 拷贝的是(栈)地址. 修改拷贝后的数据,对原数据‘有影响’
深拷贝 : 拷贝的是(堆)数据。 修改拷贝后的数据,对原数据‘没有影响’
let newObj = JSON.parse( JSON.stringify(obj) );//使用json实现深拷贝
或者使用递归....
let obj = {
name: '张三',
age: 20,
sex: '男',
hobby: ['吃饭', '睡觉', '学习'],
student: {
name: '萌萌',
age: 18
}
}
let newobj = {};
function copy(newobj, obj) {
for (const key in obj) {
console.log(key);
if (obj[key] instanceof Array) {
newobj[key] = [];
copy(newobj[key], obj[key]);
} else if (obj[key] instanceof Object) {
newobj[key] = {};
copy(newobj[key], obj[key]);
} else {
newobj[key] = obj[key];
}
}
}
copy(newobj, obj);
newobj.name = '芒果';
newobj.hobby[0] = '嘻嘻哈哈';
newobj.student.name = 'mango';
//修改拷贝后数据的值对原数据没有影响
console.log(newobj, obj);