Javascript的四种(函数)调用模式
2016-02-01 20:25
706 查看
函数的四种调用模式,分别是函数调用模式,方法调用模式,构造器调用模式以及Apply/Call调用模式。
本文先简单介绍下Javascript的作用域链问题,然后谈下四种调用模式,最后介绍一下闭包以及调用模式在闭包里面的体现。
作用域链
四种调用模式
闭包及示例
在全局作用域链中的函数分配一个作用域链,记作1级作用域链。
即:在n级作用域链中的函数,分配n+1级作用域链。
每一个函数都会分配一个作用域链,即js没有块级作用域。
po一张作用域链图(自行体会函数f1(),f2(),f3())。
访问变量时,先在当前作用域链中找,如果找到就用,找不到就到上一级作用域链中找,直到找到0级作用域链还未找到,报未定义错误。
举个例子(涉及闭包),可去掉对应注释检验
但是如果当一个函数内部还有一个函数,则内部的函数用this指的是什么呢?按道理:当内部函数被调用时,this 应该指的是外部函数的 this (就比如我爹生了我,别人问我是谁家的,我一定是说那谁谁家的不是哈哈哈哈哈)但是Javascript的函数就是这么坑爹,只认祖宗(window)。
解决方法:
在函数中定义一个变量并给它赋值为 this,那么内部函数就可以通过那个变量访问到被绑定到外部函数的正确 this。按照约定,我们给那个变量命名为 that。
其实这个例子举得不是很恰当,因为在这里f1()的this指的还是window(全局对象),所以赋值给that,that的值仍是全局对象。
that一般用在方法调用模式,用来使用特定对象的变量。
这里仅仅是理解一下that的用法。
思考:将上述代码改成下边的样子,会显示什么?如何改进?
结果:倩倩,undefined
改进:that(函数调用模式)
1.如果函数返回一个对象,this就指向这个对象;
2.否则,this指向这个新创建出来的对象(类似java中类的实例)
1.语法
函数名.apply(对象,[参数数组]);
函数名.call(对象,参数列表);
当对象为null时,函数进行函数调用模式
当对象不为null时,函数进行方法调用模式
2.this
this指向第一个参数
摘抄某网站里的概念,闭包:是指有权访问另外一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另外一个函数。
闭包的两个用途:
1.读取函数内部的变量
(前面已经有很多例子)
2.让这些变量的值始终保持在内存中
代码解析:
1.result实际上就是f2,通过f1()得到,按道理赋值过后f1应该消亡,但是却没有。(由nAdd()将n从999变为1000可知,n为f1的变量)。这是因为f2赋给了全局变量result,而f2又依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
2.nAdd()前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。(这句是阮一峰老师的原话,为什么说它是闭包,我大致理解为作为一个全局变量可以访问函数f1中的变量)
附上阮一峰老师博客里面的两道思考题,相信读懂前面的之后,自然就是小case了。
本文参考文章:
1.http://blog.saymoon.com/2009/10/difference-from-this-in-invocation-for-function-by-four-ways/
2.http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
本文先简单介绍下Javascript的作用域链问题,然后谈下四种调用模式,最后介绍一下闭包以及调用模式在闭包里面的体现。
作用域链
四种调用模式
闭包及示例
1.作用域链
在js中整个script是一个全局作用域链,记作0级作用域链。在全局作用域链中的函数分配一个作用域链,记作1级作用域链。
即:在n级作用域链中的函数,分配n+1级作用域链。
每一个函数都会分配一个作用域链,即js没有块级作用域。
po一张作用域链图(自行体会函数f1(),f2(),f3())。
访问变量时,先在当前作用域链中找,如果找到就用,找不到就到上一级作用域链中找,直到找到0级作用域链还未找到,报未定义错误。
举个例子(涉及闭包),可去掉对应注释检验
var i="倩倩"; var f1=function(){ //var i="倩宝"; var f2=function(){ //var i="郭子倩"; var f3=function(){ alert(i); } return f3; } return f2; } f1()()(); //倩倩
2.四种调用模式
2.1函数调用模式
当一个函数并非一个对象的属性时,它被当作一个函数来调用,此时this指全局对象,即window。var name="倩倩"; var f1=function(){ var name="倩宝"; alert(this.name); } f1(); //倩倩
但是如果当一个函数内部还有一个函数,则内部的函数用this指的是什么呢?按道理:当内部函数被调用时,this 应该指的是外部函数的 this (就比如我爹生了我,别人问我是谁家的,我一定是说那谁谁家的不是哈哈哈哈哈)但是Javascript的函数就是这么坑爹,只认祖宗(window)。
解决方法:
在函数中定义一个变量并给它赋值为 this,那么内部函数就可以通过那个变量访问到被绑定到外部函数的正确 this。按照约定,我们给那个变量命名为 that。
var name="倩倩"; var f1=function(){ var name="倩宝"; var that=this; var f2=function(){ alert(that.name); } return f2; } f1()(); //倩倩
其实这个例子举得不是很恰当,因为在这里f1()的this指的还是window(全局对象),所以赋值给that,that的值仍是全局对象。
that一般用在方法调用模式,用来使用特定对象的变量。
这里仅仅是理解一下that的用法。
2.2方法调用模式
方法调用模式中,this表示当前对象var name="倩倩"; var person={ name:"倩宝", sex:"女", say:function(){ alert(this.name); alert(this.sex); } } person.say(); //倩宝,女
思考:将上述代码改成下边的样子,会显示什么?如何改进?
var name="倩倩"; var person={ name:"倩宝", sex:"女", say:function(){ return function(){ alert(this.name); alert(this.sex); } } } person.say()();
结果:倩倩,undefined
改进:that(函数调用模式)
2.3构造器调用模式
JavaScript中如果用 new 方式调用一个函数,1.如果函数返回一个对象,this就指向这个对象;
var person=function(){ this.name="倩宝"; this.sex="女"; return { name:"倩倩" } } var p=new person(); alert(p.name); //倩倩
2.否则,this指向这个新创建出来的对象(类似java中类的实例)
//return 任意东西。
var person=function(){
this.name="倩宝";
this.sex="女";
return 123;
}
var p=new person();
alert(p.name); //倩宝
// 没有return var person=function(){ this.name="倩宝"; this.sex="女"; } var p=new person(); alert(p.name); //倩宝
2.4 apply/call调用模式
目前学习当中接触的不多,暂不作讨论,简单记录两个点。1.语法
函数名.apply(对象,[参数数组]);
函数名.call(对象,参数列表);
当对象为null时,函数进行函数调用模式
当对象不为null时,函数进行方法调用模式
2.this
this指向第一个参数
3.闭包及示例
前面已经了解过了JS的作用域链问题,知道0级作用域链的变量无法访问1级作用域链的变量(即低级作用域链无法访问高级作用域链的变量,“高低”一词根据理解来看了)。而闭包就能改变这种现状。摘抄某网站里的概念,闭包:是指有权访问另外一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另外一个函数。
闭包的两个用途:
1.读取函数内部的变量
(前面已经有很多例子)
2.让这些变量的值始终保持在内存中
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
代码解析:
1.result实际上就是f2,通过f1()得到,按道理赋值过后f1应该消亡,但是却没有。(由nAdd()将n从999变为1000可知,n为f1的变量)。这是因为f2赋给了全局变量result,而f2又依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
2.nAdd()前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。(这句是阮一峰老师的原话,为什么说它是闭包,我大致理解为作为一个全局变量可以访问函数f1中的变量)
附上阮一峰老师博客里面的两道思考题,相信读懂前面的之后,自然就是小case了。
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this + ", " + this.name; }; } }; alert(object.getNameFunc()());
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that + "," + that.name; }; } }; alert(object.getNameFunc()());
本文参考文章:
1.http://blog.saymoon.com/2009/10/difference-from-this-in-invocation-for-function-by-four-ways/
2.http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- 深入理解PHP之匿名函数
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子
- JavaScript 各种遍历方式详解
- call/apply/bind 的理解与实例分享
- 如何创建对象以及jQuery中创建对象的方式