js 里函数调用有4种模式:方法调用、正常函数调用、构造器函数调用、apply/call 调用。
同时,不管哪一种函数调用除了你声明时定义的形参外,还会自动添加2个形参,分别是 this 和 arguments。
这里你既然问 this,那么就只谈 this。this 的值,在上面4中调用模式下,分别会绑定不一样的值。分别来讲一说:
方法调用:
这个很好理解,函数是一个对象的属性,好比javascript
var a = { v : 0, f : function(xx) { this.v = xx; } } a.f(5);
这个时候,上面函数里的 this 就绑定的是这个对象 a。因此 this.v 能够取到对象 a 的属性 v。java
正常函数调用:
依然看代码数组
function f(xx) { this.x = xx; } f(5);
这个时候,函数 f 里的 this 绑定的是全局对象,若是是在浏览器运行的解释器中,通常来讲是楼上说的 window 对象。因此这里 this.x 访问的实际上是 window.x ,固然,若是 window 没有 x 属性,那么你这么一写,按照 js 的坑爹语法,就是给 window 对象添加了一个 x 属性,同时赋值。浏览器
构造器函数调用:
构造函数一直是我认为是 js 里最坑爹的部分,由于它和 js 最初设计的基于原型的面向对象实现方式格格不入,就好像是特地为了迎合你们已经被其余基于类的面相对象实现给惯坏了的习惯。
若是你在一个函数前面带上 new 关键字来调用,那么 js 会建立一个 prototype 属性是此函数的一个新对象,同时在调用这个函数的时候,把 this 绑定到这个新对象上。固然 new 关键字也会改变 return 语句的行为,不过这里就不谈了。看代码app
function a(xx) { this.m = xx; }var b = new a(5);
上面这个函数和正常调用的函数写法上没什么区别,只不过在调用的时候函数名前面加了关键字 new 罢了,这么一来,this 绑定的就再也不是前面讲到的全局对象了,而是这里说的建立的新对象,因此说这种方式其实很危险,由于光看函数,你不会知道这个函数究竟是准备拿来当构造函数 用的,仍是通常函数用的,因此咱们能够看到,在 jslint 里,它会要求你写的全部构造函数,也就是一旦它发现你用了 new 关键字,那么后面那个函数的首字母必须大写,这样经过函数首字母大写的方式来区分,我我的只有一个见解:坑爹:)函数
apply/call 调用:
咱们知道,在 js 里,函数其实也是一个对象,那么函数天然也能够拥有它本身的方法,有点绕,就好像函数能够本身有属性也是一个函数。其中每一个函数都拥有 apply() 这个方法,让咱们构造一个参数数组传递给函数,同时能够本身来设置 this 的值,这就是它最强大的地方,上面的3种函数调用方法,你能够看到,this 都是自动绑定的,没办法由你来设,当你想设的时候,就能够用 apply() 了。apply 接收2个参数,第一个是将传递给这个函数的 this 的值,第二个是参数数组。看代码:this
function a(xx) { this.b = xx; }var o = {}; a.apply(o, [5]); alert(a.b); // undefinedalert(o.b); // 5
是否是很神奇,函数 a 竟然能够给 o 加属性值。固然,若是你 apply 的第一个参数传递 null,那么在函数 a 里面 this 指针依然会绑定全局对象。你可能要问了,apply 函数是哪来的,由于在 js 里全部的函数都有一个共同的 prototype,也就是传说中的 Function.prototype, 这个原型里有两个神奇的方法,一个就是这里的 apply ,另外一个就是让题主疑惑的 call。prototype
说了这么一大堆,终于来到 call 了。
call() 方法和 apply() 方法很相似,它们的存在都是为了改变 this 的绑定,那 call() 和 apply() 有什么区别呢?就我我的看来,没啥鸟区别。。。开玩笑!刚刚说了,上面 apply() 接收两个参数,第一个是你想要 this 绑定的对象,第二个是一个参数数组,注意是一个数组,你想传递给这个函数的全部内容都放在数组里,而后 apply() 函数会在传递形参时自动帮你展开,同时加入我上面提到的另外一个神奇形参 arguments。而 call() 呢,它的第一个参数也是你想要 this 绑定的对象,可是后面能够接受不定参数,而再也不是一个数组,也就是你能够像平时给函数传参那样把这些参数一个一个传递,固然,神奇形参 arguments 仍是不会少的。因此若是必定要说有什么区别的话,看起来是这样的设计
function a(xx, yy) { alert(xx, yy); alert(this); alert(arguments); } a.apply(null, [5, 55]); a.call(null, 5, 55);
仅此而已。指针
再来看题主的疑问,这样写包裹代码有什么好处呢?这里就必须说一说另外一个关键的地方了,题主贴出来的代码,能够看到这个函数使用严格模式 "use strict",什么是严格模式呢?本身搜去吧。在正常模式下,js 函数里那些你没有声明就使用的变量,实际上是访问的全局对象的属性,好比说上面正常函数调用的时候,函数里的 this ,就访问的是全局对象。可是在严格模式下,不容许这种语法,全部变量都必需要显示声明,因此若是你不用 call() 传递 this 给这个函数,那么就会报错了。由于你在函数里面有一个 return 语句,访问了 this 变量。因此问题不是题主说的这样写有什么好处,而是用了严格模式,就必须这么写。
而后还想说一下,apply() 和 call() ,用它们有什么好处呢?好处就是可让你改变 this,这不是废话吗。改变 this 来干吗呢?可让这个函数,使用 this 的方法,换句话说,就是你的函数能够针对不一样的 this,来调用它们不一样的方法,有点像反射机制。哈哈,我扯远了。