浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序
在Javascript定义一个函数一般有如下三种方式:
函数关键字(function)语句:
function fnMethodName(x){alert(x);}
函数字面量(Function Literals):
var fnMethodName = function(x){alert(x);}
Function()构造函数:
var fnMethodName = new Function(‘x','alert(x);') // 由Function构造函数的参数个数可变。最后一个参数写函数体,前面的参数写入参。
上面三种方法定义了同一个方法函数fnMethodName,第1种就是最常用的方法,后两种都是把一个函数复制给变量fnMethodName,而这个函数是没有名字的,即匿名函数。
函数的执行顺序:
例1.
- test1();
- function test1() { //函数声明
- alert("1111");
- }
- test2();
- var test2 = function(){ //函数字面量
- alert("2222");
- }
- test3();
- var test3 = new Function("alert(3333);"); //运行时,初始化函数体
执行结果:弹出1111,但是没有弹出222, 3333
原理:弹出1111 是因为JS函数声明提前
没有弹出2222, 3333,是因为函数字面量不是函数声明,函数字面量表示方法是在运行时解析的,在调用test2()之前,函数字面量的函数体还没有声明。
例2.
- function f(){return 1;}
- console.log(f()); // 第四个函数把第一个函数覆盖
- var f = new Function("return 2;");
- console.log(f()); // 第二个函数把第四个函数覆盖
- var f = function() {return 3;}
- console.log(f()); // 第三个函数把第二个函数覆盖
- function f(){return 4;}
- console.log(f()); // 第四个函数已经被覆盖
- var f = new Function("return 5;");
- console.log(f()); // 第五个函数把第三个函数覆盖
- var f = function(){return 6;}
- console.log(f()); // 第六个函数把第五个函数覆盖
执行结果: 4 2 3 3 5 6
原理: 先找出函数声明,“返回值是4的函数声明”覆盖了“返回值是1的函数声明”。所以第一个f()的结果是4 。
函数作用域:
- var k = 4;
- window.onload=function() {
- var k=1;
- function t1() {
- var k = 2;
- function test(){return k;}
- console.info(test()); // 弹出 2
- var test = function(){return k;};
- console.info(test()); // 弹出 2
- var test = new Function("return k;"); // 每次执行的时候,动态的new,顶级作用域,无法获得局部变量
- console.info(test()); // 弹出 4
- }
- t1();
- };
二、函数字面量和Function()构造函数的区别
虽然函数字面量是一个匿名函数,但语法允许为其指定任意一个函数名,当写递归函数时可以调用它自己,使用Function()构造函数则不行。
- var f = function fact(x) {
- if (x < = 1) return 1;
- else return x*fact(x-1);
- };
Function()构造函数允许运行时Javascript代码动态的创建和编译。在这个方式上它类似全局函数eval()。
Function()构造函数每次执行时都解析函数主体,并创建一个新的函数对象。所以当在一个循环或者频繁执行的函数中调用Function()构造函数的效率是非常低的。相反,函数字面量却不是每次遇到都重新编译的。
用Function()构造函数创建一个函数时并不遵循典型的作用域,它一直把它当作是顶级函数来执行。
- var y = “global”;
- function constructFunction() {
- var y = “local”;
- return new Function(“return y”); // 无法获取局部变量 }
- alert(constructFunction()()); // 输出 “global”
函数直接量:
只要是表达式语法,脚本宿主就认为 function 是一个直接量函数,如果什么都不加,光以 function 开头的话则认为是一个函数声明,把 function 写进一个表达式内部,比如四则运算,宿主也会将其当作是一个直接量,如下:
只有函数表达式可以被立即调用,函数声明不可以.
- var a = 10 + function(){
- return 5;
- }();
夸张一点,如下:
- (function(){
- alert(1);
- } ) ( );
- ( function(){
- alert(2);
- } ( ) );
- void function(){
- alert(3);
- }()
- 0, function(){
- alert(4);
- }();
- -function(){
- alert(5);
- }();
- +function(){
- alert(6);
- }();
- !function(){
- alert(7);
- }();
- ~function(){
- alert(8);
- }();
- typeof function(){
- alert(9);
- }();
js中定义函数的方式有多种,函数直接量就是其中一种。如var fun = function(){}, 这里function如果不赋值给fun那么它就是一个匿名函数。
好,看看匿名函数的如何被调用。
1、执行后得到返回值的函数调用
- //方式一,调用函数,得到返回值。强制运算符使函数调用执行
- (function(x,y){
- alert(x+y);
- return x+y;
- }(3,4));
- //方式二,调用函数,得到返回值。强制函数直接量执行再返回一个引用,引用在去调用执行
- (function(x,y){
- alert(x+y);
- return x+y;
- })(3,4);
2、执行后忽略返回值
- //方式三,调用函数,忽略返回值
- void function(x) {
- x = x-1;
- alert(x);
- }(9);
嗯,最后看看错误的调用方式
- //错误的调用方式
- function(x,y){
- alert(x+y);
- return x+y;
- }(3,4);
三、应用实例的一些说明
对象直接量创建一个对象:
var obj = {x:[1,2],y:23};
代码跟下面是一样的。
- var obj=new Object();
- obj.x=new Array(1,2);
- obj.y=23;
测试:
for(var i in obj) alert(obj[i]);
函数直接量:它是一个表达式而不是语句。
(function(){})()
如下例:
- (function(){
- document.write(“some script code”);
- })()
- var a=(function(s){return s})(“abc”);
- alert(a);
- var b=function(s){return s};
- alert(b(“abc”));
这个如何解释呢
大家应该记得这种写法
var a=function (){}
那么怎么运行a呢,那么就是a()
同样的道理,我们不通过a这个变量来存那么是如何写法,就是
function(){}()
但是你会发现这样是错的
因为解析引擎解析的时候,解析的时候发现}判断到了函数结束了
并没有把那个函数作为块来运行
那么加上()是强制把function那块作为块
JS函数调用的四种方法:方法调用模式,函数调用模式,构造器调用模式,apply,call调用模式
1. 方法调用模式:
先定义一个对象,然后在对象的属性中定义方法,通过myobject.property来执行方法,this即指当前的myobject对象。
- var blogInfo={
- blogId:123,
- blogName:"werwr",
- showBlog:function(){alert(this.blogId);}
- };
- blogInfo.showBlog();
2.函数调用模式
定义一个函数,设置一个变量名保存函数,这时this指向到window对象。
- var myfunc = function(a,b){
- return a+b;
- }
- alert(myfunc(3,4));
3.构造器调用模式
定义一个函数对象,在对象中定义属性,在其原型对象中定义方法。在使用prototype的方法时,必须实例化该对象才能调用其方法。
- var myfunc = function(a){
- this.a = a;
- };
- myfunc.prototype = {
- show:function(){alert(this.a);}
- }
- var newfunc = new myfunc("123123123");
- newfunc.show();
4.apply,call调用模式
- var myobject={};
- var sum = function(a,b){
- return a+b;
- };
- var sum2 = sum.call(myobject,10,30); //var sum2 = sum.apply(myobject,[10,30]);
- alert(sum2);
浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序的更多相关文章
- 浅谈JS函数防抖及应用场景
[前言] 在工作中,我们可能碰到这样的问题: 用户在搜索的时候,在不停敲字,如果每敲一个字我们就要调一次接口,接口调用太频繁,给卡住了. 用户在阅读文章的时候,我们需要监听用户滚动到了哪个标题,但是每 ...
- 浅谈JS函数节流及应用场景
说完防抖,下面我们讲讲节流,规矩就不说了,先上代码: <!DOCTYPE html> <html lang="en"> <head> <m ...
- 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂
浅谈JS中的!=.== .!==.===的用法和区别 var num = 1; var str = '1'; var test = 1; test == num //tr ...
- 【ASP.NET MVC系列】浅谈ASP.NET 页面之间传值的几种方式
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 浅谈JS之AJAX
0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...
- 浅谈javascript函数节流
浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...
- 浅谈JS中的闭包
浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...
- 浅谈JS面向对象
浅谈JS面向对象 一 .什么是面向过程 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了.注重代码的过程部分. 二.什么是面向对象 最先出现在管理学 ...
- 浅谈c#的三个高级参数ref out 和Params C#中is与as的区别分析 “登陆”与“登录”有何区别 经典SQL语句大全(绝对的经典)
浅谈c#的三个高级参数ref out 和Params c#的三个高级参数ref out 和Params 前言:在我们学习c#基础的时候,我们会学习到c#的三个高级的参数,分别是out .ref 和 ...
随机推荐
- SQL Server 游标的应用
----------------SQL游标应用----------------- 今天由于业务需求,需要在存储过程中实现有一个表的主键去匹配在另一个表中作为外键所对应的数值 ,若在C#中则非常简单只需 ...
- Spring XML配置文件无法自动提示 eclipse中XML配置文件open with打开方式选择 XML Editor:注意它的编辑方式也是有两种的design和source
双击XML配置文件,如果打开方式不正确 则如下图: 都是灰色显示,不会有自动提示,也不会有颜色标注 右击XML配置文件,选择打开方式为XML Editor,则会有颜色标注 如果此时没有自动提示 则要手 ...
- 关于OnTimer()使用
OnTimer()其实是用来响应WM_TIMER消息的,其实OnTimer()就是一个回调函数,不过是系统默认的,当用户使用SetTimer()函数设定一个定时器的时候,只要是第三个参数为NULL,则 ...
- 拓扑排序 topsort
拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序 ...
- php 常用函数集合(持续更新中...)
php 常用函数集合 在php的开发中,巧妙的运用php自带的一些函数,会起到事半功倍的效果,在此,主要记录一些常用的函数 1.time(),microtime()函数 time():获取当前时间戳 ...
- python数据类型之列表(list)和其常用方法
列表是python常用数据类型之一,是可变的,可由n = []创建,也可由n = list()创建,第一种方法更常用. 常用方法总结: # 创建方法 n = [] 或者 n = list() # in ...
- sublime text3 安装ctags实现函数跟踪跳转
来源:http://blog.csdn.net/menglongfc/article/details/51141084 本人试用平台如下:sublime text3,和谐版 在source insig ...
- debian使用ibus
$ sudo apt-get install ibus ibus-pinyin 点击右上角的键盘图标,设置拼音输入法
- 树链剖分 - Luogu 3384【模板】树链剖分
[模板]树链剖分 题目描述 已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操 ...
- Spring学习总结(20)——Spring加载多个项目properties配置文件问题解决
多数的鲜为人知方法都是因为有着罕见的应用,就比如说Spring中PropertyPlaceholderConfigurer这个类,它是用来解析Java Properties属性文件值,并提供在spri ...