## 函数 函数是一段可以反复调用的代码块,函数区别于代码块最显著的特征就是可以有输入参数,根据不同的输入参数,可以返回不同的结果。 ### 1. 函数的声明 函数的声明有三种方式,常用的前两种。 1)function命令 function 命令后面是函数名,函数名后面是一对圆括号,里面是传入的参数。 ~~~javascript // 函数的声明或者叫函数的定义 function p(str) { console.log(str); } // 调用函数 p("abc"); ~~~ 2)函数表达式 用变量赋值的写法去声明一个函数。 ~~~javascript var print = function(str) { console.log(str); }; print("xxxx"); ~~~ 在上述代码中,在赋值预算符=右边的函数,是没有名字的,我们把这种类型的函数也称之为匿名函数,匿名函数有时我们也叫做函数表达式。 > 在通过函数表达式定义一个函数的时候,在语句后面要加上“;”。 3)Function构造函数 很少用这种方式定义:语义不明确,代码的可读性差。 ### 2.第一等公民 JavaScript将函数看做一个值,与其他类型的值(数值、字符串、布尔值等)地位相同。凡是可以使用值的地方都可以使用函数,可以把函数赋值给变量或对象的属性。也可以当做参数传递给其他函数,或者作为函数的结果返回。函数只是一个可执行的值,此外并无特殊之处。 ~~~javascript function add(x, y) { return x + y; } var add = function(x, y) { return x + y; }; var oper = add; print(oper(2,2)); // 4 function a(op) { return op; } print(a(add)(1,2)); // 3 var o2 = { name : "Tom", add : add }; print(o2.add(3,3)); // 6 ~~~ ### 3.函数名的提升 Javascript引擎将函数名视同变量名。所以采用function命令声明函数时,整个函数就会像变量声明一样,提升到代码头部。 ### 4.函数的属性和方法 * name属性:输入函数的名字 * length属性:输入函数参数的个数 * toString()方法:返回函数的源码 ~~~javascript print("add.name=" + add.name); print("add.length=" + add.length); print("add.toString()" + add.toString()); ~~~ ### 5.函数的作用域 作用域(scope)称之为变量存在的范围。 在Javascript中只有两种作用域,一种是全局作用域:即变量在整个程序中一直存在,所有的地方都可以读取。 另一种叫函数作用域:即变量只在函数内部存在。 ~~~javascript var i = 0; // 这里的i是全局变量,可以在页面的任何位置引用 function t() { var j = 0; console.log("j=" + j); console.log("i=" + i); } // console.log("out j = " + j); // 此处代码会报错,j is not defined t(); ~~~ 函数体内的变量提升 ~~~javascript function t() { console.log("j=" + j); // j=undefined var j = 0; console.log("i=" + i); } ~~~ ### 6.参数 函数在运行的过程中,有时需要提供外部数据,不同的外部数据可能会得到不同的结果,我们把这种外部数据叫做参数。需要特别注意的时,在Javascript语言中是不需要指定参数的数据类型的。 ~~~javascript function p(str) { console.log(str); } ~~~ **参数的省略** 在javascript中,函数的参数不是必须的,Javascript可以省略。 ~~~javascript function p(str, flag) { console.log("str=" + str); console.log("flag=" + flag); } console.log("======================="); p("hello"); console.log("======================="); p("hello",true); console.log("======================="); p(); console.log("======================="); ~~~ > 被省略的参数的值变成“undefined”; > 但是,没有办法只传递靠后的参数,省略靠前的参数,可以通过显示的传入undefined。 关于默认值的实现 ~~~javascript function f(a) { a = a || 1; console.log("a:" + a); } f(); // 1 ~~~ ### 7.传递方式 函数参数如果是原始数据类型(数值、字符串、布尔型),都是传值传递,如果在函数体内修改了变量的值,不会影响到函数体外。 ~~~javascript function f(o) { o = 5; console.log("o=" + o); } var i = "abc"; f(i); console.log("i=" + i); // abc ~~~ 但是,如果函数的参数是复合数据类型的值(数组、对象、函数等),传递方式是引用传递。也就是说,在函数内部修改了原对象的值,会影响到原来的值。 ~~~javascript function fo(oj) { oj.name = "Jack"; console.log("oj.name=" + oj.name); } var obj = { name : "Tom", age :20 }; fo(obj); console.log("obj.name=" + obj.name); // Jack ~~~