改变this指向:callapplybind
Posted 奥特曼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了改变this指向:callapplybind相关的知识,希望对你有一定的参考价值。
call、apply、bind都是用来改变this指向
1.call
语法:
函数.call(newObj,参数1,参数2,...参数n)
newObj: 要指向的this 当你不想改变this时 可以传null undefined
参数1..参数n: 函数自身需要的参数
let fn = function (a, b) {
console.log(this, a, b);
}
let obj = {
name: "obj"
};
fn() //window undefined undefined
fn.call(obj, 1, 2) // obj对象 1,2
fn.call(this,1,2) // window 1,2
fn.call({},1,2) // {} 1,2
fn.call() // window undefined,undefined
fn.call(window,1,2) // window 1,2
fn.call(undefined,1,2) //window 1,2
fn.call(null,1,2) // window,1,2
fn.call(obj, 1, 2) this指向了第一个参数 obj对象,可以理解为 obj.fn()去调用这个函数
fn.call(this,1,2) 由于函数是在window下定义的 所以说就是指当前的this
对于下面几个花里胡哨的undefined、null 当这个函数处于非严格模式下,则指定为 null
或 undefined
时会自动替换为指向全局对象
fn.call中的call方法哪里来的?
回答这个问题非常简单 无非就是 控制台输出一下,mdn搜索一下
1. console.dir(fn)
通过打印发现 fn函数中的prototype并没有call方法, 而在__proto__方法中有call方法,也就是通过原型链的查找机制去找到这个方法,
也就是在Function上的prototype上有一个call方法,再简单说也就是每个函数都有call、apply、bind方法
2.mdn
结论: console.log(fn.__proto__.call===Function.prototype.call); // true
使用场景
① 继承:将父构造函数中的this指向改为子构造函数的this
function Father(uname, age) {
this.uanme = uname;
this.age = age;
}
function Son(uname, age) { //this 指向实例化对象
// 就是把Father 的参数放到son中运行
Father.call(this, 1, 1); //this 改为new Son 就变成了回调函数
// Father(); //
}
let obj1 = new Son();
console.log(obj1);
下面两个例子来自 凡人进阶
② 判断变量的数据类型 Object.prototype.totString.call
console.log(Object.prototype.toString.call("1"))
// [object String]
console.log(Object.prototype.toString.call(1))
// [object Number]
console.log(Object.prototype.toString.call(false))
// [object Boolean]
console.log(Object.prototype.toString.call([]))
// [object Array]
console.log(Object.prototype.toString.call({}))
// [object Object]
console.log(Object.prototype.toString.call(function(){}))
// [object Function]
Object的原型链上有一个属性叫toString特殊的方法,相当于一个特殊的function 就可以使用call方法,通过里面的参数就可以执行不同类型的this,Object.prototype.toString的返回值是字符串,并不是数组(只是看起来前后有[ ] )。它的返回结果是固定格式的:[object 当前对象的构造器的名字]。
③ 把类数组转成数组
slice
var 新数组 = 数组.slice(起点下标,终点下标)
截取 返回值是一个新数组,参数为包含起点不包含中点 如果不传值相当于进行一次浅拷贝
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
const lis = document.getElementsByTagName('li')
console.log(lis);
const newLis = Array.prototype.slice.call(lis)
console.log(newLis);
</script>
当然 直接const newList = Array.from(lis) 更快哈!
2.apply
apply方法和call方法的用法大致一样 只不过传递的参数方式不同 ,与call的区别就是 apply传递的是数组格式
语法:
函数.call(newObj,[参数1,参数2,...参数n])
newObj: 要指向的this 当你不想改变时可以写null、undefined
参数1..参数n: 函数自身需要的参数
let fn = function (a, b) {
console.log(this, a, b);
}
let obj = {
name: "obj"
};
fn.apply(obj,[1,2]) //obj对象 1,2
fn.apply(window,[1,2]) //window undefined undefined
fn.apply()//window undefined undefined
使用场景
添加数组
const arr = [1,2,3]
const arr2 = [4,5,6]
arr.push.apply(arr,arr2)
console.log(arr); [1,2,3,4,5,6]
第一个参数执行了arr 把arr2中的数据添加到了arr中
拿到数组中最大值
const arr = [1, 2, 3]
console.log(Math.max.apply(null, arr)); //等价于Math.max(numbers[0], ...)
避开了使用循环的方式进行遍历判断 如果使用循环比较麻烦些
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] > max)
max = numbers[i];
if (numbers[i] < min)
min = numbers[i];
}
3.bind
使用bind方法会创建一个新的函数, bind 语法和call一样,和call的区别在于 bind不会立即执行
返回值:返回一个原函数的拷贝,并拥有指定的 this
值和初始参数。
语法:
函数.bind(newObj,参数1,参数2,...参数n)
newObj: 要指向的this 当你不想改变this时 可以传null undefined
参数1..参数n: 函数自身需要的参数
let fn = function (a, b) {
console.log(this, a, b);
}
let obj = {
name: "obj"
};
const newFn = fn.bind(obj, 1, 2)
newFn()
知识点 一般情况下 我们有可能吧对象中的方法拿出来进行调用
this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象
var module = {
x: 81,
getX: function () {
return this.x;
}
};
module.getX(); // 81
var retrieveX = module.getX;
console.log(retrieveX());//9
当把函数拿到外面来时 已经变成了全局作用域下的函数 所以会打印出全局作用域上的x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
再去指回原来的对象
使用场景
发送验证码
<input type="button" value="点击发送验证码">
<script type="text/javascript">
let btn = document.querySelector('input');
btn.addEventListener('click', function () {
// 禁用元素
this.disabled = true;
window.setTimeout(function () {
this.disabled = false;
}.bind(this), 5000);
});
</script>
看到定时器后面有一个改变this执行中的bind方法 如果使用call或者apply他会立即执行达不到5秒后再去关闭disable的效果
如果不加改变this指向 相当于给window上的 disable设为false了 最终永远不会触发当前的disable,只有通过bind(this)指向当前的btn才可以达到效果
总结
call | apply | bind | |
---|---|---|---|
语法 | call:fun.call(this, arg1, arg2......); | apply:fun.apply(this, [arg1, arg2......]); | bind:fun.bind(this, arg1, arg2......); |
相同点 | 都是用来改变this指向 | ||
不同点 | 第二个参数为任意类型 | 第二个参数为数组类型 | 第二个参数为任意类型 |
立即执行 | 立即执行 | 等待调用执行 | |
没有返回值 | 没有返回值 | 返回一个改变this之后的函数 |
以上是关于改变this指向:callapplybind的主要内容,如果未能解决你的问题,请参考以下文章
245 改变函数内部 this 指向:call,apply,bind,callapplybind 三者的异同
2022前端面经---改变this指向问题(callapplybind)
2022前端面经---改变this指向问题(callapplybind)
JavaScript中的callapplybind方法的区别