JavaScript学习笔记:call、apply、bind的理解及应用


一、基础部分理解

  1. call、apply 和 bind 都是用于改变函数运行时的上下文,即函数内部 this 所指的对象
  2. call 和 apply 的唯一区别是参数的写法:
    function.call(obj, parameter1, parameter2…)
    function.apply(obj, [parameter1, parameter2…])
  3. bind 和 call、apply 的区别是 使用bind并不会立刻调用函数,而后两者都是立刻调用

二、举例理解

1. 不引入参数

var a, b;

function test_1(){
	this.id = "test1";
	this.record = function(){
		console.log("test 1 function id: " + this.id);
	};
};

function test_2(){
	this.id = "test2";
	this.record = function(){
		console.log("test 2 function id: " + this.id);
	};
};

a = new test_1();
b = new test_2();

a.record();//result: "test 1 function id: test1"
b.record();//result: "test 2 function id: test2"

b.record.call(a); //result: "test 2 function id: test1"

我们可以看到本来a, b都正确打印出来所调用函数内部的id,但是当 b 调用了call 就将函数本来的 this 从指向本身 test_2 转为指向 a, 结果 b 虽然调用的是 test_2 的方法,但打印出来的 id 却是属于 test_1 的, 这就是因为 call 改变了 test_2 的 record 函数运行时的上下文

2.引入参数

var a, b;

function test_1(){
	this.id = "add";
	this.reference = 5;
	this.record = function(c){
		console.log("function id: " + this.id + " parameter: " + c + " " + this.reference + "  result: " + (c + this.reference));
	};
};

function test_2(){
	this.id = "sub";
	this.reference = 6;
	this.record = function(d){
		console.log("function id: " + this.id + " parameter: " + d + " " + this.reference + "  result: " + (d - this.reference));
	};
};

a = new test_1();
b = new test_2();

a.record(1);//result: "function id: add parameter: 1 5 result: 6"
b.record(2);//result: "function id: sub parameter: 2 6 result: -4"

b.record.call(a, 2); //result: "function id: add parameter: 2 5 result: -3"

我们可以看到引入参数后,参数本身不受 call 影响,因为 call 改变的是函数运行时的上下文,所以所有用 this 指定的变量都会被新 this 对象的上下文覆盖, 此例中 reference 参数就由本来的 6 变为了 test_1 中的 5,但是注意 最终执行的还是 test_2 的 record 方法

二、应用理解

纠结这三个函数的用法主要还是遇到了实际应用的问题

window.onload = function(){
    var test = new RecordShift();
};

class RecordShift{
    constructor(){
        this.div = document.createElement("div");
        this.div.style.setProperty("z-index", 10);
        this.div.style.setProperty("background-color", "#66d9ff");
        this.div.style.setProperty("position", "absolute");
        this.div.style.setProperty("display", "block");
    
        this.div.style.setProperty("left", window.innerWidth * 0.5 + "px");
        this.div.style.setProperty("top",  window.innerHeight * 0.5 + "px");
        this.div.style.setProperty("width", "25px");
        this.div.style.setProperty("height", "25px");

        this.div.draggable = true;

        this.start_position_x = 0;
        this.start_position_y = 0;
        this.div.addEventListener("dragstart", this.start);
        this.div.addEventListener("dragend", this.end.bind(this));

        document.body.appendChild(this.div);
    }

    start(){
        this.start_position_x = window.event.clientX;
        this.start_position_y = window.event.clientY;

        console.log("drag start position x: " + this.start_position_x + " y: " + this.start_position_y);
    }


    end(){
        this.shift_x = window.event.clientX - this.start_position_x;
        this.shift_y = window.event.clientY - this.start_position_y;

        console.log("drag end   position x: " + this.shift_x + " y: " + this.shift_y);
    }
}

当我们运行这段代码,页面中间将出现一个方块,拖动方块,可以触发 start 和 end 这两个函数,正确地打印出拖动开始的坐标和结束时的相对位移

在这里插入图片描述
现在稍微改造一下这个类,添加一个打印函数,再次运行代码

    end(){
        this.shift_x = window.event.clientX - this.start_position_x;
        this.shift_y = window.event.clientY - this.start_position_y;

        console.log("drag end   position x: " + this.shift_x + " y: " + this.shift_y);

        this.log();
    }

    log(){
        console.log("class log function");
    }

在这里插入图片描述
结果发现报错了,未找到 this.log 函数,明明坐标也是用 this 在类里指定好的,怎么变量就可以正常打印,函数就不可以了?这就是因为它们的上下文不一样导致的,这时候就要用到 call、apply 或者 bind 了。只需要改动这一个地方即可,在 this.end 后面添加 .bind(this),再次运行,没有报错,一切正常

this.div.addEventListener("dragend", this.end.bind(this));

在这里插入图片描述


总结

JS的坑不是一般的多呐…防不胜防的
希望对你有所帮助

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值