js中的call,apply,bind区别
在JavaScript中,call、apply和bind是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向。
call、apply、bind方法的共同点和区别:apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文(函数的每次调用都会拥有一个特殊值——本次调用的上下文(context)——这就是this关键字的值。);apply 、 call 、bind 三者都可以利用后续参数传参;bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
一、call
call()
语法:
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
thisObj的取值有以下4种情况:
(1) 不传,或者传null,undefined, 函数中的this指向window对象
(2) 传递另一个函数的函数名,函数中的this指向这个函数的引用
(3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean
(4) 传递一个对象,函数中的this指向这个对象
function a(){
console.log(this); //输出函数a中的this对象
}
function b(){}
var c={name:"call"}; //定义对象c
a.call(); //window
a.call(null); //window
a.call(undefined); //window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b); //function b(){}
a.call(c); //Object
如果你不理解上面的,没关系,我们再来看一个例子:
function class1(){
this.name=function(){
console.log("我是class1内的方法");
}
}
function class2(){
class1.call(this); //函数class1调用call方法,并传入this(this为class2构造后的的对象),传入的this对象替换class1的this对象,并执行class1函数体实现了class1的上下文(确切地说算伪继承,原型链才算得上真继承)。
}
var f=new class2();
f.name(); //调用的是class1内的方法,将class1的name方法交给class2使用
常用例子:
(1)
function eat(x,y){
console.log(x+y);
}
function drink(x,y){
console.log(x-y);
}
eat.call(drink,3,2);
输出:5
这个例子中的意思就是eat只算是临时调用了(或说实现了)一下drink函数。
你可以console.log(window,eat.toString()); 你可以看到eat的函数体还是原来的。window上下文还是保持着eat,drink原来的函数体,eat.call(drink,3,2) == eat(3,2) ,所以运行结果为:console.log(5);
注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。
(2)
function Animal(){
this.name="animal";
this.showName=function(){
console.log(this.name);
}
}
function Dog(){
this.name="dog";
}
var animal=new Animal();
var dog=new Dog();
animal.showName.call(dog);
输出:dog
在上面的代码中,我们可以看到Dog里并没有showName方法,那为什么(this.name)的值是dog呢?
关键就在于最后一段代码(animal.showName.call(dog)),意思是把animal的方法放到dog上执行,也可以说,把animal 的showName()方法放到 dog上来执行,所以this.name 应该是 dog。
(3)继承
function Animal(name){
this.name=name;
this.showName=function(){
console.log(this.name);
}
}
function Dog(name){
Animal.call(this,name);
}
var dog=new Dog("Crazy dog");
dog.showName();
输出:Crazy dog
Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么Dog就能直接调用Animal的所有属性和方法。
二、apply()
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
call 和 apply的区别
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。
function class1(args1,args2){
this.name=function(){
console.log(args,args);
}
}
function class2(){
var args1="1";
var args2="2";
class1.call(this,args1,args2);
/*或*/
class1.apply(this,[args1,args2]);
}
var c=new class2();
c.name();
输出:1 2
call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
既然两者功能一样,那该用哪个呢?
在JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call ;而不确定的时候用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。
三、bindbind是在EcmaScript5中扩展的方法(IE6,7,8不支持)bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
注意:bind方法的返回值是函数
var bar=function(){
console.log(this.x);
}
var foo={
x:3
}
bar();
bar.bind(foo)();
/*或*/
var func=bar.bind(foo);
func();
输出:
undefined
3
-------------------------------------------------------------
下面就【借用一道面试题】,来更深入的去理解下 apply 和 call 。
function log(msg) {
console.log(msg);
}
log(1); //
log(1,2); //
上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:
function log(){
console.log.apply(console, arguments);
};
log(1); //
log(1,2); //1 2
接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:
log("hello world"); //(app)hello world
该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
var sed = {
x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
var fiv = {
x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?
答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。
在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。 像这样:
var foo = {
bar : 1,
eventBind: function(){
var _this = this;
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(_this.bar); //
});
}
}
由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $('.someClass').on('click',function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:
var foo = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(this.bar); //
}.bind(this));
}
}
转自:https://www.cnblogs.com/libin-1/p/6069031.html
js中的call,apply,bind区别的更多相关文章
- js中call与apply的区别以及使用~
今天看了一下call与apply的区别~~ <!DOCTYPE html> <html> <head> <title>testCall</titl ...
- js 中 new call apply bind JSON.stringify 的原理以及模拟实现
1.new的原理和实现 它创建了一个全新的对象. 它会被执行 [[Prototype]](也就是 __proto__)链接. 它使 this指向新创建的对象. 通过 new创建的每个对象将最终被 [[ ...
- js中call()和apply()的区别
· 它们的共同之处: 都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象.” · 它们的不同之处: apply: 最多只能有两个参数—— ...
- Javascript中call和apply的区别与详解
在js中call和apply它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式有所区别,下面我来给大家介绍一下call和apply用法: 在web前端开发过程中,我们经常需要改变th ...
- JS中isPrototypeOf 和hasOwnProperty 的区别 ------- js使用in和hasOwnProperty获取对象属性的区别
JS中isPrototypeOf 和hasOwnProperty 的区别 1.isPrototypeOf isPrototypeOf是用来判断指定对象object1是否存在于另一个对象object2的 ...
- call apply bind 区别?
call apply bind 区别? 例:定义一个计算器,没绑定bind的为公共计算器,call可以调用,绑定bind的为私人计算器,别人调用不了, //ps:用bind绑定的call强制作借用不好 ...
- (网页)Angular.js 中 copy 赋值与 = 赋值 区别
转自st.gg Angular.js 中 copy 赋值与 = 赋值 区别 为什么用 $scope.user = $scope.master; $scope.master 会跟着 $scope.use ...
- js中的substr和substring区别
js中的substr和substring区别 Substring: 该方法可以有一个参数也可以有两个参数. (1) 一个参数: 示例: var str=“Olive”: str.substring( ...
- JS 中的require 和 import 区别整理
ES6标准发布后,module成为标准,标准的使用是以export指令导出接口,以import引入模块,但是在我们一贯的node模块中,我们采用的是CommonJS规范,使用require引入模块,使 ...
随机推荐
- kernel-init-bash
https://www.kernel.org/doc/Documentation/kernel-parameters.txthttp://unix.stackexchange.com/question ...
- Qt ------ QWidget 自定义子类使用信号与槽(Q_OBJECT)后 stylesheet 失效
这个应该属于 Qt 的一个bug,Qt assistant 给出相应的解决办法:重写函数“void paintEvent(QPaintEvent *event);”,添加下面截图中的一段代码
- python 常用模块之os
1.权限判断 bool: os.access('/python/test.py',os.F_OK) #是否存在 bool: os.access('/python/test.py',os.R_OK) # ...
- ubunto 16.04 lts 源
http://601502546.blog.163.com/blog/static/2596107620171502517889 国内有很多ubuntu的源,包括:网易源(这个之前用过,速度很快的), ...
- ElasticStack系列之十六 & ElasticSearch5.x index/create 和 update 源码分析
开篇 在ElasticSearch 系列十四中提到的问题即 ElasticStack系列之十四 & ElasticSearch5.x bulk update 中重复 id 性能骤降,继续这个问 ...
- angularjs的Controller as
<html ng-app="notesApp"> <head><title>Notes App</title></head&g ...
- 一、Kafka初认识
一.kafka使用背景 1.Kafka使用背景 在我们大量使用分布式数据库.分布式计算集群的时候,是否会遇到这样的一些问题: 我们想分析下用户行为(pageviews),以便我们设计出更好的广告位 我 ...
- angularJS $watch $apply $digest
看O'Reilly的书看到$watch这部分,不过没看懂,网上很多资料也含糊不清,不过还是找到了几个好的,简单记录一下. 一句话说明,$watch是用来监视变量的,好了直接上代码 <html&g ...
- 令assignment操作符返回一个reference to *this
[令assignment操作符返回一个reference to *this] 关于赋值,可以把它们写成连锁形式: int x, y, z; x =y =z =15; II赋值连锁形式 上述连锁赋值被解 ...
- [转载]HTML5开发入门经典教程和案例合集(含视频教程)
http://www.iteye.com/topic/1132555 HTML5作为下一代网页语言,对Web开发者而言,是一门必修课.本文档收集了多个HTML5经典技术文档(HTML5入门资料.经典) ...