千家信息网

如何改变函数的this指向

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,本篇内容介绍了"如何改变函数的this指向"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!如果是函数声
千家信息网最后更新 2025年01月16日如何改变函数的this指向

本篇内容介绍了"如何改变函数的this指向"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

如果是函数声明,那么函数内部的this指向全局对象或者调用该函数的对象。

箭头函数的this绑定的是父级作用域内的this

使用call,apply,bind可以绑定this指向。其中bind是永久改变this指向并且不会立即执行。apply,call临时改变this指向并且立即执行。

apply,call不同之处在于调用的参数形式:

call(thisArg, arg1?, arg2?, arg3?…)第一个参数代表this指向,剩下的参数就是原函数的参数。

apply(thisArg, argArray?)第一个参数代表this指向,第二个参数是以数组的形式传递参数。

/* bind, call, apply调用示例 */

var obj = {

x: 'obj',

getX: function() {

// 注意这里不能使用箭头函数

return this.x;

}

};

// 调用 obj 对象上的函数属性, this就会绑定为obj

// 'obj'

console.log(obj.getX());

var x = 'window';

function target(a, b, c) {

console.log(a, b, c);

return this.x;

}

/* bind */

// undefined undefined undefined

// 'window'

console.log(target());

const targetBound = target.bind(obj, 1); // 此时targetBound就是一个改变了this指向的target

// 1 2 3

// 'obj'

console.log(targetBound(2, 3));

/* call */

// 4 5 6

// 'obj'

console.log(target.call(obj, 4, 5, 6));

/* apply */

// 7 8 9

// 'obj'

console.log(target.apply(obj, [7, 8, 9]));

自定义实现call,apply,bind

这三个函数都有很强的错误处理功能,假如传入的thisArg是一个基本类型,也会被使用包装类替换,虽然不会报错,但是不推荐这样写,尽量传递复杂类型的变量作为thisArg。

自定义实现myBind,myCall,myApply

// 先定义一个函数将任意类型都转换成对象,用于指向this

function anyToObj(value) {

// symbol, bigint 就不判断了,直接在default中

switch (typeof value) {

case 'boolean':

return new Boolean(value);

case 'number':

return new Number(value);

case 'string':

return new String(value);

case 'undefined':

return this;

case 'object':

if (value === null) return this; // 这里的this就指向了全局对象

return value;

default:

return value;

}

}

/* myBind */

Function.prototype.myBind = function (thisArg, …argArray) {

// 防止出现 const myBind = Function.prototype.myBind; myBind();

if (typeof this !== 'function') {

throw new TypeError('myBind must be called on a function');

}

const that = this; // this 就指向 f.myBind() 的 f

const thatArg = anyToObj(thisArg); // 处理一下thisArg

const myBound = function (…args) {

// 指定唯一的键

const tempKey = Symbol('__innerFunction__');

thatArg.tempKey = that; // 将 that 函数赋值给一个对象的属性

let ret;

if (this instanceof myBound) {

// 调用 myBind 之后返回的是 myBound,假如调用 new myBound(),就会进这个分支

ret = new thatArg.tempKey(…argArray.concat(args));

} else {

// 这里是调用 myBound(),这样调用 tempKey 方法里的 this 就指向了 thatArg

ret = thatArg.tempKey(…argArray.concat(args));

}

// 不会对对象造成污染

delete thatArg.tempKey;

return ret;

};

return myBound;

};

/* myCall */

// 与 myBind 相比直接调用了

Function.prototype.myCall = function (thisArg, …argArray) {

if (typeof this !== 'function') {

throw new TypeError('myCall must be called on a function');

}

const thatArg = anyToObj(thisArg);

const tempKey = Symbol('__innerFunction__');

thatArg.tempKey = this;

const ret = thatArg.tempKey(…argArray);

delete thatArg.tempKey;

return ret;

};

/* myApply */

// 与 myCall 相比,第二个参数希望是数组形式,多了个 CreateListFromArrayLike 用于转化 argArray

Function.prototype.myApply = function (thisArg, argArray) {

if (typeof this !== 'function') {

throw new TypeError('myApply must be called on a function');

}

const CreateListFromArrayLike = function (val) {

// 同样缺乏 bigint 的处理,直接放在 default 中

switch (typeof val) {

case 'string':

case 'number':

case 'boolean':

case 'symbol':

throw new TypeError('CreateListFromArrayLike called on non-object');

case 'object':

if (Array.isArray(val)) return val;

if (val === null) return [];

return Array.from(val);

default:

return [];

}

};

// 检测 argArray 的类型

const tempArgArray = CreateListFromArrayLike(argArray);

const thatArg = anyToObj(thisArg);

const tempKey = Symbol('__innerFunction__');

thatArg.tempKey = this;

const ret = thatArg.tempKey(…tempArgArray);

delete thatArg.tempKey;

return ret;

};

// 这样 myBind,myCall,myApply就完成了,下面进行测试

var obj = {

x: 'obj',

getX: function(a, b, c) {

console.log(a, b, c);

return this.x;

}

}

var x = 'window';

// 1 2 3

// 'obj'

console.log(obj.getX(1, 2, 3));

// target变成一个全局函数,this 指向全局对象

const target = obj.getX;

// 1 2 3

// 'window'

console.log(target(1, 2, 3));

/* myBind */

const targetBound = target.myBind(obj, 1);

// 1 2 3

// 'obj'

console.log(targetBound(2, 3));

/* myCall */

// 4 5 6

// 'obj'

console.log(target.myCall(obj, 4, 5, 6));

/* myApply */

// 7 8 9

// 'obj'

console.log(target.myApply(obj, [7, 8, 9]));

"如何改变函数的this指向"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0