一.为什么使用函数?
用函数来解决代码重用的问题。
二.函数的意义
函数其实就是封装,把可以重复使用的代码放到函数中,如果需要多次使用同一段代码,就可以把封装成一个函数。这样的话,在你需要再次写这些代码的时候,你只需要调用一次函数就行了。
三.定义函数的方式
3.1 使用字面量的形式定义函数
ECMAScript中的函数使用function关键字来声明,后面跟一组参数及函数体。函数的基本语法如下:
// 1.字面量形式创建(推荐)
// function 函数名(参数){函数执行的代码}
// 形式参数 形参
function fun(num1, num2) {
console.log(num1 + num2);
}
// 调用函数
// 实际参数 实参
fun(1, 2);
3.2 使用函数表达式声明函数(匿名函数)
// 2.匿名函数
var fun2 = function () {
console.log("匿名函数");
}
fun2();
3.3 使用Function构造函数声明函数
// 3.构造函数方式创建函数
var fun3 = new Function("a", "b", "console.log(a+b)");
fun3(10, 20);
3.4 自执行函数
先前咱们写的函数只有在调动的时候才会执行,如果像下面这样写的话,代码执行到这一行的时候,函数会自己执行(或者说自己调用自己)。
(function(a){
console.log(a);
})("abc")
四. 函数的返回值return
<script>
// 创建函数
function fun(a, b) {
console.log(a + b);
// 返回值
return a + b;
console.log("aaaaaaa");
}
fun(1, 2);
console.log(fun(1, 2));
var res = fun(4, 5);
console.log(res);
</script>
注意点:
函数在执行完return语句之后停止并立即退出。因此,位于return语句后面的任何代码永远都不会执行。
一个函数中可以有多个return语句。
return语句也可以不带任何返回值。
五. arguments对象
<script>
// 创建函数
function fun(a, b, c, d) {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
// arguments对象 传递的参数组成的伪数组(不能使用数组的操作方法)
console.log(arguments);
console.log(arguments[0]);
console.log(arguments.length);
}
fun("张三", 2, 3, "李四");
function fun2() {
console.log(arguments);
}
fun2(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 不固定参数的情况下,求所有参数之和
</script>
arguments 是一个对应于传递给函数的参数的类数组对象。
可以使用arguments
对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引 0 处。例如,如果一个函数传递了三个参数
六. 函数是一种数据类型
-
function数据类型
-
函数作为参数
因为函数也是一种类型,可以把函数作为一个函数的参数,在一个函数中调用
<script>
function fun() {
console.log("hello world");
}
// 函数也是一种数据类型
console.log(typeof fun);
function fun2(a) {
// fun()
a();
}
// 调用 fun2
fun2(fun);
</script>
七. 作用域
作用域:指一个变量的作用范围。
目前的学习中,在Javascript将作用域分为 全局作用域 和 函数作用域(局部作用域)。
7.1 全局作用域
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
7.2 函数作用域(局部作用域)
在固定的代码片段才能被访问
7.3 全局变量和局部变量
变量的作用域范围可分为全局变量和局部变量。
-
全局变量:
在最外层声明的变量叫全局变量。
在函数体内部,没有使用var关键字声明的变量也是全局变量。(不推荐)
-
局部变量:
在函数体内部,使用var关键字声明的变量叫作局部变量。
7.4 作用域规则
-
函数允许访问函数外的数据。
-
整个代码结构中只有函数可以限定作用域。
-
作用域规则首先使用提升规则分析。
-
如果当前作用规则中有名字了, 就不考虑外面的名字。
注意点:
局部变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁。
<script>
// 全局作用域
var num1 = 10; // 全局变量
console.log(num1);
// 创建函数
function fun() {
console.log(num1);
// 局部作用域
var num2 = 20; // 局部变量
console.log(num2);
num3 = 30;
}
fun();
console.log(num3);
// 作用域链:在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做**作用域链**。
</script>
7.5 作用域链(重点)
-
只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
-
将这样的所有的作用域列出来,可以有一个结构:在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
-
作用域链:采取就近原则的方式来查找变量最终的值。
<script>
var num = 10;
function fun1() {
// var num = 20;
function fun2() {
// var num = 30;
console.log(num);
}
fun2();
}
fun1();
// 案例1
function f1() {
// var num = 123;
function f2() {
console.log(num);
}
f2();
}
f1();
var num = 456;
</script>
八. 预解析
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。
JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程。
预解析过程:
-
把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
-
把函数的声明提升到当前作用域的最前面,函数声明代表函数整体,所以函数提升后,函数名代表整个函数。
-
先提升var,再提升function。
-
预解析会把变量和函数的声明在代码执行之前执行完成。
8.1 变量预解析
预解析也叫做变量、函数提升。 变量提升(变量预解析): 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
8.2 函数预解析
函数提升: 函数的声明会被提升到当前作用域的最上面,函数声明代表函数整体,所以函数提升后,函数名代表整个函数。
特殊情况--函数表达式声明函数问题
fn();
var fn = function() {
console.log('想不到吧');
}
//结果:报错提示 "fn is not a function"
//解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用
练习代码详情:
<script>
// 1.变量的声明提升
console.log(a); // undefined
var a = 10;
// var a;
// console.log(a);
// a = 10;
fun();
// 函数的预解析,通过字面量形式创建的函数会被提升到当前作用域最上方,以保证函数可调用
function fun() {
console.log("让河南学子创造中国互联网未来");
}
console.log(fun2);
var fun2; // und
fun2();
// 匿名函数
var fun2 = function () {
console.log("匿名函数");
}
</script>
文章不等于全部,想掌握更熟练还需自己多多练习。