改变this的指向 call,apply,bind
前言:
js中的变量作用域
作用域指一个变量的作用范围
作用域分为全局作用域和函数作用域
全局作用域 页面打开时创建,关闭时被销毁(全局对象window)
函数作用域:
1.调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
2.在函数作用域中访问变量,会先在自身作用域中寻找,若没有找到会到函数的上层作用域中寻找,一直到全局作用域
3.在函数作用域中,不使用变量关键字声明,在赋值时会往上一级作用域寻找已经声明的同名变量,至到全局作用域时没有找到,则会成为window 属性
call apply bind
相同点
改变函数执行的上下文就是当执行一个方法的时候希望能够使用另一个对象来作为作用域对象
不同点
call
call和apply的差别在于参数的区别,call的第二个参数以参数列表的形式展现
apply
apply第二个参数以数组的形式展现
bind
事先先把fn的this改变为我们想要的结果,并把对应的参数值准备好,以后用到了直接执行即可,但和call,apply不同就是不会马上执行
常见面试题
将伪数组转化为数组
js的伪数组
(通过document.getElementByTagName获取的元素、含有length属性的对象,函数的参数arguments)具有length属性并且可以通过0,1,2…下标来访问其中元素,但没有Array的push,pop等方法。
case1: dom节点:
<div class="div1">1</div>
<div class="div1">2</div>
<div class="div1">3</div>
let div = document.getElementsByTagName('div');
console.log(div); // HTMLCollection(3) [div.div1, div.div1, div.div1] 里面包含length属性
let arr2 = Array.prototype.slice.call(div);
console.log(arr2); // 数组 [div.div1, div.div1, div.div1]
但是这个不适用IE6~8,会报错
解决方法 通过循环一个个加到数组中
for (var i = 0; i < oLis.length; i++) {
ary[ary.length] = oLis[i];
}
Array.prototype.slice.call() 对于arguments对象和含有length的对象不存在 IE兼容问题
数组的拼接,添加
let arr1 = [1,2,3];
let arr2 = [4,5,6];
//数组的concat方法:返回一个新的数组
let arr3 = arr1.concat(arr2);
console.log(arr3); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [1, 2, 3] 不变
console.log(arr2); // [4, 5, 6] 不变
// 用 apply方法
[].push.apply(arr1,arr2); // 给arr1添加arr2
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // 不变
判断变量类型
let arr1 = [1,2,3];
let str1 = 'string';
let obj1 = {name: 'thomas'};
//
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(fn1(arr1)); // true
// 判断类型的方式,这个最常用语判断array和object,null(因为typeof null等于object)
console.log(Object.prototype.toString.call(arr1)); // [object Array]
console.log(Object.prototype.toString.call(str1)); // [object String]
console.log(Object.prototype.toString.call(obj1)); // [object Object]
console.log(Object.prototype.toString.call(null)); // [object Null]
利用call,apply做继承
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
// Animal.call(this) 的意思就是使用this对象代替Animal对象,那么
// Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了
var cat = new Cat("TONY");
cat.showName(); //TONY
多继承
function Class1(a,b) {
this.showclass1 = function(a,b) {
console.log(`class1: ${a},${b}`);
}
}
function Class2(a,b) {
this.showclass2 = function(a,b) {
console.log(`class2: ${a},${b}`);
}
}
function Class3(a,b,c) {
Class1.call(this);
Class2.call(this);
}
let arr10 = [2,2];
let demo = new Class3();
demo.showclass1.call(this,1); // class1: 1,undefined
demo.showclass1.call(this,1,2); // class1: 1,2
demo.showclass2.apply(this,arr10); // class2:2,2
参考资料‘:https://juejin.cn/post/6844903567967387656