前言:我个人感觉在ES6,BOM,DOM中最难的就是函数了,在习惯了C和Java的编译语言后对JS的函数的感觉,就是都是坑。。。。
- 函数的声明
<script>
function a(){
document.write("hello,world");
}
a();
</script>
- 谈到函数就不得不谈到它的预编译过程,大致的原则是变量声明提升,函数整体提升,但这个并不能解决所有问题。所以这里来讲一下它的预编译过程。
第一步:首先函数会进行语义分析,然后是预编译过程,函数会生成
AO
(active Object)。
第二步:是找到形参和变量声明,并且将它们赋值为undefined
;
第三步:找到形参对应的实参,并且将实参的值赋予形参;
第四步:找函数声明并且将函数体赋给函数声明;
举个例子:
<script>
function a(a){
var a="hello,world";
//function a(){
// document.write("how are you");
// }
console.log(a);
}
a("you are weclome");
</script>
按照前面所说的预编译过程就是
第一步:AO={
}
第二步:AO={
a:undefined
}
第三步:AO={
a:“you are welcome”
}
第四步: 因为没有函数声明就结束了;
到这里预编译过程就结束了。。。
最后结果是“hello,world”
如果去掉注释加上a函数的话第四步将会
第四步:AO={
a:function()
{
document.write(“how are you”);
}
最后的结果还是“hello,world”。。
注意:预编译过程是发生在函数执行的前一刻。。
- 闭包函数,闭包问题应该是前端无人不知无人不晓的问题。。。
闭包函数是因为在函数内部定义函数,并且将函数返回,这样的函数我们就把他叫做闭包函数。。。
谈到闭包函数就必须要知道作用域链。。。
<script>
function a(){
var a="hello,world";
function b(){
console.log(a);
}
return b;
}
var b=a();
b();
</script>
分析过程:
函数a有个隐藏的属性a.[[scope]]],在a函数定义时只有GO,在a函数执行后b函数的定义时b函数会攥着a函数的GO AO,这样的一条作用域链才形成了闭包函数。。。
注意:闭包函数会导致内存泄漏。。
- 立即执行函数
立即执行函数的存在帮助我们解决一些问题比如
for(var i=0;i<oLi.length;i++)
{
oLi[i].onclick=function(){
console.log(i);
}
}
分析:
你会发现输出的都是
oLi.length
,这是因为var是函数作用域变量,他会将之前i
的值覆盖掉,如果使用立即执行函数就不会出现这个问题,代码如下。。
for(var i=0;i<oLi.length;i++)
{
(function(j){
oLi[j].onclick=function(){
console.log(j);
}
}(i))
}