转自:http://segmentfault.com/q/1010000002519489

1.严格模式下函数调用的 this 并不会默认成为全局对象。

使用 func.call(this) 确保函数调用的 this 指向调用函数时的 this(即全局对象)。

这是比普通 IIFE 的好处。

(function(){
"use strict";
console.log(this === window); // true
}).call(this); (function(){
"use strict";
console.log(this === window); // false
})();

ps:IIFE (Imdiately Invoked Function Expression 立即执行的函数表达式)

2. 简单理解就是,隔离上下文,避免变量冲突。

3. 扩展:js 里函数调用有4种模式:方法调用、正常函数调用、构造器函数调用、apply/call 调用

同时,无论哪种函数调用除了你声明时定义的形参外,还会自动添加2个形参,分别是 this 和 arguments。
这里你既然问 this,那么就只谈 this。this 的值,在上面4中调用模式下,分别会绑定不同的值。分别来说一说:
方法调用:
这个很好理解,函数是一个对象的属性,比如

var a = {
v : ,
f : function(xx) {
this.v = xx;
}
}
a.f();

这个时候,上面函数里的 this 就绑定的是这个对象 a。所以 this.v 可以取到对象 a 的属性 v。

正常函数调用:
依然看代码

function f(xx) {
this.x = xx;
}
f();

这个时候,函数 f 里的 this 绑定的是全局对象,如果是在浏览器运行的解释器中,一般来说是楼上说的 window 对象。所以这里 this.x 访问的其实是 window.x ,当然,如果 window 没有 x 属性,那么你这么一写,按照 js 的坑爹语法,就是给 window 对象添加了一个 x 属性,同时赋值。

构造器函数调用:
构造函数一直是我认为是 js 里最坑爹的部分,因为它和 js 最初设计的基于原型的面向对象实现方式格格不入,就好像是特意为了迎合大家已经被其他基于类的面相对象实现给惯坏了的习惯。
如果你在一个函数前面带上 new 关键字来调用,那么 js 会创建一个 prototype 属性是此函数的一个新对象,同时在调用这个函数的时候,把 this 绑定到这个新对象上。当然 new 关键字也会改变 return 语句的行为,不过这里就不谈了。看代码

function a(xx) {
this.m = xx;
}
var b = new a();

上面这个函数和正常调用的函数写法上没什么区别,只不过在调用的时候函数名前面加了关键字 new 罢了,这么一来,this 绑定的就不再是前面讲到的全局对象了,而是这里说的创建的新对象,所以说这种方式其实很危险,因为光看函数,你不会知道这个函数到底是准备拿来当构造函数用的,还是一般函数用的,所以我们可以看到,在 jslint 里,它会要求你写的所有构造函数,也就是一旦它发现你用了 new 关键字,那么后面那个函数的首字母必须大写,这样通过函数首字母大写的方式来区分,我个人只有一个看法:坑爹:)

apply/call 调用:
我们知道,在 js 里,函数其实也是一个对象,那么函数自然也可以拥有它自己的方法,有点绕,就好像函数可以自己有属性也是一个函数。其中每个函数都拥有 apply() 这个方法,让我们构造一个参数数组传递给函数,同时可以自己来设置 this 的值,这就是它最强大的地方,上面的3种函数调用方法,你可以看到,this 都是自动绑定的,没办法由你来设,当你想设的时候,就可以用 apply() 了。apply 接收2个参数,第一个是将传递给这个函数的 this 的值,第二个是参数数组。看代码:

function a(xx) {
this.b = xx;
}
var o = {};
a.apply(o, []);
alert(a.b); // undefined
alert(o.b); //

是不是很神奇,函数 a 居然可以给 o 加属性值。当然,如果你 apply 的第一个参数传递 null,那么在函数 a 里面 this 指针依然会绑定全局对象。你可能要问了,apply 函数是哪来的,因为在 js 里所有的函数都有一个共同的 prototype,也就是传说中的 Function.prototype, 这个原型里有两个神奇的方法,一个就是这里的 apply ,另一个就是让题主疑惑的 call。

说了这么一大堆,终于来到 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, [, ]);
a.call(null, , );

仅此而已。

再来看题主的疑问,这样写包裹代码有什么好处呢?这里就必须说一说另一个关键的地方了,题主贴出来的代码,可以看到这个函数使用严格模式 "use strict",什么是严格模式呢?自己搜去吧。在正常模式下,js 函数里那些你没有声明就使用的变量,其实是访问的全局对象的属性,比如说上面正常函数调用的时候,函数里的 this ,就访问的是全局对象。但是在严格模式下,不允许这种语法,所有变量都必须要显示声明,所以如果你不用 call() 传递 this 给这个函数,那么就会报错了。因为你在函数里面有一个 return 语句,访问了 this 变量。所以问题不是题主说的这样写有什么好处,而是用了严格模式,就必须这么写。

然后还想说一下,apply() 和 call() ,用它们有什么好处呢?好处就是可以让你改变 this,这不是废话吗。改变 this 来干嘛呢?可以让这个函数,使用 this 的方法,换句话说,就是你的函数可以针对不同的 this,来调用它们不同的方法,有点像反射机制。哈哈,我扯远了。

使用(function() {}).call(this);包裹代码有什么好处,什么时候应该这样做?的更多相关文章

  1. SQL Server ->> 生成时间类型的Partition Function和Partition Scheme代码

    有时工作中要建个分区函数,可是像日期这种分区函数要是搞个几百个的值那不是要搞死我.于是写了点代码自动生成一个从1990年开始的按月的分区函数和对应的分区主题 USE [TestDB] GO DECLA ...

  2. node的function函数和路由代码的小例子

    1.node事件循环 事件: const events=require("events"); emt=new events.EventEmitter(); function eve ...

  3. 不到50行代码实现一个能对请求并发数做限制的通用RequestDecorator

    使用场景 在开发中,我们可能会遇到一些对异步请求数做并发量限制的场景,比如说微信小程序的request并发最多为5个,又或者我们需要做一些批量处理的工作,可是我们又不想同时对服务器发出太多请求(可能会 ...

  4. C#代码分层的好处

    1.对于复杂的系统,分层让代码结构清晰,便于开发人员对系统进行整体的理解.把握.如果代码没有分层,把逻辑都写在一个方法里面的代码就好比是一本没有目录的文档,要找出其中某一节都要对全文遍览一次. 2.基 ...

  5. 通过代码设置资源名字,为打包AssetBundle做准备,以及新打包系统

    核心代码就是  importer.assetBundleName = name;  但是在这之前,我们需要超找到具体的资源,我们当然是不希望一个一个手动去查找.如果我选择一个文件夹,就可以查找到里边所 ...

  6. jQuery解决鼠标单双击问题

    html代码如下: <button>点击</button> JQ代码如下: <script> $(function () { // 编写相关jQuery代码 // ...

  7. JQuery解决鼠标单双击冲突问题

    转自链接:https://www.shuzhiduo.com/A/xl560MKrzr/ 在jQuery的事件绑定中,如果元素同时绑定了单击事件(click)和双击事件(dblclick),那么执行单 ...

  8. java代码之美(15)---Java8 Function、Consumer、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前写了三篇博客: 1.java代码之美(1)---Java8 Lambda 2.java代码之美(2)---Jav ...

  9. java代码(15) ---java8 Function 、Consumer 、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...

随机推荐

  1. hdu 4462 第37届ACM/ICPC 杭州赛区 J题

    题意:有一块n*n的田,田上有一些点可以放置稻草人,再给出一些稻草人,每个稻草人有其覆盖的距离ri,距离为曼哈顿距离,求要覆盖到所有的格子最少需要放置几个稻草人 由于稻草人数量很少,所以状态压缩枚举, ...

  2. 【8.14校内测试】【DP专题】

    nlogn做法,dp[i]表示当前长度为i的最长上升子序列末尾元素的值. 不会写lower_bound(qwq,贴一个以前的好看点的代码 #include<iostream>//使用low ...

  3. window.open如何返回值给父窗口

    父窗口代码 function showMyWindowNew() { var iTop = (window.screen.availHeight - 30 - 450) / 2; //获得窗口的水平位 ...

  4. hihocoder #1301 : 筑地市场 二分+数位dp

    #1301 : 筑地市场 题目连接: http://hihocoder.com/problemset/problem/1301 Description 筑地市场是位于日本东京都中央区筑地的公营批发市场 ...

  5. hdoj 1753 大明A+B 高精度/java

    大明A+B Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  6. Null 和 Undefined

    在JavaScript中存在这样两种原始类型:Null与Undefined.这两种类型常常会使JavaScript的开发人员产生疑惑,在什么时候是Null,什么时候又是Undefined? Undef ...

  7. centos7下redis-2.8.13安装笔记

    安装gcc 执行命令:yum install gcc 中间有两次提示,要求输入:yes 或 y,我们按照提示来就可以 至此安装成功 注意:如果不装gcc,解压redis后执行make命令会报错,如下图 ...

  8. Mina 断线重连

    Mina 断线重连 定义:这里讨论的Mina 断线重连是指使用mina作为客户端软件,连接其他提供Socket通讯服务的服务器端.Socket服务器可以是Mina提供的服务器,也可以是C++提供的服务 ...

  9. 华为S5300系列升级固件S5300SI-V100R003C00SPC301.cc

    这个固件是升级V100R005的中间件,所以是必经的,注意,这个固件带有http的服务,但现在无论官网还是外面,几乎找不到这个固件的web功能,如果非要实现,可以拿V100R005的web文件改名为w ...

  10. android WebView中js的alert()失效

    WebView的设置代码 wv = (WebView) findViewById(R.id.webView1); wv.getSettings().setJavaScriptEnabled(true) ...