深入了解函数
函数声明
匿名函数
var fn = function(){
    return 1
}
var fn2 = fn
fn.name //fn
fn2.name //fn
注意,这里的变量fn是保存匿名函数的内存地址,而不是函数本身.
具名函数
function fn3(){
    return 3
}
var fn5 = function fn4(){
    return 4
}
console.log(fn3) //3
console.log(fn4) //undefined
console.log(fn5) //4
注意,具名函数假如不赋值给变量,那么作用域是全局,如果赋值给变量,那么作用域在函数本身.
箭头函数
var fn6 = i => i+1
fn6(1) //2
var fn7 = i =>{
    i+1;
    ...doSometing
}
fn7(1) //undefiend
假如箭头函数只有一个变量,那么括号可不写.
箭头函数的函数体只有一句话,那么return的值就是求的值.
箭头函数的this是上下文的this.
词法作用域(静态作用域)
var globall1 = 1
function fn1(param1){
    var local1 = 'local1'
    var local2 = 'local2'
    function fn2(param2){
        var local2 = 'inner local2'
        console.log(local1)
        console.log(local2)
    }
    function fn3(){
        var local2 = 'fn3 local2'
        fn2(local2)
    }
}
JS引擎会先进行词法解析,并形成词法树
下面是上面函数的词法树
    window
      |
  ----------
 |         |
 global1  fn1
 ---
  |
 ------------------------------------
  |       |          |       |       |
  param1 local1    local2   fn2     fn3
                             |       |
                            ---     ---
                             |       |
                           local2  local2 
- 当函数寻找变量的时候,会先从函数内部寻找变量
 假如没有该变量,则会从词法树往上找.
fn2里的console.log(local1)是上层fn1的local2,所以输出’local1’,
- fn2里的console.log(local2)是自己的local2,所以输出’inner local2’,
 - fn3里的local2是自己的local2,为’fn3 local2’.
 - fn3里的fn2(local2),local2是他本身local2,即fn2(‘fn3 local2’),最终结果同2.
 
Call stack
Stack(栈),先进后出.
普通调用
function a(){ console.log('a') return 'a' } function a(){ console.log('b') return 'b' } function a(){ console.log('c') return 'c' } a() b() c()运行函数
进行了以下事情
先进行词法解析,函数提升 ->a() //进入a,记下a的位置 ->console.log('a') //进入,记下该位置 <-console.log('a') //退出,回到原位置 ->return 'a' //进入 <-return 'a' //退出 <-a() //退出a,回到原来a的位置 ->b()//进入b,记下a的位置 ... <-c() `嵌套调用
function a(){
    console.log('a1')
    b()
    console.log('a2')
    return 'a'
}
function a(){
    console.log('b1')
    c()
    console.log('b2')
    return 'b'
}
function a(){
    console.log('c')
    return 'c'
}
运行
->a()
    ->console.log('a1')
    <-console.log('a1')
    ->b()
        ->console.log('b1')
        <-console.log('b1')
        ->c()
            ->console.log('c')
            <-console.log('c')
            ->return 'c'
            <-return 'c'
        <-c()
        ->console.log('b2')
        <-console.log('b2')
        ->return 'b'
        <-return 'b'
    <-b()
    ->console.log('a2')
    <-console.log('a2')
    ->return 'a'
    <-return 'a'
<-a()  
- 递归
 
function fab(n){
    console.log('strat calc fab' +n)
    if(n>=3){
        return fab(n-1) + fab(n-2)
    }else{
        return 1
    }
}
fab(5)
运行
strat calc fab 5
    5>3
    求fab(4)
        strat calc fab 4
        fab(3)+fab(2)
        4>3
        求fab(3)
            strat calc fab 3
            fab(2)+fab(1)
            3=3
            求fab(2)
                strat calc fab 2
                fab(2)+fab(1)
                3-1<3
                fab(2)=1
            求fab(1)
                strat calc fab 1
                1<3
                fab(1)=1
        得fab(3) = 1 + 1 = 2
        求fab(2)
            strat calc fab 2
            2<3
            fab(2)=1
        得fab(2) = 1
    得fab(4) = 2 + 1 = 3
    求fab(3)
        strat calc fab3
        fab(2)+fb(1)
            求fab(2)
            strat calc fab 2
            2<3
            fab(2)=1
            求fab(1)
             strat calc fab1
             fab(1)=1
    得fab(3) = 1 + 1 = 2
得fab(5) = 3 + 2 = 5   
this&arguments
this是隐藏的第一参数,且必须是对象
function f(){
    console.log(this)
    console.log(arguments)
}
f.call() //window (chrome是Window) ,[]
f.call({name:'a'}) //{name:'a'} ,[]
f.call({name:'a'},1) //{name:'a'},[1]
f.call({name:'a'},1,2) //{name:'a',[1,2]}
this是函数与对象的羁绊
函数调用的时候,this只看调用时前面的对象是什么,不看定义时的对象,是独立存在的!
this是调用时第一个隐藏参数.
如
var name = window
var person = {
    name:'roxas',
    sayHi:function(){
        console.log('I am' + this.name)
    }
}
person.sayHi() //I am roxas
//相当于perosn.sayHi.call(peroson)
var fn = person.sayHi
fn() //I am window
//相当于peroson.sayHi.call()
call/apply
fn.call(_this,p1,p2)是函数的正常调用方式.
当你不确定参数的个数时,就使用apply.
fn.apply(_this,params)
假设数组的长度不确定
var arr = [1,2,3,4,5,....]
function sum(){
    var n = 0;
    for(var i = 0;i< arguments.length;i++){
        n+= arguments[i]
    }
}
sum.call(undefined,arr[0],arr[1],....)
这时候无法用call,所以要用apply
sum.apply(undefined,arr)
bind
 call和appy都是直接调用函数,而bind则是返回一个新函数.
 但是并没有调用,这个函数调用时会call原来的函数,call的参数是bind传入的参数.
 也就是说,bind的函数的this是bind参入的第一个参数.
柯里化
高阶函数
回调
构造函数
箭头函数
与普通函数区别
- this是上下文的this
 - 不能指定this,call()无效
 
function fn(){
    this
    function fn2(){
        this //通过调用确定
    }
    var fn3 = ()=>{
        this //一定是函数内的this
    }
}
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 Roxas Deng的博客!