js--函数

122 阅读7分钟

js--函数

函数声明

语法:function funName([参数1],[参数2]) {}

函数可以通过名称调用:funName()

参数是可选的,参数之间用逗号分隔。

function showMessage() {
  console.log( 'Hello everyone!' );
}
showMessage()
// Hello everyone!
 function handel(a, b) { console.log(a+'----'+b) }
handel(1, 2)
//1----2

变量

函数拥有单独的作用域。

函数内定义的变量只能在函数内可见。

 function handle() {
     var a = 1
     let b = 2
     console.log(a + '----' + b)
   }
   handle()
   console.log(a + '----' + b)
   // 1----2
   // Uncaught ReferenceError: a is not defined

函数可以访问函数外的变量,也可以改变外部变量的值。

如果函数内定义的变量与外部的变量同名,优先使用内部的值。

 let b = 3
 let a = 1
 function handle() {
    let b = 2
    console.log(a)
    console.log(b)
 }
 handle()
 // 1
 // 2

参数

参数(函数传参)将任意数据传递给函数。

函数的参数分为形参实参

形参:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。

实参:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。

function handle(a, b) { //形参
    console.log(a + '----' + b)
}
handle(1, 2) // 实参
// 1----2

默认值

如果为实参未提供,形参默认值为undefined

function handle(a, b) {
   console.log(a + '----' + b)
}
handle(1)
// 1----undefined

如果想设定默认值,可以在形参后用=指定。

默认值可以是复杂的表达式。只会在实参缺少参数或设置参数为undefined时才会被计算和分配。

 function handle(a, b = '默认值', c = 1 + 2) {
   console.log(a + '----' + b + '----' + c)
 }
 handle(1)
 handle(1,0)
 // 1----默认值----3
 // 1----0----3

可以通过||或运算符设置默认值。

或运算符无法区别出0,false,null,undefined,NaN,设置这些值仍显示默认值

function handle(a, b) {
   var b = b || 2
   console.log(a + '----' + b)
 }
 handle(1)
 handle(1,0)
// 1----2
// 1----2

其他方法: 空值合并运算符??和条件分支if。

arguments(严格模式不可用)

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

arguments对象是所有(非箭头)函数中都可用的局部变量

arguments包含传递给函数的每个参数,第一个参数在索引0处,长度由实际参数个数决定.

实参没有对应得形参,也可以通过arguments[下标]访问到。

函数中的形参和实参是可以相互影响的。

 function handle(a, b) { console.log(arguments)}
   handle(1) // [1, callee: ƒ, Symbol(Symbol.iterator): ƒ]
   handle(1, 2) //[1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
   handle(1, 2, 3) // [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
   ---------------------------------------------------------------------
    function handel(a, b) {
          arguments[0] = 2
          console.log(a)
           b = 3
           console.log(arguments[1])
    }
    handel(1, 2) // 2 3

rest(剩余)参数,默认参数解构赋值下,arguments对象中的值不会跟踪参数的值,只会更改arguments中对应的值,不会更改形参中对应的值,反之亦然。

function handel(a, b, ...c) {
       arguments[0] = 22
       console.log(a)
       console.log(arguments[0])
       b = 55
       console.log(b)
       console.log(arguments[1])
  }
   handel(1, 2, 3, 4) // 1 22 55 2

callee:(严格模式下不可用)

返回一个正在被执行函数的引用 。

function handel() { console.log(arguments.callee) }
handel()
// ƒ handel() { console.log(arguments.callee) }

返回值

函数可以使用renturn 将一个值返回到调用代码中作为结果。

  function handle(a, b) {
   return a + b
   }
   console.log(handle(1, 2))  //3

函数中可以出现多个return。

function handle(a, b) {
    if (a === 1) {
        return a + b
     } else {
        return a - b
     }
} 
  console.log(handle(1, 2))

没有return或者只有return返回值为undefined

 function handle(a, b) {
    if (a === 1) {
        return
     }
 }
 console.log(handle(1, 2))   // undefined
  console.log(handle(2, 2))  // undefined

return会导致函数立即退出,之后的代码不再执行。

function handle(a, b) {
    return a + b
    console.log(a + '----' + b)
    }
    console.log(handle(1, 2))
   // 3 

不要在 return 与返回值之间添加新行,js 默认会在 return 之后加上分号。

function handle(a, b) {
                return
                (a + b)
            }
  console.log(handle(1, 2)) //undefined
  相当于
  function handle(a, b) {
       return;
         (a + b)
    }

如果我们想要将返回的表达式写成跨多行的形式,那么应该在 return 的同一行开始写此表达式。或者至少按照如下的方式放上左括号:

函数表达式

一种创建函数的方式。

语法: let funName = function [函数名] () { };

函数被创建并像其他赋值一样,被明确分配给一个变量。

函数表达式结尾要加分号;

 let handel = function name() {
                console.log('函数表达式')
            };
  handel() //函数表达式

在代码块的结尾不需要加分号 ;,像 if { ... }for { }function f { } 等语法结构后面都不用加。

函数表达式是在语句内部的:let sayHi = ...;,作为一个值。它不是代码块而是一个赋值语句。不管值是什么,都建议在语句末尾添加分号 ;。所以这里的分号与函数表达式本身没有任何关系,它只是用于终止语句。

函数声明 vs 函数表达式

函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。

在函数声明被定义之前,它就可以被调用。

严格模式下,当一个函数声明在一个代码块内时,它在该代码块内的任何位置都是可见的。但在代码块外不可见。

 handel()
 var handel = function name() {
    console.log('函数表达式')
 }
 // Uncaught TypeError: handel is not a function
 --------------------------------------------------------
  handel()
  function handel() {
      console.log('函数声明')
  }
  // 函数声明

函数对象

在js中,函数是对象。

 function handel(params) {}
 console.log(Object.prototype.toString.call(handel)) 、
 // [object Function]
function handel(params) {}
console.dir(handel)
// arguments: null
// caller: null
// length: 1
// name: "handel"

name属性:

函数声明的名字可以通过name来访问。

function handel(params) {}
console.dir(handel.name)
// handel

函数表达式的名字也可以通过name来访问。在赋值中,会根据上下文来推测一个

如果函数自己没有提供,name在被赋值时,会赋值变量的名称。

如果函数自己提供,name在被赋值时,会赋值函数的名称 。该函数名称只能在函数内部使用。

 let handel = function () {
      console.log(handel.name)
   }
  handel()
  console.log(handel.name) //handel handel
-------------------------------------------------------
let handel = function fun() {
    console.log(fun.name)
    console.log(handel.name)
 }
    handel()
   console.log(handel.name)  // fun fun fun
   console.log(fun.name) // Uncaught ReferenceError: fun is not defined

无法推测时,name显示为空。

let arr = [function () {}]
 console.log(arr[0].name)
 // ''

length属性

它返回函数形参的个数。但是rest(剩余)参数不参与计数。

 function handel(a) { console.log(handel.length) }
 function handel1(a, b) { console.log(handel1.length) }
 function handel2(a, b, ...c) { console.log(handel2.length) }
 handel(1, 2, 3, 4)  //1
 handel1(1, 2, 3, 4) //2
 handel2(1, 2, 3, 4) // 2

自定义属性

我们也可以添加自己的属性。

 function handel(a) {
   console.log(handel.CustomProperties)
 }
  handel.CustomProperties = '自定义属性'
  console.log(handel.CustomProperties) //自定义属性
  handel() //自定义属性

caller:(严格模式下无法使用)

返回一个调用当前函数的引用 如果是由顶层调用的话,则返回null。

 function handel() {  console.log(handel.caller) }
 function handel1() { handel() }
 handel1()
 handel()
 // ƒ handel1(params) {  handel() }
 // null

自执行函数

一般使用:(function(){ })()或者 (function(){ }());

声明函数的结构花括弧后面不能有其他符号,但是函数表达式可以。

 function handel(){  console.log('自执行')  }()  
 // Uncaught SyntaxError: Unexpected token ')'
 let handel = function handel() {  console.log('自执行') }()
 //自执行

要想立即执行,函数必须是函数表达式。

而在function前面加上!、()、+、-、=等运算符,都可以将函数声明转换成为函数表达式。

+function(){  console.log('自执行1');}();   //自执行1
-function(){  console.log('自执行2');}();   //自执行2
!function(){  console.log('自执行3');}();   //自执行3
(function(){  console.log('自执行4');})();  //自执行4
(function(){  console.log('自执行5');}());  //自执行5

new Function

new Function是一种创建函数的方式,但是很少用到。

语法:let func = new Function ([arg1, arg2, ...argN], functionBody);

new Function 允许我们将任意字符串变为函数。

写法:

new Function('a', 'b', 'return a + b'); // 基础语法

new Function('a,b', 'return a + b'); // 逗号分隔

new Function('a , b', 'return a + b'); // 逗号和空格分隔

new Function('console.log(1111)'); // 只有函数体

 let handel = new Function('a', 'b', 'c', 'return a+b+c')
 console.log(handel(1, 2, 3)) 
 // 6
 let handel = new Function('a,b,c', 'return a+b+c')
  console.log(handel(1, 2, 3))
  //6 
 let handel = new Function('a ,b ,c ', 'return a+b+c')
  console.log(handel(1, 2, 3))
   // 6
 let handel = new Function('console.log(1111)')
 console.log(handel())
   // 1111 

new Function 创建的函数无法访问外部变量,只能访问全局变量。

 let x = 20
 function handel() {
     let x = 10
     let func = new Function('console.log(x)')
      func()
 }
 handel()
 // 20

箭头函数

箭头函数是另一种创建函数的方式,比函数表达式更简洁。

写法

let func = (param1, param2, …, paramN) => { statements }

let func = (arg1, arg2, ...argN) => expression

第二种相当于 (param1, param2, …, paramN) =>{ return expression; }

当代码块只有一个语句时{}可以省略,多行必须加花括号。

没有参数 ,括号也要保留。

let handel = () => console.log('箭头函数')
handel() 
// 箭头函数

参数只有一个时,括号是可选的。

 let handel = a => console.log(a)
 handel(1) // a 

箭头函数在参数和箭头之间不能换行。

 let handel = (a)
            => console.log(a)
 handel(1)
 // Uncaught SyntaxError: Unexpected token '=>'

特点:

没有单独的this

没有arguments

不能new

也没有 super

还有尾调用函数柯里化可以了解下。