函数知识点
- callee&caller 在严格模式下都无法被使用
- callee
arguments.callee 指的是函数自己的引用
function test(){
console.log(arguments.callee)
}
test()
/* 打印出自己
ƒ test(){
console.log(arguments.callee)
}
*/
function test(){
console.log(arguments.callee);
function fun(){
console.log(arguments.callee);
}
fun()
}
test()
/*
f test(){
f fun(){}
fun()
}
------------------------------
f fun(){}
打印出来的都是自己
*/
在使用匿名函数递归的时候可以用得到
// 求10的阶乘
var num =(function (n){
if(n===1){
return 1
}
return n * arguments.callee(n-1)
}(10))
- caller
返回一个对函数的引用,该函数调用了当前函数
就是说在哪个环境里被调用
function fun(){
console.log(fun.caller)
}
function test(){
fun()
}
test()
/*
f test(){....}
*/
- 函数的作用域以及预编译
函数在执行之前都有一个预编译过程
预编译环节1 变量声明,2 函数声明 ,最后才开始执行
fun ()
function fun(){
console.log("函数执行")
}
// 函数执行
变量声明也会提前
funciton fun(a){
cosnole.log(a)
}
函数执行都会有作用域的产生
先声明变量形参和变量声明
形参实参统一
函数声明的属性名变成GO属性名值为undefined
将函数声明赋值
// 最外层的作用域是GO也就是window,当有函数执行,函数会生成AO
fun (a)
function fun(a){
console.log(a)
}
var a = "声明提前,赋值在后"
var a // 变量声明优先被执行,函数体执行时这天已经被执行过
fun(a)
/*
undefined
"声明在前,赋值在后"
*/
- AO和GO
[[scope]]:每个js函数都是一个对象,对象中有些属性我们可以访问,有些不可以,这些属性仅供js引擎存取,[[scope]]就是一个,[[scope]]就是我们所有的作用域,里面储存了执行期上下文的集合
作用域链:[[scope]]中所储存的执行期上下文对象的集合,这个集合呈链式链接
GO指的是全局作用域 也就是window的作用域
AO 执行期上下文 指的是函数作用域
scope是个类数组,最先指向ao,最后指向go
当一个函数执行的时候会产生自己的scope,0指向AO,1指向系统GO
每有一个函数执行,都会在window的scope上生成一个AO ,以此类推,最后的是GO
当在函数里又有一个函数执行了,那么会在原来的AO的基础上,增加新AO
function a() {
function b(){
var num=100
}
b()
}
a()
/*
a 执行:a的AO scope[0] AO ,scope[1] GO
b 执行: a的AO scope[0] AO , scope[1] GO
b的AO scope[0] AO(b) ,scope[1] AO (a) , scope[2] GO
b的scope[1]==a的scope[0] 指向相同
*/
正是因为作用域的特性,内部函数可以使用并且修改外部函数的值,如果外部函数需要用到内部函数的值,那么需要 闭包
- 闭包
根据上面所述,通常外部函数拿不到内部函数的数据,因为访问不到内部函数的AO
只有把内部函数的数据返回出去,才可以拿得到,此时也就形成了闭包
换句话说,只要函数内部的值被外部使用,那么一定形成闭包
function a (){
var b=30
return b
}
var c = a()
console.log(c)
// 30
闭包可以嵌套
// 连续闭包
function a() {
function b(){
var num=100
return num
}
return b()
}
var num2= a()
// num2: 100
不仅仅是return 只要变量被外部使用,都能形成闭包
var b=0
function a (){
b = "外部变量接收"
}
a()
console.log(b) // 外部变量接收