好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

JavaScript 函数

JavaScript 函数

在 JavaScript中, 函数 是头等 (f irs t-class) 对象,因为它们可以像任何其他对象一样具有 属性 和 方法 。它们与其他对象的区别在于 函数 可以被 调用 。简而言之,它们是 Function 对象。(MDN)

函数 就是一段 代码 片段, 调用 函数 就是执行 函数 中的 代码 。

1. 函数 的使用

1.1 语法

函数 使用前通常与变量一样需要先进行声明,用 function 关键字定义 函数 。

  // 常见的 函数 的定义方式 
 function    函数 名  ( 参数 ,  参数 ,   ...  )   { 
   代码 片段 ; 

   return  返回值 ; 
 } 

 //  调用  函数  (执行 函数 中的 代码 ) 
 var   函数 的返回值  =    函数 名  ( 参数 ,  参数 ,   ...  )  ; 
 

调用 函数 就是执行 函数 中的 代码 参数是 调用 函数 的时候传递过去的,在 函数 执行过程中可以访问到 函数 执行完毕后可以有 一个 返回值, 调用 函数 的地方可以接收到这个返回值

1.2 调用 函数

使用 函数 名() 的方式即可 调用 一个 函数

以下是 一个 最简单的 函数 :

  function   say  (  )   { 
  console .  log  (  'hello'  )  ; 
 } 

 say  (  )  ;   //  输出 :"hello" 
 

调用 这个 函数 就会在控制台 输出 hello 字符串。

这个 函数 没有返回值, 默 认会返回 一个 undefined 。

1.3 带有参数与返回值的 函数

在声明 函数 的时候,可以对参数也做上说明

假设有 一个 需求, 需要 一个 计算三角形周长的 函数 。

计算三角形周长则需要知道三角形三条边各自的长度,然后将他们求和。

定义 函数 的时候就可以将三条边作为参数进行声明。

  function   calcPerimeter  ( a ,  b ,  c )   { 
   // a, b, c 分别代表三条边 
   var  sum  =  a  +  b  +  c ; 

   return  sum ; 
 } 

 //  调用  函数  并将返回值赋值给perimeter 
 var  perimeter  =   calcPerimeter  (  ,   ,   )  ; 
 

在 调用 函数 的时可以 传递值 过去,这些值可以在 函数 中被访问。

在以上 calcPerimeter 函数 被 调用 的时,传递了 3, 4, 5 三个值。

三个值对应到 函数 声明时定义的三个参数 a, b, c 。

所以 函数 执行过程中 sum 的值为 3 + 4 + 5 ,即 12 ,随后 sum 被作为返回值进行返回。

最终变量 perimeter 也会被赋值为12。

2. 怎么运用 函数

2.1 合理包装 内容

函数 可以对 代码 进行封装,让逻辑更加清晰。

比如如下 代码 块:

  // 改写前 
 var  num  =   ; 

 var  flag  =   false  ; 

 var  i ; 
 var  len ; 
 for   ( i  =   ,  len  =  num  -   ;  i  <=  len ;  i ++  )   { 
     if   ( num  %  i  ===   )   { 
        flag  =   true  ; 
         break  ; 
     } 
 } 

console .  log  ( flag )  ; 
 

以上 代码 第一眼可能无法看出具体在做什么,仅需 要做 一点 修改 ,就能有所改善。

  // 改写后 
 function   isPrimeNumber  ( num )   { 
   var  flag  =   false  ; 
  
   var  i ; 
   var  len ; 
   for   ( i  =   ,  len  =  num  -   ;  i  <=  len ;  i ++  )   { 
     if   ( num  %  i  ===   )   { 
      flag  =   true  ; 
       break  ; 
     } 
   } 

   return  flag ; 
 } 


 var  num  =   ; 

 var  result  =   isPrimeNumber  ( num )  ; 

console .  log  ( result )  ; 
 

改写后的 代码 似乎多了几行,但是将其中核心部分包装成了 函数 。

通过 isPrimeNumber 函数 名可以很容易的了解到这一段 代码 作用是用来判断 一个 数是否为 质数 。

当然有个前提就是起 一个 可以让大部分人看得懂 的 函数 名。

2.2 优秀的 函数 名

优秀的 函数 名可以帮助他人更容易理解 代码 ,同时当自己一段时间后再回头看 代码 时,能更容易进入当时写 代码 时候的思维模式等。

这里提供几个 函数 命名的建议,具体的命名可以根据团队规范、个人成长等做调整。

2.2.1 拼写准确

准确的拼写十分重要,绝大多数情况下 函数 名都会是英文单词组成的。

当然许多时候手一快可能就少了 一个 字母,或者错将 wrap 进行乾坤大挪移拼写成了 warp 。

许多情况是无法避免的,经常需要自检。

当然可以借助一些单词的检查 插件 ,如 Visual Stu dio Code 可以借助 Code Spell Checker 插件 来检查单词的正确性。

再者碰到想起的 函数 名但是单词拼写不出来,尽可能翻词典,日积月累能有大量的词汇沉淀。

2.2.2 尽量不使用拼音或者混用拼写

尽量不要使用拼音或者是首字母缩写。

以下 函数 名或许会造成困扰:

  function   jslsh  (  )   {  } 

 function   jsNumber  (  )   {  } 
 

以上是 计算两数和 函数 的命名,可能只有天和地知道这个是什么意思。

当然,如果是自己写 demo 或者测试 代码 的时候,其实不需要考虑这么多。

2.2.3 有“状态”的 函数 名

如碰到 函数 功能 是判断 是否 、 有没有 、 可以 的时候,可以带上一些前缀,比如:

  // 是否登入 
 function   isLogin  (  )   {  } 
 

同时可以合理的使用动词,比如 打开 文件 就可以使用 openFile 函数 名,具体的状态可以根据语境、 函数 作用、个人习惯等做调整使用。

2.2.4 合理使用缩写

使用词语的缩写尽量使用通用的缩写

如:

pwd - password mgr - manager del - delete …

这些缩写大部分开发者是可以看的懂的缩写。

3. 函数 示例

3.1 计算圆的面积

分析:根据圆面积公式 S=π·r·r,其中 S 就是要求的值,即 函数 的返回值,π 是常量(固定的 一个 值),半径r是未知数,所以r就可以设计成参数

  function   circleArea  ( r )   { 
     var  pi  =   ; 

     return  pi  *  r  *  r ; 
 } 

 // 计算半径为10的圆的面积 
 var  area  =   circleArea  (  )  ; 
 

3.2 判断某个DOM元素是否含有某个类名

分析:

某个DOM 和 某个类名 可以说明有两个未知量,可以设计成两个参数。

根据描述也可以确定 一个 某个DOM 的类型是个 DOM 对象, 某个类名 是个字符串

只要拿到这个DOM的 class 属性 ,判断里面是不是含有这个类型即可得到结果

  function   hasClass  ( el ,  className )   { 
   // el 是 element的缩写,表示 一个 dom元素 
  
   // 如果没有元素 则返回 
   if   (  ! el )   { 
       return   false  ; 
   } 

   // 根据空格分割成数组 
   // 可以不使用 split  方法 ,使用字符串也可以用indexOf匹配 
   var  classList  =  el . className .  split  (  ' '  )  ; 

   // 判断是否存在 
   if   ( classList .  indexOf  ( className )   >=   )   { 
       return   true  ; 
   } 
  
   return   false  ; 
 } 
 

4. 函数 的其他知识

以下扩展 内容 可能需要一定的知识积累,遇到不懂的地方可以停下脚步,先学习下一章节

4.1 函数 表达式

以上篇幅的 函数 其实都通过 函数 声明 的方式来定义,还有一种方式就是使用 函数 表达式定义 函数 。

  //  函数 声明 
 function   add  ( a ,  b )   { 
     return  a  +  b ; 
 } 

 //  函数 表达式 
 var   add   =   function  ( a ,  b )   { 
     return  a  +  b ; 
 }  ; 
 

通过上述例子可以看出写法上的区别就是 函数 表达式 是将 函数 赋值给了变量。

这两种方式创建的 函数 最大的区别在于, 不能提前 调用 使用 函数 表达式创建的 函数

光看句子有点抽象,举个例子?:

  var  num1  =   add1  (  ,   )  ; 

 var  num2  =   add2  (  ,   )  ; 

 //  函数 声明 
 function   add1  ( a ,  b )   { 
     return  a  +  b ; 
 } 

 //  函数 表达式 
 var   add2   =   function  ( a ,  b )   { 
     return  a  +  b ; 
 }  ; 
 

上面一段 代码 在执行的时候会报 add2 is not a function 的 错误 ,表示 add2 不是 函数 ,也就是说 add2 不能被提前使用,而 add1 可以。

具体原因可以查看 执行上下文 章节。

4.2 函数 作用域

函数 有他自己的作用域, 函数 内声明的变量等 通常情况下 不能被外部访问,但是 函数 可以访问到外部的变量或者其他 函数 等

  var  a  =   ; 

 function   fn  (  )   { 
     var  b  =   ; 

    console .  log  ( a )  ;   //  输出 :1 
    console .  log  ( b )  ;   //  输出 :2 
 } 

 fn  (  )  ; 

console .  log  ( b )  ;   // ReferenceError: b is not defined 
 

执行以上 代码 会报 b is not defined 错误 。

4.3 匿名 函数

没有名字的 函数 就是 一个 匿名 函数

  var   fn   =   function  (  )   { 
    console .  log  (  '我是 一个 匿名 函数 '  )  ; 
 }  ; 
 

除了在 函数 表达式 中会出现匿名 函数 ,还有许多场景。

相对常见的 一个 就是 自执行匿名 函数 ,MDN官方翻译为 立即 调用 函数 表达式 。

自执行 就是这个 函数 声明后就会立即执行,自执行的匿名 函数 通常会被用来 形成独立的作用域 。

如:

  (  function  (  )   { 
     var  num  =   ; 

     alert  ( num )  ; 
 }  )  (  )  ; 
 

这是 一个 自执行的匿名 函数 ,这个匿名 函数 是被包裹了一段括号后才被 调用 的。

以下这段 代码 会报错:

  // 报错 
 function  (  )   { 
     var  num  =   ; 

     alert  ( num )  ; 
 }  (  )  ; 
 

浏览器会告诉你必须给 函数 一个 名字。

通过括号包裹一段 函数 ,让 js引擎 识别成他是 一个 函数 表达式,再对他进行执行,就不会报错,这是加括号的原因。

同理,可以使用 + , ! 等运算符代替括号,让 一个 匿名 函数 成为 一个 函数 表达式即可。

大部分第三方框架都会通过 一个 自执行的匿名 函数 包裹 代码 ,与浏览器全局环境隔离,避免污染到全局环境。

4.4 具有 函数 名的 函数 表达式

函数 表达式进行声明的时候也可以使用具名 函数

  var   count   =   function   fn  ( num )   { 
    console .  log  (  '我是 一个  函数 '  )  ; 
 }  ; 
 

以上这段 代码 是不会报错的,但是不能通过 fn 访问到 函数 ,这里的 fn 只能在 函数 内部进行访问,通常在使用递归的形式做计算的时候会用到这种写法。

  var   count   =   function   fn  ( num )   { 
     if   ( num  <   )   { 
         return  num ; 
     } 

     return   fn  ( num  -   )   +  num ; 
 } 

 count  (  )  ; 
 

上面这个例子,就是在 函数 内部访问 fn 调用 自己,使用递归的形式求和。

注:递归相关的知识可以参考相关文献进行学习

4.5 arguments

arguments 是 一个 对应于传递给 函数 的参数的类数组对象。(MDN)

通常情况下 函数 都具有 arguments 对象,可以在 函数 内部直接访问到。

他是 一个 类数组,即长得很像数组,成员都是用数字编号,同时具有 length 属性 。

arguments 中存放着当前 函数 被 调用 时,传递过来的所有参数,即便不声明参数,也可以通过 arguments 取到传递过来的参数。

  function   sum  (  )   { 
    console .  log  ( arguments )  ; 
 } 

 sum  (  ,   ,   ,   )  ; 
 

执行上述 代码 ,可以看到在控制台 输出 了 一个 对象,存放的就是所有传递过去的参数,利用这一特性,就可以不限制参数个数,或者让 函数 做中转站( 拦截 函数 ),利用 arguments 将参数传递给另 一个 函数 。

如, 一个 不确定 用户 输入的参数个数的 求和函数 :

  function   sum  (  )   { 
   var  total  =   ; 

   var  i ; 
   var  len ; 
   for   ( i  =   ,  len  =  arguments . length ;  i  <  len ;  i ++  )   { 
    total  +=  arguments [ i ]  ; 
   } 

   return  total ; 
 } 

 var  total  =   sum  (  ,   ,   ,   ,   )  ; 
console .  log  ( total )  ;   //  输出 :25 
 

通过循环遍历 arguments 对象,就可以得到所有参数,然后做累加就可以达到求和的目的。

4.6 函数 和 方法

方法 在本质上是个 函数 。

通常都能听到“ 调用 一下某个 方法 ”,“取到某个 方法 的返回值”,这里的 方法 其实就是 一个 函数 。

一般 方法 是用来描述对象的某个行为的,但是平时我们会混用,口头交流的时候会经常把 函数 直接称作 方法 。

只要自己理解,不需要去纠结 函数 和 方法 到底是什么,也不用特意纠正别人的说法,大家都能听得懂就行。

4.7 JS DOC 注释

使用 JS DOC 描述 函数 是非常良好的习惯,良好的 JS DOC 书写还可以使用工具 快速 生成 文档。

JS DOC 对 函数 的描述大体如下:

  /**
 * 这是这个求幂 函数  计算 x 的 y 次方
 * @p ara m {Number} x - 底数
 * @p ara m {String} y - 指数
 */ 
 function   pow  ( x ,  y )   { 
     // ... 
 } 
 

除此之外还可以描述返回值等。

4.8 纯 函数 与副作用

所谓纯 函数 ,就是没有副作用的 函数

一个 函数 从执行开始到结束,没有对外部环境做任何操作,即对外部环境没有任何影响(没有副作用),这样的 函数 就是纯 函数 。

纯 函数 只负责输入 输出 ,对于一种输入只有一种 函数 返回值。

如果 函数 中存在 Math.random 这种影响返回值的 函数 ,也不能算是纯 函数 。

  // 纯 函数  
 function   add  ( a ,  b )   { 
   return  a  +  b ; 
 } 

 // 非纯 函数  
 var  person  =   {  name :   '小明'   }  ; 
 function  changeName  { 
  person . name  =   '小红'  ;   // 影响了 函数 外的 内容 ,产生了副作用 
 } 
 

4.9 构造 函数

当 一个 函数 与 new 关键字一起被 调用 的时候,就会作为 一个 构造 函数 。

  function   Person  ( name ,  age )   { 
     this  . name  =  name ; 
     this  . age  =  age ; 
 } 

Person . prototype .  say   =   function  (  )   { 
    console .  log  (  '我是'   +   this  . name )  ; 
 }  ; 

 var  person  =   new   Person  (  '阿梅'  ,   )  ; 

person .  say  (  )  ; 

console .  log  ( person )  ; 
 

可以看到当 函数 作为构造 函数 调用 的时候, 默 认返回的是 一个 对象。

细心的读者仔细观察就能发现,构造 函数 的 默 认返回值是 函数 体内的 this。

事实上构造 函数 的执行有一定流程:

创建 一个 空对象,将 函数 的this指向这个空对象 执行 函数 如果 函数 没有指定返回值,则直接返回 this(一开始创建的空对象),否则返回指定返回值

理解这个流程,就能理解构造 函数 的返回值。

具体的 函数 的 prototype 属性 等可以参阅 原型 章节。

5. 小结

函数 特性相对较多,也是 JavaScript 的核心之一。

函数 可以用于 封装代码 ,提供 代码 的复用率和可读性,在大部分情况下,当两段 代码 具有超高相似度时,应当设计成 函数 ,不同的部分使用参数进行区分。

JavaScript 对象 ? ?JavaScript 表达式

查看更多关于JavaScript 函数的详细内容...

  阅读:58次

上一篇

下一篇

第1节:什么是 JavaScript    第2节:学习环境准备    第3节:调试方案    第4节:JavaScript 变量    第5节:JavaScript 数据类型    第6节:JavaScript if 语句    第7节:for 语句    第8节:JavaScript 算数运算符    第9节:JavaScript 比较运算符    第10节:JavaScript 逻辑运算符    第11节:JavaScript 函数    第12节:JavaScript 表达式    第13节:JavaScript 对象    第14节:JavaScript 字符串    第15节:JavaScript 数字    第16节:JavaScript 数组    第17节:JavaScript switch 语句    第18节:JavaScript while 语句    第19节:JavaScript 的 break 与 continue    第20节:JavaScript with    第21节:document.cookie    第22节:JavaScript Function    第23节:JavaScript Math    第24节:JavaScript Date    第25节:JavaScript RegExp    第26节:JavaScript JSON    第27节:什么是 DOM    第28节:DOM 和 JavaScript 的关系    第29节:获取和操作 DOM 节点    第30节:DOM 与事件    第31节:DOM 事件绑定    第32节:DOM 事件对象    第33节:DOM 事件流    第34节:事件相关的优化    第35节:自定义事件    第36节:表单校验    第37节:什么是 BOM    第38节:常用的 BOM 相关对象    第39节:BOM 常用属性和方法    第40节:AJAX    第41节:异常处理    第42节:三元运算符    第43节:逗号操作符    第44节:void    第45节:typeof    第46节:delete 操作符    第47节:debugger    第48节:getter & setter    第49节:new 运算符与构造函数    第50节:JavaScript 原型    第51节:JavaScript instanceof    第52节:JavaScript this    第53节:严格模式    第54节:作用域    第55节:闭包    第56节:变量提升    第57节:对象包装器    第58节:Lodash    第59节:moment    第60节:swiper    第61节:ECMAScript 6    第62节:Node.js    第63节:Babel    第64节:CSS 预处理器    第65节:代码规范    第66节:TypeScript    第67节:WebComponents    第68节:Vue、React、Angular    第69节:小程序    第70节:JavaScript 关键字    第71节:分号导致的问题    第72节:对象属性访问问题    第73节:this 使用问题    第74节:浮点数精度问题    第75节:独一无二的 NaN    第76节:避免全局污染    第77节:控制台观察对象问题    第78节:根据环境选择语言特性    第79节:相关资源