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 5002、场景:对象中的函数,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;iarguments[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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
关注你微信了!
[***.104.42.241]2024年03月24日 03时37分53秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
【u3d泰斗破坏神】08 --- UGUI 制作艺术字体
2019-04-26
【u3d泰斗破坏神】09 --- 角色血条的制作、掉血特效
2019-04-26
Unity Shader 入门精要(01) -- 渲染流水线
2019-04-26
Unity Shader 入门精要(02) -- shader的编码基础
2019-04-26
Unity Shader 入门精要(03) -- Unity的基础光照
2019-04-26
Unity Shader 入门精要(04) -- 基础纹理
2019-04-26
Unity3D 移动平台的资源路径问题
2019-04-26
二分查找(折半查找)
2019-04-26
线段树
2019-04-26
编程机制
2019-04-26
自己写的Java版计算器
2019-04-26
字、位、字节摘抄的,怕忘了
2019-04-26
printf与scanf的用法知识(C Primer Plus总结)
2019-04-26
三目运算符(条件运算符)
2019-04-26
C语言中的goto语句
2019-04-26
欧几里德算法及拓展
2019-04-26
CSDN-markdown编辑器基本用法
2019-04-26
等差数列公式搜集
2019-04-26
复合字面量(compound literal)
2019-04-26
gets和puts
2019-04-26