函数和作用域

JavaScript函数是指一个特定代码块,可能包含多条语句,可以通过名字来供其它语句调用以执行函数包含的代码语句。

比如我们有一个特定的功能需要三条语句实现

statement1;
statement2;
statement3;

那么每次想实现这个功能的时候就需要写这三句话,很麻烦,我们可以把这三条语句打包为一个函数

function doSomething(){
    statement1;
    statement2;
    statement3;
}

这样每次想实现功能的时候我们就调用一下函数就可以了,调用函数通过函数名称()的形式调用

doSomething();

声明函数

函数声明

function printName(){
    console.log('饥人谷')
}

printName()

函数表达式

var printName = function(){
    console.log('饥人谷')
}

printName()

参数

function printName(name){
    console.log(name)
}

printName('hunger')
printName('valley)

函数在定义的时候可以写多个参数

function printPersonInfo(name, age, sex){
    console.log(name)
    console.log(age)
    console.log(sex)
}

arguments

在函数内部,你可以使用arguments对象获取到该函数的所有传入参数

function printPersonInfo(name, age, sex){
    console.log(name)
    console.log(age)
    console.log(sex)
    console.log(arguments)
console.log(arguments[0])
console.log(arguments.length)
console.log(arguments[1] === age)
}

printPersonInfo('饥人谷', 3, 'male')

重载

重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载

在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,这是不是意味着JavaScript不能通过重载功能实现一个函数,参数不同功能不同呢?

在JavaScript中,函数调用没必要把所有参数都传入,只要你函数体内做好处理就行,但前提是传的参数永远被当做前几个

function printPeopleInfo(name, age, sex){
    if(name){
        console.log(name);
    }

    if(age){
        console.log(age);
    }

    if(sex){
        console.log(sex);
    }
}


printPeopleInfo('hunger', 3);
printPeopleInfo('hunger', 3, 'male');

返回值

有时候我们希望在函数执行后给我们一个反馈,就像表达式一样,给我们个结果,我们可以通过return来实现

function fn(a, b){
    a++;
    b++;
    return a + b;
}

var result = fn(2, 3);
console.log(result);

这样我们就能拿到函数希望给我的反馈了,调用return后,函数立即中断并返回结果,即使后面还有语句也不再执行

其实我们不写return语句,函数也会默认给我们返回undefined

递归

简单来说就是自己调用自己,递归需要设置结束条件

function factorial(n){
    if(n === 1){
        return 1
    }
    return n * factorial(n-1)
}
factorial(3)  //6

声明提前

和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式那么规则和变量一样

console.log(fn) //undefined

var fn = function(){}

如果我们使用函数声明的方式,那么即使函数写在最后也可以在前面语句调用

fn() // "1"

function fn(){
    console.log('1')
}

命名冲突

当在同一个作用域内定义了名字相同的变量和方法的话,会根据前置顺序产生覆盖

    var fn = 3;
    function fn(){}

    console.log(fn); // 3

相当于

var fn
function fn(){}  //覆盖上面的

fn = 3  //重新赋值
console.log(fn)

当函数执行有命名冲突的时候,可以认为在还是内部一开始有隐藏的声明变量这个操作

function fn(fn){
  console.log(fn);

  var fn = 3;
  console.log(fn);
}


fn(10) //10 3

/*执行时等价于 function fn(){ var fn fn = 10 console.log(fn)

fn = 3
console.log(fn);

}

*/

作用域链

先看面试题

题目1

var a = 1
function fn1(){
  function fn2(){
    console.log(a)
  }
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() //输出多少

题目2

var a = 1
function fn1(){
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
function fn2(){
  console.log(a)
}
var fn = fn1()
fn() //输出多少

题目3

var a = 1
function fn1(){

  function fn3(){
    function fn2(){
      console.log(a)
    }
    var a

    fn2()
    a = 4
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn() //输出多少

解密

  1. 函数在执行的过程中,先从自己内部找变量
  2. 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
  3. 注意找的是变量的当前的状态

results matching ""

    No results matching ""