js函数的相关问题及补充
前言
除了在前面所学习的javascript函数的基础部分内容,js函数还有许多内容需要深入了解,以下内容是对博主练习时的遇到相应的问题及对js函数部分补充,如有错误,欢迎大家给予指正。
一、函数的解析问题
首先,观察以下案例
var a=1;
function fn(){
a=10;
}
fn();
console.log(a); // 10
var a=1;
function fn(a){
a=10;
}
fn(a);
console.log(a); // 1
var a=1;
function fn(){
var a=10;
}
fn();
console.log(a); // 1
第一个案例中,运行函数之前a已经赋值为1,运行函数时,在函数中寻找变量a,最终找到全局变量a,将a赋值为10,所以最终打印出的a的值为10,具体解析为
var a; //a的值为undefined
function fn(){
a=10; //寻找变量a,最终在函数外部找到全局变量a,对全局变量a进行赋值
}
a=1; //a被赋值为1
fn(); //运行函数,a被赋值为10
console.log(a); // 10
第二个案例中,参数传入时是进行了栈中值的复制,函数中运行的是a的复制a’,a的值没有发生改变,具体解析如下
var a; //a的值为undefined
function fn(a){ //进行a的复制a',值为undefined
a=10; //a'赋值为10
}
a=1; //a被赋值为1
fn(a); //将参数a传入函数,传入的a的值为1
console.log(a); // a的值为1
第三个案例中,函数内部定义了局部变量a,运行函数时,函数优先在内部寻找局部变量,找到局部变量后直接对局部变量赋值,不会再去外部寻找全局变量,在运行函数后,没有被标记的局部变量被内存回收,最终打印的是全局变量a的值,解析如下
var a; //定义全局变量a 值为undefined
function fn(){
var a; //定义局部变量a 值为undefined
a=10; //局部变量a被赋值为10
}
a=1; //全局变量a被赋值为1
fn(); //运行函数,局部变量被内存回收
console.log(a); // 打印的a为全局变量,值为1
总结:
- 函数在预解析具有函数提升的效果
- 函数使用变量作为参数时,是对变量进行复制后传入函数的,函数中参数的变化不会影响到原本的变量
- 函数进行内部变量赋值时优先从内部寻找局部变量,找到局部变量后直接对局部变量进行赋值,如果没有找到局部变量,就从函数外部寻找变量,直到找到全局变量为止
二、循环内部函数运行问题
案例:设置3个按钮,每按一个按钮显示当前按钮的索引弹窗。
var btns=document.getElementsByClassName("btns");
for (var i=0;i<btns.length;i++){
btns[i].onclick=function(){
alert(i+1);
}
}
按照上述代码运行的结果是,依次点击按钮,每次弹窗弹出的都是4,说明函数运行时,循环已经结束,函数内部 i 的值为循环结束时的3
改进方法一:
将循环每次运行的 i 值保存在对象的一个属性内
var btns=document.getElementsByClassName("btns");
for (var i=0;i<btns.length;i++){
btns[i].index=i;//将每次循环的i保存给每个按钮的属性中
btns[i].onclick=function(){
alert(this.index+1);//使用this指向当前的对象btns[i]
}
}
改进方法二:
定义一个必包函数,将其函数体本身作为返回值返回
var btns=document.getElementsByClassName("btns");
for (var i=0;i<btns.length;i++){
btns[i].onclick=function(num){
return function(){ //必包函数作为返回值返回
alert(num+1);
}
}(i);
}
必包函数优缺点:
优点:可以访问到函数内部的局部变量
缺点:必包函数的作用域被延长了,造成内存使用变大,并有可能造成内存泄漏
改进方法三:
使用let声明循环中变量,其基本效果同var一致
var btns=document.getElementsByClassName("btns");
for (let i=0;i<btns.length;i++){
btns[i].onclick=function(){
alert(i+1);
}
}