首页 web前端 js教程 JavaScript的各种常见函数定义方法_javascript技巧

JavaScript的各种常见函数定义方法_javascript技巧

May 16, 2016 pm 04:36 PM
javascript 函数 定义 方法

本文详细讲述了JavaScript的各种常见函数定义方法,分享给大家供大家参考。具体分析如下:

首先看一下JavaScript最常见的四种函数定义:

用Function构造函数定义的函数,代码如下:

var multiply = new Function('x', 'y', 'return x * y;');
登录后复制

函数声明,这种方式也是最为常见的一种:

function multiply(x, y) {
  return x * y;
}
登录后复制

函数表达式,声明为匿名函数然后赋值给一变量,很常见的方式:

var multiply = function(x, y) {
  return x * y;
}
登录后复制

函数表达式,但是函数声明为命名函数再赋值给一变量,长得跟上一种方式真像:

var multiply = function multi(x, y) {
  return x * y;
}
登录后复制

首先比较一下函数名,以及将函数赋值给的那个函数变量直接的关系,真绕……直观一点儿,从刚刚的例4说吧,就是multiply这个函数变量与multi这个函数名的关系:

函数名是不能够被修改的,相反的,函数变量是可以重新被赋值的。函数变量可以被重新赋值应该很好理解,我们第4个例子刚刚定义的multiply这个变量,看它不顺眼,重新赋值为:

multiply = function(x, y) {
  return x + y;
}
登录后复制

立马摇身一变,从乘法变成加法了。但是multi这个函数变量想变就是不可能的了,函数定义已经在那儿了,只要还保留这它的引用,它就是不会变的,可能这里不大好理解,先这样想着,往下看,慢慢就应该能理解了。

函数名同时是无法在函数外部使用的,它只在函数体内部可见,一个很简单的例子:

var foo = function bar() {
  alert('hello');
}
foo(); // 提示“hello”字符串
bar(); // 执行报错,bar未定义

登录后复制

和明显,这里的bar确实是一个函数名,但是它确实不能在外部调用。这时候肯定会有童鞋问干嘛这个例子还是长得那么乖,和例4一个样,怎么不用例2的方式呢?问得好,且听我慢慢分解。

继续说例4,我们可以看见函数名(multi)和函数变量(multiply),本不相同,其实两者根本就没有任何关系,因此没有保持一致的必要。说到这儿,我想上面4个例子应该可以精简到3个,例2和例4本质应该是一致的。什么,不信?嘻嘻,我还得继续卖关子哈~继续读下去~~

我们发现例2和例4相比,只不过少了var的函数变量,而例3与例4相比,只不过少了那个函数名,这里从现象上看,例2和例4的本质是相同的,铁证如下:

function foo() {}
alert(foo); // 提示包含“foo”的函数名
var bar = foo;
alert(bar); // 提示依然只包含“foo”的函数名,和bar半毛钱关系都没有

登录后复制

的确是铁证吧?上面的类似例2的代码结合起来写是不是就成例4的方式了?正确,这就是我刚刚所说的两者本质应该相同,只是用例2方式定义函数的时候,JS引擎帮我们做了一些事情,比如声明了函数名为multiply的函数,同时还悄悄定义了一个也叫multiply的变量,然后赋值给这个变量,两个完全一样的名字,我们自以为在使用函数名multiply的时候,实际是在用multiply这个函数变量,晕了吧~说实话,我也晕了~~总之我们调用的时候,实在用函数变量调用,而函数名是无法在外部调用函数的,因此有了我上述的推断。

但是这里要提到的一个小小的差别,函数声明方式定义的函数,与构造函数声明的或者函数表达式声明的不同之处在于,函数声明方式的函数可以在函数定义之前就调用……不说了,还是看代码:

foo(); // 提示Foo
function foo() {
  alert('Foo');
}
bar(); // 哥们,和上面确实不一样,就不要逞能,这不报错了?提示bar未定义
var bar = function() {
  alert('Bar');
}
登录后复制

再说说构造函数声明的函数,这样声明的函数是不会继承当前声明位置的作用域,它默认只会拥有全局作用域,然而这个是其他几种函数声明方式也一样有的,如下:

function foo() {
  var hi = 'hello';
  //return function() {
  //  alert(hi);
  //};
  return Function('return hi;');
}
foo()(); // 执行效果大家自己跑一下看看
登录后复制

可以想见,用构造函数声明返回的这个函数执行必然报错,因为其作用域(即全局作用域)中没有hi这个变量。

还有一点,就是往往大家要说构造函数方式声明的函数效率要低,这是为什么呢?今天从文档是得知是因为另外3种方式申明的函数只会被解析一次,其实他们存在于闭包中,但是那也只与作用域链有关,函数体是只会被解析一次的。但是构造函数方式呢,每次执行函数的时候,其函数体都会被解析一次,我们可以想想这样声明的函数是一个对象,其中存放了参数以及函数体,每次执行的时候都要先解析一次,参数和函数体,才会执行,这样必然效率低下。具体实验不知道如何做?

最后说一个大家都不怎么注意的地方,什么时候看似函数声明方式的方式却不是函数生命方式(还是这么绕~简单点儿说,就是例2的方式什么时候在不经意间就成其他方式了):

当成为表达式的一部分,就如同例3和例4。
不再是脚本本身或者函数的“源元素”(source element)。什么是源元素呢?即在脚本中的非嵌套语句或者函数体(A "source element" is a non-nested statement in the script or a function body),例如:

var x = 0;        // source element 
if (x == 0) {      // source element 
  x = 10;        // not a source element, 因为嵌套在了if语句里
  function boo() {}   // not a source element, 因为嵌套在了if语句里
} 
function foo() {     // source element 
  var y = 20;      // source element 
  function bar() {}   // source element 
  while (y == 10) {   // source element 
   function blah() {} // not a source element, 因为嵌套在了while语句里
   y++;        // not a source element, 因为嵌套在了while语句里
  } 
}
登录后复制

源元素的概念大概有了理解,继续刚刚说的函数声明,请看:

// 函数声明
function foo() {} 
  
// 函数表达式
(function bar() {}) 
  
// 函数表达式
x = function hello() {} 
 
if (x) { 
  // 函数表达式
  function world() {} 
}
 
// function statement 
function a() { 
  // function statement 
  function b() {} 
  if (0) { 
   // 函数表达式
   function c() {} 
  } 
}
登录后复制

最后这里说一下我自己的理解,之所以要区分函数声明与非函数声明,因为在我看了,函数声明方式的函数定义,在JS解析引擎执行的时候会将其提前声明,也就是像我们刚刚上面说的那样,可以在函数定义之前使用,实际上是解析引擎在我们使用前已经将其解析了,但是非函数声明式,就像表达式函数声明,JS解析引擎只会把var声明的变量提前定义,此时变量值为undefined,而真正对这个变量的赋值是在代码实际所在位置,因此上述提到报错都是undefined,实际变量已经定义了,只是还没有赋值,JS解析引擎不知道它为函数。

相信本文所述对大家javascript WEB程序设计的有一定的借鉴价值。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

微信删除的人如何找回(简单教程告诉你如何恢复被删除的联系人) 微信删除的人如何找回(简单教程告诉你如何恢复被删除的联系人) May 01, 2024 pm 12:01 PM

而后悔莫及、人们常常会因为一些原因不小心将某些联系人删除、微信作为一款广泛使用的社交软件。帮助用户解决这一问题,本文将介绍如何通过简单的方法找回被删除的联系人。1.了解微信联系人删除机制这为我们找回被删除的联系人提供了可能性、微信中的联系人删除机制是将其从通讯录中移除,但并未完全删除。2.使用微信内置“通讯录恢复”功能微信提供了“通讯录恢复”节省时间和精力,用户可以通过该功能快速找回之前被删除的联系人,功能。3.进入微信设置页面点击右下角,打开微信应用“我”再点击右上角设置图标、进入设置页面,,

手机版龙蛋孵化方法大揭秘(一步一步教你如何成功孵化手机版龙蛋) 手机版龙蛋孵化方法大揭秘(一步一步教你如何成功孵化手机版龙蛋) May 04, 2024 pm 06:01 PM

手机游戏成为了人们生活中不可或缺的一部分,随着科技的发展。它以其可爱的龙蛋形象和有趣的孵化过程吸引了众多玩家的关注,而其中一款备受瞩目的游戏就是手机版龙蛋。帮助玩家们在游戏中更好地培养和成长自己的小龙,本文将向大家介绍手机版龙蛋的孵化方法。1.选择合适的龙蛋种类玩家需要仔细选择自己喜欢并且适合自己的龙蛋种类,根据游戏中提供的不同种类的龙蛋属性和能力。2.提升孵化机的等级玩家需要通过完成任务和收集道具来提升孵化机的等级,孵化机的等级决定了孵化速度和孵化成功率。3.收集孵化所需的资源玩家需要在游戏中

手机字体大小设置方法(轻松调整手机字体大小) 手机字体大小设置方法(轻松调整手机字体大小) May 07, 2024 pm 03:34 PM

字体大小的设置成为了一项重要的个性化需求,随着手机成为人们日常生活的重要工具。以满足不同用户的需求、本文将介绍如何通过简单的操作,提升手机使用体验,调整手机字体大小。为什么需要调整手机字体大小-调整字体大小可以使文字更清晰易读-适合不同年龄段用户的阅读需求-方便视力不佳的用户使用手机系统自带字体大小设置功能-如何进入系统设置界面-在设置界面中找到并进入"显示"选项-找到"字体大小"选项并进行调整第三方应用调整字体大小-下载并安装支持字体大小调整的应用程序-打开应用程序并进入相关设置界面-根据个人

golang函数动态创建新函数的技巧 golang函数动态创建新函数的技巧 Apr 25, 2024 pm 02:39 PM

Go语言提供了两种动态函数创建技术:closures和反射。closures允许访问闭包作用域内的变量,而反射可使用FuncOf函数创建新函数。这些技术在自定义HTTP路由器、实现高度可定制的系统和构建可插拔的组件方面非常有用。

C++ 函数命名中参数顺序的考虑 C++ 函数命名中参数顺序的考虑 Apr 24, 2024 pm 04:21 PM

在C++函数命名中,考虑参数顺序至关重要,可提高可读性、减少错误并促进重构。常见的参数顺序约定包括:动作-对象、对象-动作、语义意义和遵循标准库。最佳顺序取决于函数目的、参数类型、潜在混淆和语言惯例。

excel函数公式大全 excel函数公式大全 May 07, 2024 pm 12:04 PM

1、 SUM函数,用于对一列或一组单元格中的数字进行求和,例如:=SUM(A1:J10)。2、AVERAGE函数,用于计算一列或一组单元格中的数字的平均值,例如:=AVERAGE(A1:A10)。3、COUNT函数,用于计算一列或一组单元格中的数字或文本的数量,例如:=COUNT(A1:A10)4、IF函数,用于根据指定的条件进行逻辑判断,并返回相应的结果。

C++ 函数默认参数与可变参数的优缺点比较 C++ 函数默认参数与可变参数的优缺点比较 Apr 21, 2024 am 10:21 AM

C++函数中默认参数的优点包括简化调用、增强可读性、避免错误。缺点是限制灵活性、命名限制。可变参数的优点包括无限灵活性、动态绑定。缺点包括复杂性更高、隐式类型转换、调试困难。

如何在Java中写出高效和可维护的函数? 如何在Java中写出高效和可维护的函数? Apr 24, 2024 am 11:33 AM

编写高效和可维护的Java函数的关键在于:保持简洁。使用有意义的命名。处理特殊情况。使用适当的可见性。

See all articles