javascript中为何在匿名function函数后面还外加

2020-05-20 22:29:05

参考地址 javascript中为何在匿名function函数后面还外加

  对于很多初学者来说,遇到它们经常会产生一系列问号:这是编程吗,用它做什么,怎么我没在其他语言里见过呢?

    接下来我就详细地解释一下:

    它可以解释成为“匿名函数自调用”,也就是说,定义一个匿名函数,然后马上调用它(因为它是匿名的,如果不立即调用就获取不到该函数的引用了)。通常它被应用在一些大型的JS框架中(如上面所说的),因为这个匿名函数的函数体相当于提供一个匿名的名字空间,这样就不会再与用户自定义的JS函数、变量、对象发生冲突了。尽管JS没有显示地提供命名空间的定义和使用机制,但这种匿名方式却不失为是一种很好的解决命名空间问题的方法。

    所以说,(function(){代码})()就等于执行了一个函数,只不过它是匿名的而已。如果在这个匿名函数内部想再次调用这个函数,就需要调用constructor属性了(这是Object中定义的,JS的继承机制如同Java一样保证了了所有对象都继承Object类)。

    明白了它是什么了,下面我们就要学习该怎样使用它了,以下这些问题是我们会经常遇到的,不如提前做好理论只是准备以备后期能顺利地实现开发。请看下面问题:

1、下列哪些正确?(B、C

A.function(){

       alert("Here!");

    }();

B.(function(){

       alert("Here!");

    })();

C.(function(){

       alert("Here!");

    }());

2、下列哪个结果是正确的?(A、B、C、D

A.(function(a1,a2){

       alert("Here!"+(a1+a2));

    })(1,2);

B.(function(a1,a2){

       alert("Here!" +(a1+a2));

    }(1,2));

C.void function(a1,a2){

       alert("Here!" +(a1+a2));

    }(1,2);

D.var f = function(a1,a2){

       alert("Here!" +(a1+a2));

    }(1,2)

    注:A 、B、C与D四种格式都正确,前两者属于同种情况的不同写法,后两种是将函数对象的返回值赋给其他变量,C是忽略函数返回值,而D正相反!

    具体举个例子:

function test(){

          return (function(p1,p2){

                            return p1+p2;

          })(1,2);

};

(function(){

          alert(test());

}());

    下面我们就深入研究一下这种匿名函数:

1、

function Foo() { 

    var a = 123; 

    this.a = 456; 

    (function() {

       alert(a); // 123

       alert(this.a); // undefined 

    })(); 

};

var f = new Foo();

② 

function Foo() { 

    var a = 123; 

    this.a = 456; 

    (function(_this) {

       alert(a); // 123

       alert(_this.a); // 456 

    })(this); 

};

var f = new Foo();

以上两个对比,说明:

(1)匿名函数可以直接访问到外层署名函数(Foo)中的变量(使用关键字var定义的),但不能访问外层署名函数的属性(使用关键字this定义的);

(2)匿名函数中的this指向的是匿名函数对象的地址,它与外层署名函数(Foo)对象的this指向的地址不同;

(3)匿名函数若要访问外层署名函数(Foo)中的属性,可以通过参数传递的方式实现。 

2、

① 

function Foo() { 

    var a = 123; 

    this.a = 456; 

    (function(b) {

       alert(a); // 123

       alert(b); // 456 

    })(this.a); 

};

var f = new Foo();

(function() { 

    var a = 123; 

    this.a = 456; 

    (function() {

       alert(a); // 123

       alert(this.a); // 456 

    })();

})();

以上两个对比,说明:

(1) 匿名函数既可以直接访问外层匿名函数中的变量,又直接可以访问外层匿名函数中的属性,而匿名函数却不可以直接访问外层已命名函数中的属性;

2)以上两种方式可以实现相同的功能。

3、

(function() { 

    var a = 123; 

    this.a = 456; 

    (function() { 

       alert(a); // 123 

       alert(this.a); // 456 

       this.b = 789; 

    })(); 

    (function() { 

       alert(this.b); // 789 

    })(); 

})();

(function() {

    alert(this.a); // 456

    alert(this.b); // 789 

})();

function Foo() { 

    var a = 123; 

    this.a = 456;

    (function() { 

       alert(a); // 123 

       alert(this.a); // undefined 

       this.b = 789; 

    })(); 

    (function() { 

       alert(this.b); // 789 

    })(); 

};

var f = new Foo(); 

(function() {

    alert(this.a); // undefined

    alert(this.b); // 789 

})();

以上两个对比,说明:

(1)匿名函数(即用两个小括号括起来的部分)位于一个执行上下文,不论这些代码放在哪个位置上。

4、

function Foo() {

(function() {

this.b = 789;

})();

(function() {

alert(this.b); // 789

alert(b); // 789

var a = 0;

alert(a); // 0

})();

}

var f = new Foo();

(function() {

alert(this.b); // 789

alert(b); // 789

})();

function Foo() {

(function() {

this.b = 789;

})();

(function() {

alert(this.b); // 789

alert(b); // undefined

var b = 0;

alert(b); // 0

})();

}

var f = new Foo();

(function() {

alert(this.b); // 789

alert(b); // 789

})();

以上两个对比,说明:

1)没有加 this取值时,如果当前 {} 中不存在同名的局部变量,则等同于加 this 处理;如果当前 {} 中存在同名的局部变量,则按常规处理。 

以上只是鄙人的粗浅见解,内容还不够完整,还会不断完善删改,如其中有什么错误之处还望读者谅解,真诚希望能留下您的宝贵建议,以图修改!这里欢迎每一位爱好JS的读者,真心希望能和你们交流心得!


  • 2019-10-14 21:18:57

    Comparable 的 使用

    要做这个呢,我们也是用到了Arrays.sort 这个排序的方法!但不同的是,我们之前用的是int数组,现在我们用的是这个UserBean数组。如果你想对这个UserBean数组进行排序,你要多做一件事,就是让这个 UserBean类去 实现Comparable 的接口,并重写 里面  comparaTo 的方法。注意,这个接口是可以提供泛型的 ———————————————— 版权声明:本文为CSDN博主「sdn_bt496」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明

  • 2019-10-15 05:53:20

    xUtils 里的DbUtils使用心得

    使用xUtils做Android数据库开发非常简便和得心应手,而且它本身还支持很多查询功能,比如一对多,select count和自定义sql查询等,并且支持事务(默认关闭) 下面是官方sample给的代码和我的一些使用心得 首先是两个实体类,对应两张表,这两张表中有一对多的关系

  • 2019-10-15 09:18:48

    腾讯 Android 面试笔试总结

    Activity中的几种启动模式 Android消息机制 IntentService 事件分发 Android性能优化、内存优化 内存优化 View的绘制 Eventbus原理 Rxjava的操作符有哪些,说说他们的作用 线程锁 锁方法和类对象啥的有啥区别 AsyncTask原理 说说MVP和MVVM的特点 Android中用到的观察者模式有哪些地方 说说google新出的Lifecycle框架 okhttp原理 Retrofit原理 RecyclerView源码、缓存分析 Binder机制 Android Jetpack Kotlin Activity中的几种启动模式

  • 2019-10-15 09:20:49

    SpringBoot注解梳理

    @SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文。 @Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全。 @EnableAutoConfiguration 自动配置。 @ComponentScan 组件扫描,可自动发现和装配一些Bean。 @Component可配合CommandLineRunner使用,在程序启动后执行一些基础任务。 @RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。 @Autowired自动导入。 @PathVariable获取参数。 @JsonBackReference解决嵌套外链问题。 @RepositoryRestResourcepublic配合spring-boot-starter-data-rest使用。

  • 2019-10-15 09:52:00

    动图解释递归,按值传递和按引用传递的区别,线性查找和二分查找,二叉查找树

    对于大部分人,数据结构一直是一个短板,当然我也是,不是学不会,而是容易忘,就拿最简单的排序来说吧,当时学习的时候明明已经弄得很清楚了,过了一段时间不用又忘记了,还要重新再看一遍,不知道有多少小伙伴和我有一样的烦恼。今天让我们用用动图的方式学习一下数据结构中的递归和二分查找吧,这种讲解方式非常生动,而且非常容易记住和理解。