JavaScript函数是指一个特定代码块,可能包含多条语句,可以通过名字来供其它语句调用以执行
函数包含的代码语句。
比如我们有一个特定的功能需要三条语句实现
statement1;
statement2;
statement3;
那么每次想实现这个功能的时候就需要写这三句话,很麻烦,我们可以把这三条语句打包为一个函数
function doSomething(){ 函数的命名一般用动词,两个单词用驼峰
statement1;
statement2;
statement3;
}
这样每次想实现功能的时候我们就调用一下函数就可以了,调用函数通过函数名称()的形式调用
doSomething();
声明函数
使用function关键字可以声明一个函数
//函数声明
function sayHello(){
console.log('hello')
}
//函数调用
sayHello()
声明不必放到调用的前面
函数表达式
var sayHello = function(){
console.log('hello');
}
sayHello()
声明必须放到调用的前面
参数
function sayHello(name){
console.log('hello ' + name)
}
sayHello('若愚')
sayHello('饥人谷)
多个参数
函数在定义的时候可以写多个参数
function printInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
}
printInfo('饥人谷', 2, 'boy')(其实并不能一一对应)
arguments
在函数内部,你可以使用arguments对象获取到该函数的所有传入参数
function printPersonInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
}
重载
其他语言重载范例:例如C语言中的
int sum(int num1, int num2){ 整数
return num1 + num2;
}
float sum(float num1, float num2){ 浮点数
return num1 + num2;
}
sum(1, 2);
sum(1.5, 2.4);
在 JS 中
没有重载! 同名函数会覆盖。 但可以在函数体针对不同的参数调用执行相应的逻辑
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
返回值
有时候我们希望在函数执行后得到一个结果供别人使用,可以通过return来实现
function sum(a, b){
a++;
b++;
return a + b;
}
var result = sum(2, 3);
conslole.log(result);
注意点
如果不写return语句,函数也会默认给我们返回undefined
注意点2
函数在执行过程中,只要遇到return就会立即结束退出函数体
function fn(a){
if(a < 0){
return;
}
//下面没用 else ,但效果一样
a++;
return a + a;
}
注意点3
函数的返回值和 console.log()是两个不同的东西,千万不要这样
function getAge(age){
return console.log(age);
}
console.log()作用是我们去调试代码,是把东西展示出来
声明前置
var 和 function 的声明前置
在一个作用域下,var 声明的变量和function 声明的函数会前置
console.log(a); //undefined
var a = 3;
console.log(a); //3
sayHello();
function sayHello(){
console.log('hello');
}
函数表达式
console.log(fn); //undefined
fn(); //报错
var fn = function(){}
函数表达式和 var 一个变量没什么区别
先有,再 用
函数内部的声明前置
function fn(){
console.log(a) //undefined
var a = 3
console.log(a)
}
fn()
当命名冲突时
先 前置,再 覆盖
var fn = 3;
function fn(){}
console.log(fn); // 3
function fn(){}
var fn = 3;
console.log(fn); // 3
参数重名
function fn(fn){
console.log(fn);
var fn = 3;
console.log(fn);
}
fn(10); //10 3
作用域
在 JS 中只有函数作用域,没有块作用域
function fn(){
var a =1;
if(a > 2){
var b = 3;
}
console.log(b);
}
fn(); // undefined
console.log(a); // "ReferenceError: a is not defined
var
声明一个已经存在的变量
function fn(){}
var fn
console.log(fn)
var a = 1
var a
var a
console.log(a)
var重复声明一个已经存在的变量,原变量值不变
不加var作用
function fn(){
a = 1;
}
fn();
console.log(a); // 1
可以看到不写var会声明一个全局的变量,这是我们在编程中应该要避免的,即使真的需要全局变量,也应该在最外层作用域使用var声明
更深入了解,参考下一节 作用域链
递归
自己调用自己
设定终止条件
优点: 算法简单
缺点: 效率低
求 n 的阶乘 n!
function factor(n){
if(n === 1) {
return 1
}
return n * factor(n-1)
}
factor(5)
求 1+2+...+n 的值
function sum(n){
if(n === 1) {
return 1
}
return n + sum(n-1)
}
sum(10)
立即执行函数表达式
(function(){ 用小括号,里面相当于 一个表达式
var a = 1;
})()
console.log(a); //undefined
作用: 隔离作用域
其他写法
(function fn1() {});
// 在数组初始化器内只能是表达式
[function fn2() {}];
// 逗号也只能操作表达式
1, function fn3() {};
作用域链
相关概念
执行上下文 executionContext
活动对象 AO
Scope 属性
执行顺序
范例1
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo() // 输出什么
}
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//声明 foo 时 得到下面
foo.[[scope]] = globalContext.AO
//声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
注意: 在当前的执行上下文内声明的函数,这个函数的[[scope]]就执行当前执行上下文的 AO
范例2
var x = 10;
bar() // 输出什么
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
globalContext = {
AO: {
x: 10
bar: function
},
Scope: null
}
//声明 bar 时 得到下面
bar.[[scope]] = globalContext.AO
注意: 在当前的执行上下文内声明的函数,这个函数的[[scope]]就执行当前执行上下文的 AO
当调用 bar() 时, 进入 bar 的执行上下文
barContext = {
AO: {
x: 30,
foo: function
},
Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的执行上下文里声明 foo 时 得到下面
foo.[[scope]] = barContext.AO
当调用 foo() 时,先从 bar 执行上下文中的 AO里找,找到后即调用
当调用 foo() 时,进入 foo 的执行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
所以 console.log(x)是 30
网友评论