Javascript方法callapplybind的解析与实现
Posted 橘猫吃不胖~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javascript方法callapplybind的解析与实现相关的知识,希望对你有一定的参考价值。
javascript方法call、apply、bind的解析与实现
1 this的指向
this
的指向,始终坚持一个原理:this
永远指向最后调用它的那个对象。下面我们来看几个简单的例子:
例1:在下面的例子中,非严格模式下,this.name
打印出的是橘猫吃不胖
,因为最后调用fun()
的地方是全局对象window
,相当于window.fun()
,所以this
指向了Window
。
var name = "橘猫吃不胖";
function fun()
var name = "小明";
console.log(this.name); // 橘猫吃不胖
console.log("fun内this:", this); // fun内this:Window
fun();
console.log("fun外this:" + this); // fun外this:Window
例2:在下面这个例子中,函数fun
是被对象obj
调用的,所以this
的指向就是obj
,this.name
就是对象obj
中的name
的值。
var name = "橘猫吃不胖";
var obj =
name: "小明",
fun: function ()
console.log(this.name); // 小明
obj.fun();
例3:下面的例子中,虽然对象obj
中的fun
函数被赋值给了a
,但是调用函数a()
的是全局对象Window
,因此this.name
就是橘猫吃不胖
。
var name = "橘猫吃不胖";
var obj =
name: "小明",
fun: function ()
console.log(this.name); // 橘猫吃不胖
var a = obj.fun;
a();
例4:在箭头函数中,this
引用的是定义箭头函数的上下文。下面的例子中,箭头函数是在Window
上定义的,因此箭头函数的this
会保留定义该函数的上下文。
let name = "橘猫吃不胖";
let obj =
name: "小明"
;
let fun = () => console.log(this.name);
fun(); //橘猫吃不胖
obj.fun = fun;
obj.fun(); // 橘猫吃不胖
所以this
指向的场景总结如下:
1、全局单独使用的
this
,与普通函数中的this
,都指向全局对象Window
,严格模式下,this
指向undefined
;
2、调用对象中的方法时,this
指向该对象;
3、构造函数中的this
,指向了该构造函数的实例对象;
4、箭头函数中的this
,指向了定义箭头函数的上下文;
2 如何改变this的指向
使用call
、apply
、bind
函数可以改变this
的指向。
下面会详细说明这三个函数的运用与实现。
3 call
3.1 使用方式
call()
方法接收一些参数:第一个参数是函数内this
的值,剩下的参数是其他的参数。它以指定的this
值调用函数,即设置调用函数时函数体内this
对象的值。用法如下:
函数.call(this值, 参数1, 参数2, 参数3......);
例如:
fun.call(this, 10, 20, 30);
示例代码:
let obj = num: 10 ;
function sum(num1, num2)
console.log(this.num + num1 + num2);
sum.call(obj, 10, 20); // 40
在上面的例子中,sum
使用了call
方法,使this
从原本的Window
变成了obj
对象,那么sum
函数内的this.num
就是obj.num
就是10,因此最后输出40。
3.2 call的实现
首先,我们在调用call
方法时,是直接在函数上调用的,说明call
方法定义在Function
的原型对象上,第一个参数是其内部this
指向的对象,其余参数用rest
参数接收:
// obj是内部this要指向的对象
Function.prototype.myCall = function (obj, ...args)
// ...
接下来,判断调用该方法的是不是一个函数,如果不是函数,应该报错:
// obj是内部this要指向的对象
Function.prototype.myCall = function (obj, ...args)
// 如果调用该方法的不是函数,即this不是function,报错
if (typeof this !== "function") return new TypeError("TypeError");
判断是否传入了obj
,如果没有传入,应该让其指向Window
:
// obj是内部this要指向的对象
Function.prototype.myCall = function (obj, ...args)
// 如果调用该方法的不是函数,即this不是function,报错
if (typeof this !== "function") return new TypeError("TypeError");
// 如果没有传入obj,那么this要指向Window
obj = obj ? obj : window;
设置result
存放最终的结果,给obj
定义fun
函数,使其等于this
,也就是调用myCall
方法的函数,再执行obj.fun
,并传入参数args
,结果赋值给result
:
// obj是内部this要指向的对象
Function.prototype.myCall = function (obj, ...args)
// 如果调用该方法的不是函数,即this不是function,报错
if (typeof this !== "function") return new TypeError("TypeError");
// 如果没有传入obj,那么this要指向Window
obj = obj ? obj : window;
// 存放最终的结果
let result = null;
// 将调用myCall的函数赋值给obj.fun
obj.fun = this;
// 调用obj.fun,使this指向obj
result = obj.fun(...args);
最后,我们将obj
上新增的方法fun
删去,返回结果result
即可,整体实现代码如下:
// obj是内部this要指向的对象
Function.prototype.myCall = function (obj, ...args)
// 如果调用该方法的不是函数,即this不是function,报错
if (typeof this !== "function") return new TypeError("TypeError");
// 如果没有传入obj,那么this要指向Window
obj = obj ? obj : window;
// 存放最终的结果
let result = null;
// 将调用myCall的函数赋值给obj.fun
obj.fun = this;
// 调用obj.fun,使this指向obj
result = obj.fun(...args);
//删除obj上新增的方法fun
delete obj.fun;
// 返回结果
return result;
4 apply
4.1 使用方式
apply()
与call()
的不同之处在于第二个参数的形式。
apply()
方法接收两个参数:函数内this
的值和一个参数数组。第二个参数可以是数组的字面量,也可以是Array
的实例对象,但也可以是arguments
对象。它也是以指定的this
值调用函数,即设置调用函数时函数体内this
对象的值。用法如下:
函数.apply(this值, Array);
例如:
fun.apply(this, ["张三", "李四"]); // 第二个参数是数组字面量表示方式
fun.apply(this, new Array("张三", "李四")); // 第二个参数是Array的实例对象
示例代码:
let obj = num: 10 ;
function sum(num1, num2)
console.log(this.num + num1 + num2);
sum.apply(obj, [10, 20]); // 40
在上面的例子中,sum
使用了apply
方法,使this
从原本的Window
变成了obj
对象,那么sum
函数内的this.num
就是obj.num
就是10,因此最后输出40。
4.2 apply的实现
同样,调用apply
方法时,是直接在函数上调用的,说明apply
方法定义在Function
的原型对象上,第一个参数是其内部this
指向的对象,第二个参数用args
参数接收:
// obj是this需要指向的对象
Function.prototype.myApply = function (obj, args)
// ...
判断是否是函数调用了myApply
,不是则报错:
// obj是this需要指向的对象
Function.prototype.myApply = function (obj, args)
// 如果不是函数调用myApply,报错提示
if (typeof this !== "function") return new TypeError("TypeError");
判断是否传入了obj
,如果没有传入,应该让其指向Window
:
// obj是this需要指向的对象
Function.prototype.myApply = function (obj, args)
// 如果不是函数调用myApply,报错提示
if (typeof this !== "function") return new TypeError("TypeError");
// 是否传入了obj,不是则指向window
obj = obj ? obj : window;
设置result
存放最终的结果,给obj
定义fun
函数,使其等于this
,也就是调用myApply
方法的函数,再执行obj.fun
,并传入参数args
,结果赋值给result
:
// obj是this需要指向的对象
Function.prototype.myApply = function (obj, args)
// 如果不是函数调用myApply,报错提示
if (typeof this !== "function") return new TypeError("TypeError");
// 是否传入了obj,不是则指向window
obj = obj ? obj : window;
// 存放最终的结果
let result = null;
// 将调用myApply的函数this赋值给obj.fun
obj.fun = this;
// 调用obj.fun,使this指向obj
result = obj.fun(...args);
最后,我们将obj
上新增的方法fun
删去,返回结果result
即可,整体实现代码如下:
// obj是this需要指向的对象
Function.prototype.myApply = function (obj, args)
// 如果不是函数调用myApply,报错提示
if (typeof this !== "function") return new TypeError("TypeError");
// 是否传入了obj,不是则指向window
obj = obj ? obj : window;
// 存放最终的结果
let result = null;
// 将调用myApply的函数this赋值给obj.fun
obj.fun = this;
// 调用obj.fun,使this指向obj
result = obj.fun(...args);
// 删掉obj.fun
delete obj.fun;
return result;
5 bind
5.1 使用方式
bind()
方法会创建一个新的函数实例,其this
值会被绑定到传给bind()
的对象。它的返回值也是方法,接受的第一个参数是一个对象,其余参数会作为新的函数的参数。用法如下:
函数.bind(this值, 参数1, 参数2, 参数3......);
例如:
fun.bind(this, "aaa", "bbb", "ccc");
示例代码:
let obj = num: 20 ;
function num()
console.log(this.num);
console.log(Math.max(...arguments));
let pnum = num.bind(obj, 2, 3, 5, 7, 68, 8);
pnum(); // 20 68
在上面的代码中,num
使用了bind
方法,但是该函数并未立即被调用,而是使其this
从原本的Window
变成了obj
对象,返回了一个函数并赋值给了pnum
,所以调用pnum
函数,this.num
就是obj.num
就是20,其余的参数执行后会输出68。
5.2 bind的实现
调用bind
方法时,是直接在函数上调用的,说明bind
方法定义在Function
的原型对象上,第一个参数obj
是其内部this
指向的对象,第二个参数用args
参数接收:
Function.prototype.myBind = function (obj, ...args)
// ...
判断是否是函数调用了myBind
,不是则报错:
Function.prototype.myBind = function (obj, ...args)
// 如果不是函数调用了myBind,则报错
if (typeof this !== "function") return new TypeError("TypeError");
判断是否传入了obj
,如果没有传入,应该让其指向Window
:
Function.prototype.myBind = function (obj, ...args)
// 如果不是函数调用了myBind,则报错
if (typeof this !== "function") return new TypeError("TypeError");
// 判断是否传入了obj,如果没有传入,应该让其指向Window
obj = obj ? obj : window;
将调用myBind
的函数赋值给fun
,并在myBind
函数最后返回一个函数,该函数就是fun
使用了apply
方法:
Function.prototype.myBind = function (obj, ...args)
// 如果不是函数调用了myBind,则报错
if (typeof this !== "function") return new TypeError("TypeError");
// 判断是否传入了obj,如果没有传入,应该让其指向Window
obj = obj ? obj : window;
// 将调用myBind的函数存放起来
let fun = this;
// 返回一个函数,并为该函数预留出传参数的空间
return function Fn(...rest)
return fun.apply(obj, args.concat(rest));
6 call、apply、bind的区别
call
和apply
的区别:
call
方法接受的是若干个参数列表,而apply
接收的是一个包含多个参数的数组
bind
和apply
、call
区别:
1、
bind
不会立即调用函数,call
和apply
会立即调用
2、bind
与call
接收的参数形式相同,第一个都是this
要指向的对象,其余的参数是其他参数,apply
第一个参数是this
要指向的对象,第二个参数是数组
以上是关于Javascript方法callapplybind的解析与实现的主要内容,如果未能解决你的问题,请参考以下文章