修改this指向
方法 | 参数 | 返回值 | 作用 |
---|---|---|---|
call | thisArg, arg1, arg2, ... ,注意,call接收的参数是一个参数列表 | 函数返回值 | 调用一个函数,将其 this 值设置为提供的值,并为其提供指定的参数。 |
apply | thisArg, [arg1, arg2, ...] ,请注意这里,apply接收的参数是一个参数数组 | 函数返回值 | 调用一个函数,将其 this 值设置为提供的值,并以数组形式为其提供参数。 |
bind | thisArg, arg1, arg2, ... | 新函数 | 创建一个新函数,当调用这个新函数时,它的 this 值被绑定到提供的值,并且它的参数序列前置指定的参数。 |
可以使用apply()
和call()
方法以新创建的对象为上下文执行构造函数
开始之前,因为这三个都是会改变this的指向,而this指向是js中很重要的一个部分,所以我们停一停,复习一下this指向,以便更好地认识和实现这仨兄贵
this指向
1、构造函数通过new
关键字构造对象时, this指向被构造出的对象
function Game(name, type){
this.name = name;
this.type = type;
Game.prototype.showThis = function(){
console.log(this)
}
}
var dmc = new Game('DMC', 'ACT')
dmc.showThis()
可以看到指向的是被构造出来的dmc
2、全局作用域中,this指向window
3、谁调用方法,this指向谁
4、普通函数非通过其他人执行,this指向window
function fn(){
console.log(this)
}
fn() //window
function fn1(){
console.log(this) // window
function fn2(){
console.log(this)
}
fn2() // window
}
fn1()
// 被赋值后再调用
var obj = {
fn: function(){
console.log(this)
}
}
var fn3 = obj.fn
fn3() // window
5、数组里面的函数,按照数组索引取出运行时,this指向该数组,其实就是数组调用函数,所以指向数组
function fn(){
console.log(this)
}
var arr = [fn1]
arr[0]() // [fn] --> 就是arr
6、=>
函数中的this指向他的父级非=>
函数this
call
、apply
都不能改变=>
函数的this
以上可以浓缩为:非
=>
函数的this指向它执行时的上下文对象,=>
函数的this指向它的父级非=>
函数的this
7、call
、apply
、bind
可以改变函数运行时候函数中this的指向
节流防抖中可以使用这种方式实现
call
call的主要用途:
- 直接调用函数
- 可改变函数内部的this
- 可以实现继承
使用上面的例子:
- fn() 相当于 fn.call(null)
- fn(fn2)相当于fn.call(null, fn2)
- obj.fn()相当于obj.fn.call(obj)
手写:
// context - 传入的执行上下文对象, 不传或者传null就默认为window
// args - 传入的参数列表
Function.prototype.myCall = function(context, ...args){
// this只有指向函数才能执行
if(typeof this != 'function'){
return new TypeError(`type error! ${this} is not a function`)
}
// 获取传入的执行上下文context, 若未传入则指向window, 就是例如fn.call()、fn.call(null)这种
context = context || globalThis // 使用globalThis是考虑到web和node下的全局this不一样
// 缓存this到传入的执行上下文对象去执行, 这一步相当于改变了this指向, 即指向了context
context.fn = this
// this指向改变后, 传入参数, 原fn在执行上下文对象运行并缓存此时fn在context下运行得到的返回值
const res = context.fn(...args)
// 用完就删除执行上下文中新增的this, 取消绑定
delete context.fn
// 返回原fn在context下运行得到的返回值
return res
}
apply
apply的用途:
- 调用函数,改变内部的this指向
- 参数必须为数组
- 主要应用于数组类
// apply和call很像,就后面传参有点改动
Function.prototype.myApply = function(context, args){
if(typeof this != 'function'){
return new TypeError(`type error! ${this} is not a function`)
}
context = context || globalThis
context.fn = this
// 因为传入的是数组, 所以如果没有参数就不要展开传进fn执行
const res = args ? context.fn(...args) : context.fn()
delete context.fn
return res
}
bind
- 改变原函数内部指向
- 返回改变指向后的拷贝
这里因为返回的是拷贝,所以我们要return的是一个function
Function.prototype.myBind = function(context, ...args1){
if(typeof context != 'undefined'){
return new TypeError(`type error! ${this} is not a function`)
}
context = context || globalThis
context.fn = this
return function(...args2){
const res = context.fn(...args1, ...args2)
delete context.fn
return res
}
}