声明方式创建函数
例:
function fun(){
console.log(1)
}
fun()
function fun(){
console.log(2)
}
fun()
结果:2,2
分析:
函数名相当于变量。函数就是对象。
函数会声明提前。(我觉得是函数体提前。)
当第一个fun创建时,它引用的是函数体的地址。
第二个fun再出现时,变量不会被重复创建。
所以,内存里不会再创建fun变量,只会创建第二个函数,然后第一个函数体被释放,将fun变量的引用改为第二个函数的地址。
到最后执行完,内存里只有第二个函数。
如:
function fun(){
console.log(1)
}
fun()
function fun(){
console.log(2)
}
fun()
赋值方式创建函数。
var fun = function (){
console.log(1)
}
fun()
var fun = function (){
console.log(2)
}
fun()
结果:1,2
分析:只有函数名提前,函数体留在原地。
如:
var fun;
fun = function (){
console.log(1)
}
fun()
fun = function (){
console.log(2)
}
fun()
重载:
定义:相同函数名不同参数。根据调用时的参数来自动执行对应的函数。
作用:减少api数量,减轻调用者负担。
问题:js不支持重载,因为不能给同一个变量赋值多次!
解决:使用arguments(它叫类数组对象,像数组的对象,并不是数组,是对象。它可以遍历,有length属性,有下标)。
其他语言这样重载:
function pay(){
console.log("手机支付")
}
function pay(money){
console.log("现金支付")
}
function pay(card,pwd){
console.log("card支付")
}
pay(100)
pay()
js里这样:
function pay(){
if(arguments.length==0){
console.log("手机支付")
}
else if(arguments.length==1){
console.log("现金支付")
}else{
console.log("card支付")
}
}
pay()
结果:手机支付
函数的执行原理
创建前:
创建执行环境栈,用于记录将来调用的函数
用浏览器的主程序main函数并创建window对象,
main函数创建并引用window对象,
定义函数时:
创建函数对象
在window中添加函数名变量
函数名变量引用函数对象
函数执行时:
优先在函数作用域对象中查找变量使用,如果没有,去window中找。
函数调用后:
函数名出栈,
作用域对象释放
局部变量释放。
闭包:既重用变量,又保护变量不被污染的机制。
全局变量:优:可反复使用;缺:随处可用;
局部变量:优:仅函数内可用;缺:不可重用(因为函数在调用时会创建作用域对象,结束调用后会释放。);
闭包三部曲:
1:用外层函数包裹受保护的变量和内层函数;
2:外层函数return内层函数;
3:调用外层函数,得到内层函数对象,保存在变量中;
function outer(){
var i = 0
return function fun() {
i++
console.log(i)
}
}
//getnum得到一个函数对象。
var getnum = outer()
getnum()
getnum()
getnum()
结果:1,2,3
闭包形成的原因:
外层函数调用后,外层函数作用域对象无法释放,因为被内层函数引用着。
缺点:
比普通函数更占内存,因为比普通函数多出外层作用域对象。
闭包面试题:
1:
function fun() {
var n = 999
nAdd = function(){n++}//强制给未定义变量赋值,会在全局创建。
return function () {
console.log(n)
}
}
var get = fun()
//相当于var get = function(){
// console.log(n)
//}
get()//999
nAdd()//n此时为1000
get()//1000
此闭包向外抛出两个函数,公用一个变量。
2:
function fun(){
for(var i=0,arr=[];i<3;i++){
arr[i]=function () {
console.log(i)
}
}
return arr
}
var funs = fun()
funs[0]()
funs[1]()
funs[2]()
作用域连:
存放在所有变量,控制着变量的使用顺序。