深入了解函数
函数声明
匿名函数
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的博客!