一个函数是可以通过外部代码调用的一个“子程序”。函数中可以封装一系列语句,在需要时直接调用该函数。在定义函数时可以将值传递至函数,同时在调用函数时也可以返回一个值

创建与调用函数

1、使用 函数表达式 来创建一个函数

语法:

1
2
3
4
5
6
/* 创建函数 */
var 变量名 = function 函数名(形参1, 形参2...形参N){
//函数体
}
/* 调用函数 */
变量名(实参1, 实参2...实参N);

例:

1
2
3
4
5
6
7
/* 创建函数 */
var fun = function(a, b){
console.log(a+b)
}
console.log(fun.name) // fun
/* 调用函数 */
fun(4, 3)

2、使用 函数声明语句 来创建一个函数

语法:

1
2
3
4
5
6
/* 创建函数 */
function 函数名(形参1, 形参2...形参N){
//函数体
}
/* 调用函数 */
函数名(实参1, 实参2...实参N);

例:

1
2
3
4
5
6
7
8
/* 创建函数 */
function fun(arg){
console.log("你调用了" + arg + "函数");
return 0;
}
console.log(fun.name) // fun
/* 调用函数 */
fun("fun");

函数体

函数体为可执行的语句,只在调用函数时执行

形参实参

形参是一个未声明的局部变量,只在调用函数时被声明和赋值

而实参则是对应形参的实际值,可以是任何表达式

形参和实参是可选项可以为空

函数表达式

函数表达式会将该函数( Function类型对象 )作为值返回

在 JavaScript 中 函数表达式函数声明语句 都使用了 function关键字

Js 引擎在解析一条语句时,如果 function关键字前有相关运算符,则会将其作为函数表达式执行,如果没有则会将其作为函数声明语句执行

函数也是对象

在 JavaScript 中函数是一个”Function类型对象”,因此函数和对象的使用是一样的

不同的是函数除了可以添加属性外,还可以封装调用

return

return语句用来设置函数的返回值

语法:

1
return 表达式

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 例1 */
function sum(a, b, c){
return a+b+c
}
var result = sum(4,7,8); //result 的值为19
/* 例2 */
function fun() {
return {
sey: function () {
return 123;
}
}
}
var s = fun()
console.log(s.sey());

return 语句可以终止函数的执行( return 后的语句将不会执行 ),并返回一个指定的值给函数调用表达式( 默认返回 undefined )

函数的返回值可以是任何数据类型

方法(methods

在对象中如果一个属性值是一个函数,则该属性可以称为该对象的方法

语法:

1
2
3
4
5
6
7
8
9
10
11
/* 1.通过对象字面量添加方法 */
var 对象名 = {
属性名: 函数表达式
}

/* 2.通过访问对象表达式添加方法 */
var 对象名 = {} //初始化对象
对象名.属性名 = 函数表达式

/* 方法调用 */
对象名.属性名()

例:

1
2
3
4
5
6
7
8
9
10
11
/* 创建对象 */
var person = {
name: '小明',
birth: 2002,
age: function() {
var y = new Date().getFullYear(); //返回当前年份到变量y
return y - this.birth; //计算年龄并返回给方法调用表达式
}
}
/* 方法调用 */
person.age()

toString 方法

toString 方法是 Object 类型对象中的一个方法,任何对象都可以使用该方法。该方法用来将任意数据类型转换成字符串并返回

在使用 console.log() 输出对象到控制台时其输出值在不同运行环境( 如Chrome、FireFox、Node.js … )会略有不同,默认情况下输出一个对象的值,实际上是输出对象中 toString 方法的返回值

例:

1
2
3
4
5
6
7
8
9
10
var obj = {name: 'value'};
var arr = [1, 2, 3];
function fun(){}
console.log(obj.toString()); // [object Object]
console.log(arr.toString()); // 1,2,3
console.log(fun.toString()); // function fun(){}
Object.prototype.toString = function () {
return 'is Object';
}
alert(obj); // is Object

当两个对象做比较运算( 如 < > == 仅相等运算有意义 )时,则是比较对象的引用值( 内存地址 ),其它与对象有关的运算,默认情况下都是和对象的 toString 方法的返回值做运算

立即调用函数表达式(IIFE

立即调用函数表达式 是一个在定义时就会立即执行的函数,也称立即执行函数

它由 函数表达式+() 组成

语法:

1
2
3
(function([形参1, 形参2...形参N]){
//函数体
})([实参1, 实参2...实参N])

例:

1
2
3
4
var str='Hello'
(function(a) {
console.log(a);
})(str)

arguments 对象

arguments 是 Js 引擎在执行时自动向函数中添加的局部变量,其值是一个保存了函数实参的类数组对象(类似数组,但不是数组)

属性:

  • .length 获取实参的个数

  • .callee 返回当前执行的函数

  • [下标] 根据索引返回或修改实参的值

例:

1
2
3
4
5
6
7
8
9
10
/* 例1 */
function fun(){
console.log(arguments.length)
}
fun(1, 2, 3, 4) //执行结果:4
/* 例2 */
(function (){
arguments[0] = 0;
console.log(arguments[0], arguments[1], arguments[2]); //输出:0 2 3
})(1, 2, 3)

全局与局部变量

局部变量

通常函数内声明的变量都为局部变量,在调用函数时函数内声明的变量只在该函数内有效

例:

1
2
3
4
5
6
7
(function() {
var lv='我是局部变量';
/* 在函数内输出 */
console.log(lv); // 我是局部变量
})()
/* 在函数外输出 */
console.log(lv) //报错:test is not defined

全局变量

默认情况下,不再函数内声明的变量都为全局变量,如果变量不声明(var)直接赋值,则该变量直接为全局变量

全局变量在函数内或函数外都可以访问

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 例1 */
var gv = '我是全局变量';
(function(){
/* 在函数内输出 */
console.log(gv); // 我是全局变量
}())
/* 在函数外输出 */
console.log(gv) // 我是全局变量

/* 例2 */
(function(){
a = 666;
})()
console.log(a, window.a) // 666 666

window 对象

默认情况下,全局变量会作为在全局对象window的属性和方法存储

在 Js 中,访问一个全局变量,默认会从全局对象window中访问

例:

1
2
3
4
5
var a = 123;
function fun(){
return a;
}
console.log(window.a, window.fun()); //输出:123 123

作用域(scope

作用域是指一个变量作用的 范围

分类:

  • 全局作用域
  • 函数作用域

全局作用域中的变量即全局变量,函数作用域中的变量即局部变量

在浏览器中,全局作用域其作用范围是整个页面。函数作用域其作用范围只在函数内

作用域链

函数内可以嵌套多个函数,而作用域则是根据函数代码的层次进行分层,以使子作用域可以访问父级作用域中的变量,而不能从父作用域引用子级作用域中的变量

如果一个变量不 “在当前的作用域中”,则会从父级作用域中查找,即沿着链式的作用域链查找( 就近原则 )

例:

1
2
3
4
5
6
7
8
9
var num = 10;
function fun1() { //外层函数
var num = 20;
function fun2() { //内层函数
console.log(num); //输出结果: 20
}
fun2();
}
fun1();

作用域

当内层函数要访问一个变量时,会先在当前作用域中查找,若不存在,则向上一级作用域中查找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错 ReferenceError

变量提升(Hoisting

使用var关键字声明,会在当前作用域中提前声明

例:

1
2
3
4
5
console.log(a);	//输出:undefined
console.log(b); //报错:b is not defined
var a = 1; //这里发生变量提升
b = 2; //不使用var关键字声明,则不会发生变量提升
console.log(a, b); //输出:1 2

使用function关键字声明,会在当前作用域中提前声明

例:

1
2
3
4
5
6
7
8
9
fn();
fun(); //错误:fun is not a function
console.log(fun); //输出:undefined
function fn() { //function声明会将引用值一起提升
console.log("this is function");
}
var fun = function() { //这里只提升声明
console.log("this is function");
}

function声明要比var声明的优先级更高

例:

1
2
3
4
5
console.log(fn.toString()); // [Function: fn]
var fn = 100;
function fn() {
console.log("this is function");
}

PS:JavaScript 中 var 关键字只会提升声明,不会提升其初始化的值,而 function 声明则会将其引用值提升