概念
函数就是将某一段代码进行封装,并为这段代码起个名子,通过这个名子就可以调用这段代码,使用函数可以实现代码复用、便于修改;
函数声明
JavaScript 有三种声明函数的方法
[1]函数声明式
函数声明式是使用 function关键字 来定义函数; function关键字后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面
-
语法
-
function 函数名(形参){ // 函数体 }
-
-
举例说明
-
function paly(str){ return `我最喜欢玩${ str}` }
-
[2]函数表达式
采用变量赋值的方法,写一个匿名函数赋值给变量,这又称作函数表达式(因为等号右侧只能是表达式)
-
语法
-
const 变量名 = function(){ // 函数体 }
-
-
举例说明
-
const play = function(str){ return `我最喜欢玩${ str}` }
-
-
注意事项
-
采用函数表达式声明函数时,function关键字后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效;
-
const play = function toplay(str){ console.log('toplay1', toplay) return `我最喜欢玩${ str}` } play() // f toplay(str){...} console.log('toplay2', toplay) // Error toplay is not defined
-
[3]使用构造函数声明函数
使用构造函数声明函数,参数中最后一个参数为函数体,除了最后一个参数之外的参数为函数的参数(不推荐使用);
-
语法
-
new Function(形参···,函数体)
-
-
示例
-
const paly = new Function('str','return `我最喜欢玩${str}`') console.log(paly('游戏')) // 我最喜欢玩游戏
-
函数调用
调用函数时,要使用圆括号运算符。圆括号之中,可以加入函数的参数;
函数名(实参)
函数提升
函数声明式具有函数提升->可以在声明之前调用
-
console.log('play', paly('游戏')) // play 我最喜欢玩游戏 function paly(str){ return `我最喜欢玩${ str}` }
-
上述代码等价于 将函数声明提升到
当前
作用域的最前面;-
function paly(str){ return `我最喜欢玩${ str}` } console.log('play', paly('游戏'))
-
函数表达式没有函数提升,必须先声明后使用;
但是使用var定义变量过程中具有变量提升
-
console.log('play', play) // undefined console.log('play', play('游戏')) // Error play is not a function var play = function(str){ return `我最喜欢玩${ str}` }
-
上述代码等价于
-
var play console.log('play', play) // undefined console.log('play', play('游戏')) // Error play is not a function play = function(str){ return `我最喜欢玩${ str}` }
-
使用let与const定义变量接收函数表达式则没有变量提升;
-
console.log('play', play) // Error Cannot access 'play' before initialization console.log('play', play('游戏')) let play = function(str){ return `我最喜欢玩${ str}` }
-
console.log('play', play) // Error Cannot access 'play' before initialization console.log('play', play('游戏')) const play = function(str){ return `我最喜欢玩${ str}` }
函数提升与变量提升的优先级
优先级:函数提升>变量提升
;若是函数名与变量名相同,提升过程中不会被覆盖
,但是重新赋值会被覆盖
;
-
举例说明·
-
console.log(bar); // function bar() { console.log(123); } console.log(bar()); // 123 undefined var bar = 456; function bar() { console.log(123); } console.log(bar); // 456 bar = 789; console.log(bar); //789 console.log(bar()) // bar is not a function /* 解析说明-[1]函数提升优先级大于变量提升,并且在提升过程中不会被变量提升覆盖 var bar = function() { console.log(123); } var bar console.log(bar); console.log(bar()); 解析说明-[2]变量赋值会将函数覆盖 bar = 456; console.log(bar); bar = 789; console.log(bar); console.log(bar()) */
-
函数重复声明
如果同一个函数被声明了多次,后一个函数就会覆盖
前一个函数的声明;与此同时需要注意由于函数声明式具有函数提升,因此第一次声明在任何时候都是无用的!!!
function test(){
console.log(111)
}
test() // 222
function test(){
console.log(222)
}
test() // 222
-
无论何时调用都是222
-
上面代码等价于
-
function test(){ console.log(111) } function test(){ console.log(222) } test() // 222 test() // 222
-
函数传值
函数涉及到的数据有两个方向:
- 1、函数外向函数内传递->通过
形参与实参
可以实现将函数外的数据传递给函数内部。 - 2、函数内向函数外传递->通过return关键字即可以实现将函数内的数据传递到函数的调用处
[1]参数
函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数;
function square(x) {
return x * x;
}
square(2) // 4
square(3) // 9
- 上面x就是square函数的形参,2、3就是square函数的实参;
形参与实参之间就是赋值的关系;
- 若是简单数据类型,无论怎么修改不会影响原始值;
- 若是复杂数据类型,相当于赋值的地址引用,
修改属性/元素将会影响原始值
;// 简单类型 function square(x) { x = 222 } const num = 111 square(num) console.log('num', num) // 111 // 引用类型 function square(x) { x.age = 22 } const obj = { name:'chaochao', age:18 } square(obj) console.log('obj', obj) // {name: 'chaochao', age: 22}
在函数调用过程中,实数是可以省略的,省略的参数的值就变为undefined
function square(x) {
return x * x;
}
console.log(square()) // NaN
-
但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined;
function f(a, b) { return a; } f( , 1) // SyntaxError: Unexpected token ,(…) f(undefined, 1) // undefined
如果有同名的参数,则取最后出现的那个值;
function f(a, a) { console.log(a); } f(1, 2) // 2
function f(a, a) { console.log(a); } f(1) // undefined
arguments对象
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来;
arguments是一个对应于传递给函数的参数的伪数组;
[1]除箭头函数外每个函数内部都有一个arguments对象
[2]作用是存储函数调用时传入的每一个参数(实参);