优快云话题挑战赛第1期
活动详情地址:优快云
参赛话题:前端学习记录
话题描述:记录前端学习过程中的某个知识点、解决方案等等
问题
在实际的开发过程中,我们阅读别人的代码时,我们常常会被函数的封装和函数之间的调用关系而烦劳,这对于开发者来说是件很头疼的事情,更可怕的是这类问题经常出现在一些基础的考试题上,看看下面这段代码吧:
//1、
var nAdd;
function out(){
var n = 999;
nAdd = function(){
n ++; //++在后,先执行后自增
// 如果是上一行的代码是console.log(n++),则输出999
console.log(n)//1000 此时n已经自增为1000
}
return function(){
console.log(n);
}
}
var getN = out();
getN();//999 因为nAdd尚未执行
nAdd();//1000
getN();//1000 nAdd执行后,n为1000
//2、
function test(){
var arr = [];
for(var i=0;i<3;i++){
// 将下标i作为形参传递给立即执行函数function,j作为实参并将其作为数组arr的下标
//arr数组中储存的都是匿名函数function,所以输出的j是下标
(function(j){
arr[j] = function(){
console.log(j)
}
}(i))
}
return arr;
}
var myArr = test();
myArr[0]();//0
myArr[1]();//1
myArr[2]();//2
//3、
function fun(){
var i=1;
return function(){console.log(i++)}//i先执行后自增
}
var getFun = fun();
getFun();//1
getFun();//2
var i=2;
getFun();//3 闭包的特点之一,即使外界有重名的变量,也不影响闭包内调用的变量
getFun();//4
//4、
function fn(){
var a = 1;
function b(){
a++;
console.log(a)
}
function c(){
a--;
console.log(a)
}
//此时函数b和函数c尚未执行,所以不会对a造成影响
a += 10;
//将函数b和c存储到一个数组中并返回给函数fn
return [b,c];
}
var arr = fn();
//执行函数b
arr[0]();//2
//执行函数c
arr[1]();//1
是不是很复杂,但是这种复杂的逻辑经常出现在考试题上,根本毫无道理可言,小编不推荐大家去做这类简单练习题,举个例子:
在一个项目中,张三写了三个函数A,B,C,李四写了两个函数D,E,他们两人分别独立的开发,一般情况下不会出现同名的函数,由于李四项目集成的时候,他要调用张三写的函数,于是李四很荣幸的成为了项目的leader,但是张三写的函数需要访问李四写的函数中的变量,这个时候,如果是李四一个人写的话,李四可以使用闭包的方式对功能进行封装,但是两个人独立开发,而且两个人的模块可以分开单独使用,这个时候李四可以使用call函数的方式调用张三写的函数。
那么什么是call函数和闭包呢?
概念
闭包:如果A函数中嵌套了B函数,那么A和B构成一个闭包,A称为外部函数,B称为内部函数或者闭包函数
call函数:call函数是js反射机制提供的调用一个函数的一种方式用到的函数
这里把call函数和闭包放在一起理解,实属瞎扯,但是我们在实现函数解耦和重构优质代码的时候会涉及这部分内容的使用。
实践
在日程表和日历小应用的开发过程中,张三和李四都要使用Calendar函数库,但是Calendar函数库由张三提供,李四的函数中存储了一个开始日期,表示这个日期是计算某个日程所在日期的周数的基准,意思就是这个日期是第1周的某一天,以后的日期要按这个开始日期计算,而张三虽然有相似的功能,但是它默认的是该年的第一天,以后日期的周数按这个年的第一天为基准开始计算,因此,李四找到张三,他要调用张三的getDateInfoAfterAnotherDate函数,而张三写的函数是getDateInfoAfterFirstDayOfYear,同时getDateInfoAfterFirstDayOfYear函数调用了getDateInfo函数,下面附上简化代码:
张三的代码
function getDateInfoAfterFirstDayOfYear(year,month,date){
var dateinfo = getDateInfo(year,month,date);
//这里省略计算周数的逻辑
return {
"week":周数;
“day”:dateinfo.day;
}
}
function getDateInfo(year,month,date) {
//此处省略逻辑
return {
"days":距1970年1月1日的天数;
"day":星期数;
}
}
李四要求张三重构getDateInfoAfterFirstDayOfYear为getDateInfoAfterAnotherDate函数
张三的代码
function getDateInfoAfterAnotherDate(year,month,date){
var dateinfo1 = getDateInfo(year,month,date);
var dateinfo2 = getDateInfo(year,1,1);
if(this.year&&this.month&&this.date) {
dateinfo2 = getDateInfo(this.year,this.month,this.date);
}
//这里省略计算周数的逻辑
return {
"week":周数;
“day”:dateinfo1.day;
}
}
李四的调用
getDateInfoAfterAnotherDate.call({
"year":year,
"month":month,
"date":date
},firstdayYear,firstdayMonth,firstdayDate);
总结
Ⅰ:内部函数可以访问外部函数的局部变量以及外部函数以外的全局变量
Ⅱ:使用call函数调用一个函数时,该函数可以访问调用者的成员变量
Ⅲ:使用闭包时一定要注意不要污染全局变量
Ⅳ:使用call函数调用的函数可以被其他多个函数调用
Ⅴ:当函数库中出现多级闭包时,可以考虑使用call函数来解耦
Ⅵ:内部函数只能够被与该内部函数构成闭包的外部函数调用
优快云话题挑战赛第1期
活动详情地址:优快云