网站首页 > 技术文章 正文
改变函数中this指向的方法
结合 MDN 官网中 JavaScript 章节中对this详解,我们了解到了函数原型对象中改变this指向的三种方法,分别为bind、apply、call,在以下的内容中会进行详细的介绍。
一、对this的理解
在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。ES5 引入了 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。ES2015 引入了箭头函数,ES2015 引入了箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)。代码如下所示:
// 普通函数
const test1 = {
prop: 42,
func: function() {
return this.prop;
},
};
console.log(test1.func()); // expected output: 42
// 箭头函数
const test2 = {
prop: 42,
func: ()=> {
console.log(this.prop)
},
}
console.log(test.func());// expected output: undefined
二、为什么需要改变这个 this 的指向?
需要改变这个 this 的指向,是因为原来的 this 被污染了,需要重新再进行 this 指向,因为,this 指向的是被调用的父级作用域,而如果函数在另一个函数里面执行的时候,那么,这个 this 的指向的就是这个函数,而不是那个被执行函数原来的那个作用域。如下代码所示:
const fighter = {
fire: function (res) {
console.log(this.model);
},
};
setTimeout(function () {
fighter.fire();
}, 1000);
// undefined
此时,setTimeout() 里面的函数 this 的指向是指向了 window,而 fighter.fire() 这个函数的执行 this是需要指向这个 fighter 的。所以,执行的时候控制台就会输出 undefined 。因为在 fighter 这个域下找不到这个 model 的参数。这个就需要把这个 this 的指向改成指向有nodel变量的对象中。以下是改变 this 指向的方法。
三、使用 call 改变 this 指向
函数(Function)的原型对象中有一个call方法,调用call方法可以传递多个参数,但是第一个参数是改变this指向的目标对象,剩下的参数都会传递到调用call方法的函数,并且call方法调用也相当于call方法前面的函数被调用了。代码如下所示:
const fighter = {
fire: function (args1, args2) {
console.log(this.model);
console.log(args1);
console.log(args2);
},
};
setTimeout(function () {
fighter.fire.call({model:'700'}, 'fire', '700');
}, 1000);
// 700
// fire
// 700
四、使用 apply 改变 this 指向
使用 apply 改变 this 指向和 call 改变指向大致上方法是一样的,唯一有不同的就是apply方法只会只会接收两个参数如果传递超出的参数并不会返还给调用apply方法的函数,而且第二个参数规定是一个数组。代码如下所示:
const fighter = {
fire: function (args1) {
console.log(this.model);
console.log(args1);
},
};
let plane = fighter.fire;
setTimeout(function () {
plane.apply({model:'700'}, ['1']);
}, 1000);
// 700
// 1
// 如果第二个参数没有传递一个数组的话,那apply方法就会报 TypeError 类型错误;
const fighter = {
fire: function (res) {
console.log(this.model);
},
};
setTimeout(function () {
fighter.fire.apply({model:'700'},111);
}, 1000);
// VM435:7 Uncaught TypeError: CreateListFromArrayLike called on non-object at <anonymous>:7:16
五、使用 bind 改变 this 指向
bind的执行和前面的 call 和 apply 的执行是不一样的,call 和 apply 是立即执行一次。而 bind 是手动执行同时 bind 是永久改变 this 的指向。如下代码所示:
function f() {
return this.a;
}
const g = f.bind({ a: 'azerty' });
console.log(g()); // azerty
const h = g.bind({ a: 'yoo' }); // bind only works once!
console.log(h()); // azerty
const o = { a: 37, f, g, h };
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty
像这个例子,变量 g 是需要手动执行才会触发,这是第一点。另一点是下面再次执行 g() 的时候,由于,前面已经使用过 bind 改变了 this 的指向。这个时候再次调用 f 这个函数,就不需要再改变 this 的指向了,直接执行就可以。
六、总结
6.1「相同点」
都可以改变函数内部的this指向。
6.2「不同点」
call、apply会自动调用函数,bind需要手动调用。
call、bind有无数个参数,apply只有2个参数,且第二个参数必须为数组。
6.3「使用场景」
call 经常做继承。
apply 经常跟数组有关系。比如借助数学对象实现数组最大值最小值
bind 不调用函数,但是还想改变this指向时。比如改变定时器内部的this指向
6.4「区分call、apply」使用场景
// 1. 数组追加
var array1 = [12, "foo", {name: "Joe"}, -2458];
var array2 = ["Doe", 555, 100];
Array.prototype.push.apply(array1, array2);
console.log(array1)
// [12, "foo", {name: "Joe"}, -2458, "Doe", 555, 100]
// 2.最大值最小值
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
- 上一篇: JS面试之数组的几个不low操作
- 下一篇: JMeter后置处理器之JSON Extractor
猜你喜欢
- 2024-11-21 浅析GIF 格式图片的存储与解析
- 2024-11-21 如何用2 KB代码实现3D赛车游戏?2kPlus Jam大赛了解一下
- 2024-11-21 快速了解ES6的代理与反射
- 2024-11-21 「实战」蘑菇街 PC 端首页,瀑布流布局的实现原理与细节技巧
- 2024-11-21 Knative 驾驭篇:带你 '纵横驰骋' Knative 自动扩缩容实现
- 2024-11-21 ECMAScript 6使用教程总结
- 2024-11-21 一道二进制子串算法,让面试官都解不出来?
- 2024-11-21 高级前端进阶,为什么要使用call、apply、bind?
- 2024-11-21 碎片时间学编程「202]:分组数组元素
- 2024-11-21 从入门到入土:Lambda完整学习指南,包教包会(上)
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-