javascript学习笔记--理解apply()、call()、bind() 以及caller、callee属性

xiaoxiao2021-02-28  131

本文目录如下: - 前言 - apply()、all()函数、bind()函数 - caller属性与callee属性 - 总结


前言

在公司做一些全栈开发,实际上也不算,啥都会一点儿,其中就包括前端的javascript脚本语言。之前有过一些代码经验(代码算不上精致,用面向对象语言,写面向过程的代码逻辑),最近,突然想,无论什么语言,多沉淀一下总是好的,于是有了这个博客专栏,希望用笔头记下自己学习的点点滴滴,欢迎大家拍砖。

apply()函数与call()函数

  无论是小白还是老司机,相比对这两个大名鼎鼎的函数不陌生。先来看看这两个函数的基本描述:

对于javascript脚本语言,所有的函数都包含这两个函数,不需要任何的继承 他们的用途都是一样的,都是为了扩充函数的功能,有的说法也叫作用域,比较难以理解接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。 call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。      对于前面两点,实际上还是比较好理解的,想必对于第三点,尤其是对于我这种小白来说,还是比较蒙逼的,什么是函数运行作用域?下面举个例子,然后看起运行的行为,然后我们再来重新进行定义,让第三点读起来通俗易懂。 //声明一个Person对象 function Person(name){ this._name=name this.showName=function(){//打印自己名字的方法showName() return this._name; } } //声明一个Chinese对象,无showName() function Chines(name){ this._name = name; } } //声明一个American对象,showName() function American(name){ this._name = name; } } //从声明来看,这三个函数没有依赖关系; //那么现在Chinese和American都想有一个这样的方法,有什么解决思路呢? /* 1.继承 已经超出本文的研究范围,不做深入研究 2.在这两个对象中加上showName()方法,那如果是100个对象呢,是不是要写100遍这个函数,这个简直就是灾难 3.利用apply()和call方法 */ //ok,讨论完方案之后我们来改造下代码,当然我们直接摒弃了方法2,因为方法2太low了,我们来说下方法3 function Chinese(name){ Persion.apply(this); this._name=name } //声明一个American对象,showName() function American(name){ Persion.apply(this); this._name=name } //wait 这不就是第二种方法吗,实际上还是要在每个对象上加代码,不过我们的代码看起来优雅了不少,下面来跑下测试结果看看 var chinese = new Chinese("chenglong"); var american = new American("john"); console.log(chinese.showName()); //输出chenglong console.log(american.showName()); //输出john //通过apply,两对象就有了Person对象的方法了 //当然用call方法也是一样的,不过call方法需要指定具体的参数,看起来像这个样子 function Chinese(name){ Person.call(this,name); this._name=name } //声明一个American对象,showName() function American(name){ Person.call(this,name); this._name=name } var chinese = new Chinese("chenglong"); var american = new American("john"); console.log(chinese.showName()); //输出chenglong console.log(american.showName()); //输出john //你也可以不用继承的方式 这就退化成了普通的调用了,这种方式不必改造任何的代码 //声明一个Chinese对象,无showName() function Chinese(name){ this._name = name; } //声明一个American对象,showName() function American(name){ this._name = name; } var person = new Persion("person"); var chinese = new Chinese("chenglong"); var american = new American("john"); console.log(person.showName.apply(chinese)); //输出chenglong console.log(person.showName.call(chinese,"chenglong")); //输出chenglong console.log(person.showName.apply(american)); //输出john console.log(person.showName.call(american,"john")); //输出john //看起来这种情况下,apply更优雅,但是没指定参数,总是发慌,用call限定了参数;而且多了个person对象,真让人不爽,因此把apply和call运用到类中,一劳永逸

  现在,我们来总结一下,基本描述的第三点,在继承中我们有一句这样的代码Persion.call(this,name)和 Persion.apply(this),当有了这个代码之后,我们的Chineses从此就有了showName的方法,apply中文是啥意思?应用的意思,我们似乎可以这么拆解:将Person的所有的方法(或者某个方法)应用在apply()/call()传进来的第一个参数上,我们的函数对象(有一个对象A,有一些基础的方法,比如打印名字什么的,而有个对象B,不想重载这些方法,那这个时候就用apply()/call()来把A的方法扩展下吧,为我所用)这就达到了,将Chinese对象的方法进行扩展的目的,不得不佩服javascript语言发明者的绝妙思维。  

bind()函数

 实际上理解了call函数和apply函数之后,再来理解bind函数就没那么难了,bind函数从某种意义上来说,用法和上述两个函数一模一样。最大的区别是,bind函数具有懒加载,可以用着回调,该函数实际上返回的是一个更换了this指针的函数引用,你可以不立即执行它,将它保存在变量中,而apply和call就不行,你调用了就立即执行。举个例子:  

var obj = { x: 100, }; var foo = { getX: function() { return this.x; } } console.log(foo.getX.bind(obj)()); //100 console.log(foo.getX.call(obj)); //100 console.log(foo.getX.apply(obj)); //100 //虽然结果都是一样的,但是你可以发现bind函数在后面多了一对小括号,这就是区别

caller和callee属性

  caller:调用者的意思,返回的是谁是这个函数的调用者的函数引用。举个例子:   

function callerDemo() { if(arguments.caller){//调用者不是null,则返回调用者的函数引用 console.log(callerDemo.caller.toString()); }else { console.log("This function's caller is windows"); } } function handleCaller(){ callerDemo(); } handleCaller();//输出的是handleCaller函数的引用 callerDemo();//This function's caller is windows

callee:callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用。这个特性在递归函数中非常的有用。

function calleeDemo() { alert(arguments.callee); } callerDemo();//打印函数对象本身的引用

总结

最后,再总结一下:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的,第一个参数都是传入的对象的this指针;bind函数返回的是函数,具备回调性质,apply、call立即调用caller 返回的是调用该函数的函数的引用;calee是argument的一个属性方法,返回的是这个函数的本身的引用apply、call、bind的通用理解方式是:xxx对象的xx方法运用到xxx对象上(obj.method.apply,call,bind),使得目标对象的方法得到了扩展
转载请注明原文地址: https://www.6miu.com/read-35774.html

最新回复(0)