JavaScript函数
# JavaScirpt中的函数
在JavaScript中,alert()
,prompt
,console.log
都是函数,String
,Number
,Boolean
也是函数。
函数就是某段代码的封装,这段代码帮助我们完成某一个功能,默认情况下JavaScript引擎或者浏览器会给我们提供一些已经实现好的函数。
# 函数声明和调用
# 函数声明
function 函数名(){
函数封装代码
}
2
3
# 函数调用
直接通过函数名()
调用即可。
# 函数的参数
函数的参数增加了函数的通用性,针对相同的数据处理逻辑能够适应更多的数据;在函数的内部把参数当做变量使用;函数调用时,按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递
# 函数返回值
函数不仅仅可以接收参数,也可以有返回值;
- 使用return关键字来返回结果,
- 一旦在函数中执行return操作,那么当前函数就会终止;
- 如果函数中没有使用return 语句,那么函数有默认的返回值undefined
- 如果函数使用return 语句,但是return后面没有任何值,那么函数的返回值也是undefined。
案例:封装一个工具函数将数字转换为万、亿
function formatCount(count){
var result = 0
if(count >= 10_0000_0000){ // 10_0000_0000是1000000000的语法糖
result = Math.floor(count / 1_0000_0000)+"亿"
} else if(result >= 10_0000) {
result = Math.floor(count / 1_0000)+"万"
} else {
result = count
}
return result
}
2
3
4
5
6
7
8
9
10
11
# arguments参数
在函数中存在一个特别的对象,arguments对象
- 默认情况下
arguments
对象是所有(非箭头)函数中都可以使用的局部变量 - 该对象中存放着所有的调用者传入的参数,从0开始,依次存放
- arguments变量的类型是一个object类型(array-like),不是一个数组,但是和数组的用法看起来类似
- 如果调用者传入的参数多于函数接收的参数,可以通过
arguments
去获取所有的参数
function foo(...arguments) {
console.log(typeof arguments);
console.log(arguments);
if (arguments) {
console.log(arguments[0]);
}
}
foo();
foo(1, 2, 3);
foo({ name: "zs" }, { name: "ls" });
2
3
4
5
6
7
8
9
10
function foo() {
console.log(typeof arguments);
console.log(arguments);
console.log(...arguments)
if (arguments) {
console.log(arguments[0]);
}
}
foo();
foo(1, 2, 3);
foo({ name: "zs" }, { name: "ls" });
2
3
4
5
6
7
8
9
10
11
arguments案例
function sum (){
var sum = 0
for(var i = 0; i < arguments.length; i++){
sum += arguments[i]
}
return sum;
}
2
3
4
5
6
7
# 斐波那契数列实现
菲波那切数列,除了第一个位置和第二个位置外,当前位置的数字等于前面两个数字的和
递归实现
function fibonacci(n){
if(n === 1 || n === 2) return 1
return fibonacci(n - 1) + fibonacci(n - 2)
}
2
3
4
for循环实现
function fibonacci(n) {
if(n === 1 || n === 2) return 1;
var n1 = 1;
var n2 = 1;
var result = 0;
for(var i = 3; i <= n; i++){
result = n1 + n2;
n1 = n2;
n2 = result;
}
return result;
}
2
3
4
5
6
7
8
9
10
11
12
# 局部变量和外部变量
外部变量和局部变量的概念
- 定义在函数内部的变量称之为局部变量
- 定义在函数外部的变量称之为外部变量
- 函数的作用域表示在函数内部定义的变量,只有在函数内部才可以被访问到
for (var i = 0; i < 3; i++) {
console.log(i);
var foo = "foo";
}
console.log("for循环外面访问foo:", foo); // foo
console.log("for循环外面访问i: ", i); // 3
function test() {
var bar = "bar";
}
test();
console.log("test函数外面访问bar: ", bar); // undefined
2
3
4
5
6
7
8
9
10
11
函数有自己的作用域,函数内部定义的变量只有函数内部能访问到
TODO:变量的访问顺序
var message = 'outmessage';
function outFunction(){
var message = 'onemessage'
console.log('onemessagfe: ', message) // onemessagfe: onemessage
function innerFunction(){
var message = 'towmessage'
console.log('twomessage: ',message) // twomessage: towmessage
}
innerFunction()
}
console.log('message: ', message) // message: outmessage
outFunction()
2
3
4
5
6
7
8
9
10
11
12
13
# 全局变量
在函数之外声明的变量称之为全局变量;全局变量在任何函数中都是可见的;通过var声明的全局变量会在window对象上添加一个属性。
# 函数表达式
在JavaScript中,函数是一种特殊的值,function 函数名(){}
的方式称之为函数的声明。
另外一种形式
var foo = function(){
console.log('函数表法式')
}
2
3
这种方式成为函数表达式;function关键字后面没有函数名,函数表达式是允许省略函数名的
无论函数是如何创建爱你的,函数都是一个值(这个值的类型是一个对象)
# 函数的声明以及调用方式对应的结果
# 函数表达式和函数声明的对比
- 语法不同
- 函数声明:在主流代码中声明为单独语句的函数
- 函数表达式:在一个表达式中或者另一个语法结构中创建的函数
- JavaScript创建函数的时机不同
函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用
在函数声明之前定义,它就可以被调用
这是有有内部算法的原因
当JavaScript准备运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数
# 使用场景
当需要声明一个函数时,首先考虑函数声明语法,它能够为组织代码提供更多的灵活性,因为我们可以在声明这些函数之前调用这些函数
# JavaScript头等函数
头等函数(第一级函数)是指在程序设计语言中,函数被当做头等公民。因此,函数可以作为别的函数的参数,函数的返回值,赋值给变量或存储在数据结构中。
通常对作为头等公民的编程方式,称为函数式编程。JavaScript是符合函数式编程的语言,这也是JavaScript的一大特点。
比如函数可以在变量和变量之间相互赋值
function foo(){
console.log('函数执行')
}
var bar = foo
bar()
function sayHello(name) {
function hi(){
console.log('Hi '+name)
}
return h1
}
var fn = sayHello('zs') // 函数柯里化
fn()
2
3
4
5
6
7
8
9
10
11
12
13
14
# 回调函数
函数可以作为一个值相互赋值,那么也可以传递给另一个函数
function foo(fn){
fn()
}
function bar(){
console.log('bar函数被调用')
}
foo(bar)
2
3
4
5
6
7
上面代码中的foo函数也可以称之为高阶函数
高阶函数必须满足下面两个条件之一
- 接受一个或多个函数作为输入
- 输出一个函数
# 匿名函数
如果在传入一个函数时,我们没有指定这个函数的名词或者通过函数表达式指定函数对应的变量,那么这个函数称之为匿名函数。
# 立即执行函数
# 立即执行函数定义
专业名称:Immediately-Invoked Function Expression(IIFE立即调用函数表达式)
表达的含义是一个函数定义完后被立即执行
- 第一部分是定义了一个匿名函数,这个函数有自己独立的作用域
- 第二部分是后面的(),表示这个函数被执行了
(function(){ console.log('立即执行函数') })()
1
2
3
# 立即执行函数的作用
立即执行函数会创建一个独立的执行上下文环境,可以避免外界访问或修改内部的变量,也避免了对内部变量的修改
# 立即执行函数的应用场景一
a.js
var fModule1 = (function () {
var resultmodule = {};
var message = "World";
resultmodule.message = message;
return resultmodule; // 返回立即执行函数的结果
})();
2
3
4
5
6
7
a.html
<body>
<script src="./js/y1.js"></script>
<script>
console.log(fModule1)
</script>
</body>
2
3
4
5
6
# 立即执行函数应用场景二
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<button class="btn">4</button>
<button class="btn">5</button>
<script>
var btns = document.querySelectorAll(".btn");
for (var i = 0; i < btns.length; i++) {
(function (m) {
btns[m].onclick = function () {
console.log(`第${m}个按钮被点击了`);
};
})(i);
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 立即执行函数的其它写法
立即执行函数必须是一个表达式(整体),不能是函数声明
下面这种写法会报错,因为是一个函数声明,不是一个函数表达式
function foo(){
console.log('立即执行函数')
}()
2
3
当()
出现在匿名函数的末尾想要调用函数时,他会默认将函数当成是函数声明。
当()
包裹函数时,它默认将函数作为表达式去解析,而不是函数声明
(function foo(){
console.log('立即执行函数')
})()
2
3
下面这种代码也是一个函数表达式,所以可以立即执行
// + - ! 都可以
+function foo(){
console.log('立即执行函数')
}()
(function foo(){
console.log('立即执行函数')
}())
2
3
4
5
6
7