call、apply、bind
发布日期:2022-02-08 04:21:01 浏览次数:3 分类:技术文章

本文共 4888 字,大约阅读时间需要 16 分钟。

call、apply

  • 假如有一个命名函数fn,有三种写法,都可以执行函数;但是call、apply可以改变this的指向。但如果函数中没有this,call、apply就没有任何意义了,和普通的执行函数概念一样。
  • call、apply的第一个参数都是this的重定向指向;不同的是,call可以有多个参数,apply只有两个参数,第二个参数是一个数组。
  • 如下:
    fn(value1,value2,…);
    fn.call(obj,value1,value2,…);
    fn.apply(obj,[vlaue1,value2,…]);
  • 如果使用call或apply,第一个参数是null,就意味着将函数中this重定向到window(管你之前指向谁)。

1、一般情况下的call、apply应用场景:

function fn(_a,_b){
this.a=_a; this.b=_b; // console.log(this); //this--->window }fn(); //没给参数,给了参数就能打印出所给参数值console.log(a,b); //undefined undefinedvar obj = {
};fn.call(obj, 30, 50);//call在执行函数时,函数的参数从第二位开始依次写入objconsole.log(obj.a,obj.b);//30 50fn.apply(obj, [300, 500]);//apply只有两个参数,第一个是函数中this的指向,第二个是一个数组,这个数组就是函数的参数console.log(obj.a,obj.b);//300 500

在这里插入图片描述

2、场景:对象中的函数,call、apply的应用 :

var obj = {
fn: function (_a, _b) {
this.a = _a; this.b = _b; }}obj.fn(3,5); //this--->obj; console.log(obj); // {a: 3, b: 5, fn: ƒ}var obj1={
};obj.fn.call(obj1,3,5);obj.fn.apply(obj1,[3,5]);console.log(obj,obj1);//{a: 3, b: 5, fn: ƒ} {a: 3, b: 5}obj.fn.call(null,3,5); //把this重新定向给window了// 等同于obj.fn.call(window,3,5);console.log(obj,a,b); //{fn: ƒ} 3 5

在这里插入图片描述

在这里插入图片描述

  • 示例一:下面贴个apply第一个参数为null的巧妙用法(第二个参数,允许作为一个数组传入值)
小知识:Math.max没有this,null,传入以后并没有任何作用,所以用apply目的是传参时传入的是数组。var Math={
max:function(){
if(arguments.length===0)return; var max=arguments[0]; if(arguments.length===1)return max; for(var i=1;i
arguments[i]?max:arguments[i]; } return max; }}var arr=[4,3,7,0];var max=Math.max.apply(null,arr);//apply可以将参数以数组的形式传入var max1=Math.max.call(null,14,3,7,0);//call就不行了,要写好多参数console.log(max,max1);结果显而易见:7 14
  • 示例二:为了了解Array.prototype.slice.call()的使用,然后把slice方法重构一下。
(1)先看一下怎么用的。一般slice的使用方法:var array=[1,2,2];  array.slice();现在想不创建数组,就能使用slice方法的话,可以从原型链里面拿。var divs=document.getElementsByTagName("div");var arr=Array.prototype.slice.call(divs);// 等同于var arr=[].slice.call(divs);console.log(divs,arr);// 这种写法是用了Array原型的概念,arr的原型链下有slice方法,然后用call把slice里的this重定向到divs,就可以复制出divs里的内容给arr。

在这里插入图片描述

(2)slice重构class Array1 {
constructor() {
// 构造函数 } // 属性和方法 动态属性,实例属性,该类的原型属性,实例化的原型链属性 // 动态属性 其实相对static 静态来说的 // 实例属性,该属性是通过new 构造函数来实例化对象以后调用的 // 该类的原型属性 站在类的立场上,类.prototype.属性 ES5中的方式 // 实例化的原型链属性 站在实例对象的的立场上,ES5中,对象中原型链上的方法和属性 slice(start, end) {
// ES6中实例方法中的this就是该类实例化的对象 console.log(this); //目前传入的对象是divs start = Number(start); end = Number(end); if (isNaN(start)) start = 0; if (isNaN(end)) end = this.length; if (start < 0) start = this.length + start; if (end < 0) end = this.length + end; var arr = []; for (var i = start; i < end; i++) {
arr.push(this[i]); } return arr;//返回数组 }}var divs=document.getElementsByTagName("div");var arr=Array1.prototype.slice.call(divs);console.log(arr);// 这里其实就是简单模拟一下Array.prototype.slice.call()的使用机制,arr的原型依然是Array.prototype,因为毕竟返回的是数组。

在这里插入图片描述

总结:

call 执行函数,将该函数中this指向call的第一个参数,如果该函数有参数,那么call的第二个参数开始一 一带入所有参数。
apply 执行函数,将该函数中this指向call的第一个参数,如果该函数有参数,那么apply的第二个参数是这个函数的所有参数组成数组。

bind

prototype 原型

先来简单介绍一下原型的概念:

  • 原型是构造函数(类)的叫法,只有构造函数(类)才有prototype,原型链是针对对象的叫法,只有对象才有__proto__。
  • 对象的原型链和构造函数(类)的原型是同一个引用对象。对象的原型链就是构造函数(类)的原型。
  • ES5中没有类,借用原型的概念实现类(构造函数-ES5;类-ES6;ES5是用首字母大写的命名函数,也就是构造函数来模拟类)。
(1)ES6中的类class Box {
constructor() {
} play() {
console.log(this); // this--->实例对象 }}var b = new Box();console.log(b.__proto__.play() === Box.prototype.play());

在这里插入图片描述

(2)ES5中的类function Box() {
}Box.a = 3;//静态属性Box.once = function () {
// 静态方法}Box.prototype.b = 4;//实例属性Box.prototype.play = function () {
// 实例方法 console.log(this);}var box=new Box();console.log(box.__proto__.play() === Box.prototype.play());

在这里插入图片描述

bind

  • 当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象。
  • bind返回一个绑定obj的新函数。
function fn1(fn){
fn(3); // fn.call(obj,789);}function fn2(_a){
this.a=_a;} // fn1(fn2); //可以使用call在函数fn1中改变fn的this指向并传入参数,但是如果不用这种方式呢?// bind就出现了。var obj={
};fn1(fn2.bind(obj));// 把fn2函数中的this指向obj,并且返回这个被指向this后新的函数console.log(obj);var fns=fn2.bind(obj);// bind返回一个绑定obj的新函数console.log(fns===fn2);// 这里创建了一个新的函数

在这里插入图片描述

  • 举个小栗子:
var b=900;var obj={
b:2, a:function(){
// 回调函数 setTimeout(function(){
console.log(this.b); //这个this指向window },1000); setTimeout((function(){
console.log(this.b); //这个this不再指向window,而是指向obj }).bind(this),100); // 所以就能实现不使用箭头函数也可以把this指向obj // 事件函数 // 比如事件,但删不掉,因为得到的是新函数 // 可以先存储绑定的函数,删除时也是删除这个存储的 this.bindHandler=this.clickHandler.bind(this); document.addEventListener("click",this.bindHandler); }, clickHandler:function(e){
console.log(this.b); document.removeEventListener("click",this.bindHandler); }}obj.a();

在这里插入图片描述

,就大量用到了this、bind。

总结:call、apply会直接执行,但bind是创建一个新的东西,不会立即执行。

转载地址:https://blog.csdn.net/weixin_43297321/article/details/104402583 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:高光小球(径向渐变&mousemove事件)
下一篇:js setter&getter

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年03月24日 03时37分53秒