講函數(shù)前,先了解Function和function的區(qū)別。
- function是關(guān)鍵字(if else var )function聲明一個(gè)函數(shù)
function f(){}
Function是全局對(duì)象new Function('x','y','return x+y',)或者Function('x','y','return x+y')
聲明函數(shù)有兩種方法1.關(guān)鍵字聲明 2.new Function聲明
1.具名函數(shù) function f(){ return undefined} 2.匿名函數(shù) var f f = function(){} 這兩個(gè)屬于第一種
3.new Function('x','y','return x+y ') 這個(gè)屬于第二種(除非無(wú)聊或者想用字符串拼湊的時(shí)候才有這種)
函數(shù)的五種聲明方式
function f(x,y){ return x+y }var f = function (x,y){ return x+y }var f = function x(x,y){ return x+y }var f = new Function('x','y','return x+y') // window.Function-
var f= (x,y) => { return x+y }//es6的箭頭函數(shù)
var f = (x,y) => x+y //return和花括號(hào)一起省略
var f = n => n*n //參數(shù)只有一個(gè)時(shí),參數(shù)的括號(hào)可以省略
name知識(shí)點(diǎn)
每個(gè)函數(shù)都有名字,但是比較雞肋,基本用不到
function f(){}
f.name // f
var f2 = function(){}
f2.name // f2
var f3 = function f4(){}
f3.name // f4
f4.name // f4 is not defined
f5 = new Function('x','y','return x+y ')
f5.name // anonymous
函數(shù)是可以反復(fù)調(diào)用的代碼塊 調(diào)用函數(shù)英文是call
call
var f = {}
f.params = ['x','y']
f.functionBody = 'console.log("fff")'
f.call = function (){
return window.eval(f.functionBody)
}
f.call() // fff

call其實(shí)就是函數(shù)的復(fù)雜寫(xiě)法
f(1,2) === f.call(undefined,1,2),實(shí)際參數(shù)從第二個(gè)開(kāi)始傳,undefined是this , 1,2是argumentscall的第一個(gè)參數(shù)可以用this得到,call后面的參數(shù)可以用arguments得到
f和的區(qū)別 f是函數(shù)體 f.call()指向這個(gè)對(duì)象的函數(shù)體

其中可以執(zhí)行代碼的對(duì)象就叫函數(shù)(我們寫(xiě)的代碼)
函數(shù)原型Function.prototype有三個(gè)重要的方法call apply bind,會(huì)重寫(xiě)toString方法覆蓋Object的toString方法
this
在普通模式下,如果this是undefined,瀏覽器會(huì)自動(dòng)把this變成window
f = function (){
console.log(this == = window)
}
f.call(undefined) // true
如果是嚴(yán)格模式,給undefined打印出的就是undefined,
f = function (){
'use strict'
console.log(this === window)
}
f.call(undefined) //false
arguments
argument是偽數(shù)組,因?yàn)樗脑玩溕蠜](méi)有Array.prototype,或者 proto沒(méi)有指向Array.prototype
下面判斷
f = function(){
arguments.push(4)
console.log(arguments)
}
f.call(undefined,1,2,3)
會(huì)報(bào)arguments.push is not a function的錯(cuò),所以是偽數(shù)組
很好判斷是不是偽數(shù)組,給push方法
call stack 調(diào)用棧
Stack Overflow 和中國(guó)的segment fault 這兩個(gè)網(wǎng)站的由來(lái)就是從棧溢出而來(lái)的
function sum(n){
if(n==1){
return 1
}else{
return n + sum.call(undefined, n-1)
}
}
sum.call(undefined,9650) //46566075
再大就棧溢出Maximum call stack size exceeded,所有棧的調(diào)用最多在9650左右,再多就棧溢出了

作用域
在使用變量的時(shí)候 ,怎么去找它的聲明 ,就找這個(gè)作用域里面的聲明,找不到找外面作用域的聲明,如果還找不到 。再往外面找,就近原則
聲明提升:變量提升,函數(shù)的聲明也提升,先提升在看代碼
f1里的console.log是什么
var a = 1
function f1(){
f2.call()
console.log(a) //undefined
var a = 2
function f2(){
var a = 3
console.log(a)
}
}
f1.call()
console.log(a)
//3
//undefined
//1
先變量提升改寫(xiě)代碼
var a = 1
function f1(){
var a
function f2(){
var a
a = 3
console.log(a) // a定義再賦值在console.log前面,所以是3 }
f2.call()
console.log(a) // a先定義,賦值在console.log下面,所以是undefined
a = 2
}
f1.call()
console.log(a)
例2
f4打印的是什么
var a = 1
function f1(){
console.log(a)
var a = 2
f4.call()
}
function f4(){
console.log(a) //1, f4的a 一定是f4的作用域或者它的父作用域
}
f1.call()
console.log(a)
f1的a只在f1函數(shù)里有效,而f4的a 一定是f4的作用域或者它的父作用域 ,不用和上面的變量提升搞混
例3
????里的內(nèi)容有沒(méi)有可能是的a輸出的不是1
var a = 1
function f4(){
console.log(a)
}
??????? //a = 2 不是立刻執(zhí)行就可能是2
f4.call()
作用域說(shuō)的是a是那個(gè)a,但并沒(méi)有說(shuō)a是哪個(gè)a的值,如果????里設(shè)置了延時(shí)代碼,那么a就不一定是1了
閉包
var a = 1
function f4(){
console.log(a)
}
這就是閉包 如果一個(gè)函數(shù),使用了它范圍外的變量,那么(這個(gè)函數(shù)+這個(gè)變量)就叫做閉包