聊一聊call、apply、bind

问:改变this指向的方法有哪些?

三种(我知道的)

call 、apply 、bind(这里不含es6语法讲解)

我在复习这几个方法的时候,看了很多博客和讨论,前面两种都很好理解,但是bind(我笨)的自定义,我花了一点时间去适应!

话不多说,开始探索:

1.call

对于call,以前只知道是改变this的一种方法以及怎么用,但是没考虑过当前环境是严格模式还是非严格模式,在一番学习之后,我发现了一点有意思的知识。

第一点:(怎么用)

call的使用很简单,直接看代码!

let obj = {a:1};
function sayHi(a){
	console.log("summer 真乖!");
	console.log("this是",this);
	console.log(a);
}
sayHi();    
sayHi.call(obj,9999);//第一个参数是this要指向的对象,后面的参数是传递给函数的参数(可以传多个)

输出:
window
undefined

obj:{a:1}
9999

在这里插入图片描述

使用真的easy了。

接下来,看看严格模式和非严格模式下的区别吧!

其实区别就是对于第一个参数的处理不同(我所知道的,有其他不同,评论指出,感谢!)

非严格模式下:

function test (val){
    console.log("this----",this);
    console.log("val-----",val);
}
test.call(1,999);

输出
this---- Number {1}
val----- 999

严格模式下:

'use strict'
function test1 (val){
    console.log("this----",this);
    console.log("val-----",val);
}
test1.call(1,888);

输出
this---- 1
val----- 888

在这里插入图片描述
在这里插入图片描述

实际告诉我们:


🎈 在非严格模式下:如果传入一个原始类型的数据( Number 、String 、 Boolean 、Symbol)等,它的内部会先进行对象包装,将传入的原始类型的数据转化成一个包装对象,再将函数的this指向这个包装对象,而不是原始数据本身


🎈 在严格模式下:call的第一个参数传入什么,调用的函数就指向什么!不进行任何操作!

不理解,可以看上面的代码和图示,表达的很清楚!

2.apply

apply和call真的差不多,只不过传递参数的方式不太一样,所以这里就不再详细讲,介绍一下用法:

function test (...args){
    console.log("this----",this);
    console.log("val-----",arguments);
}
test.apply(true,[1,2,3]);//后面传递参数使用的是数组

输出:
this---- Boolean {true}
val----- Arguments(3) [1, 2, 3, callee: (...), Symbol(Symbol.iterator): ƒ]

包括对于第一个传入参数的处理,和call也是一致的

apply___ VS ___ call

call传递参数(第一个以后的),可以单个传,也可以传数组 ! 😲

apply传递参数(第一个以后的),可以传数组,不能穿单个值 ! 😲

在这里插入图片描述

3.bind
与call和apply的区别:

call和apply改变函数的this指向后,直接执行函数💡

bind改变函数的this指向后,返回一个函数,而不是立马执行 💡

看实际效果:

let obj = {a:1}

function test(){
    console.log("bind----",this);
}
let res = test.bind(obj);//调用bind后返回一个函数,原函数并没有立马执行
console.log(res);
res();

输出 : 
ƒ test(){
    console.log("bind----",this);
}
bind---- {a: 1}

有趣的是,bind和call、apply一样,在非严格模式下,对于第一个参数的处理是一样的👇👇

"use strict"
function test1(){
    console.log("bind-----",this);
}
test1.bind(1)();

输出 :
bind----- 1

在这里插入图片描述

你以为到这里结束了?当然不是!!!

当函数调用bind改变this指向后,会返回一个函数,那可不可以让返回的这个函数的this也改变呢?🤔

let obj = {a:1};
let jbo = {b:1};
function t(){
    console.log(this);
}
let first = t.bind(obj);
first();
let second = first.bind(jbo);
second();
{a: 1}
{a: 1}

在这里插入图片描述

答案是不行,💥bind改变this指向后,就不能二次改变了,除非函数二次调用bind💥

在这里插入图片描述

4.自定义

相信看完,或多或少都有提升吧!

接下来,我们一起看看如何自己实现call、apply、bind方法吧!

myCall💡

Function.prototype.myCall = function(context = window, ...args) {
	let type = typeof context;
	context = context == null || context == undefined ? window : context;
	context.fn = null;
if (type == "number" || type == "string" || type == "boolean") {
    switch (type) {
        case "number":
            context = new Number(context);
            break;
        case "string":
            context = new String(context);
            break;
        case "boolean":
            context = new Boolean(context);
            break;
    }
    context.fn = this;
} else {
    context.fn = this;
}
	const res = context.fn(...args);
	delete context.fn;
	return res;
}

myApply💡

Function.prototype.myApply = function(context = window, ...args) {
	let type = typeof context;
	context = context == null || context == undefined ? window : context;
	context.fn = this;
	const res = context.fn(...args);
	delete context.fn;
	return res;
}

myBind💡

Function.prototype.myBind = function(context) {
    if (typeof this != "function") {
        throw new Error("this is not a function");
    }
    let _this = this;
    let oargs = Array.prototype.slice.call(arguments, 1);
    let Func = function() {
        let iargs = Array.prototype.slice.call(arguments);
        return _this.apply(this instanceof Func ? this : context, oargs.concat(iargs));
        // 因为调用bind之后返回的是一个函数,所以有可能作为构造函数被new了,所以这里要加一个判断,保证原型上的东西不丢
    }
    let Fnull = function() {}
    Fnull.prototype = this.prototype;
    Func.prototype = new Fnull();
    return Func;
}

对于自定义方法,都是我个人学习和自我总结之后写的,如果有错误,还请各位大佬指正!

好了,对于改变this(不含es6)的方法,我介绍完了,欢迎大家评论补充、纠错!

觉得有用,记得给个赞,哈哈😁

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

summer·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值