2021-08-06函数预解析+函数类型+函数高级

  • 闭包的缺点和解决

    闭包会使函数中的变量都放在内存中,对内存消耗很大,会造成内存泄漏或内存溢出,所以在退出函数之前要手动释放闭包,释放闭包后就相当于删除了函数中的变量,释放闭包后再调用函数,就没有变量可引用了,就会报错

    function f1(){
    	var a = 996;
    	function f2(){
            a++;
    		console.log(a);
    	}
        return f2;
    }
    var result = f1();
    result();
    result();
    result = null;//释放闭包,局部变量自动销毁
    result();//局部变量销毁了,无效了报错了
    

5.Javascript预解析

  1. 当浏览器解析到script标签的时候,会立即扫描script标签中的所有代码,然后进行预解析
  2. 预解析包含变量提升和函数提升
  3. 预解析,解析的是带var的变量和由function定义的函数
1.变量提升
  1. 带var的变量提升

    console.log(a);
    var a = 1;
    console.log(a);
    
    //预解析结果
    var a;				//声明,未赋值
    console.log(a);		//所以 返回undefined
    a = 1;				//变量声明提升了,赋值了
    console.log(a);		//返回1
    
  2. 不带var的变量不会提升

    console.log(a);
    var a = 1;
    console.log(a);
    
2.函数提升
f1()
function f1(){
	console.log('奥利给');
}
// 解析结果
function f1(){
	console.log('奥利给');
}
f1()
3.特点
  • 带var的变量和的带function的函数都会被预解析
  • 函数体内的代码会发生预解析
  • 函数的预解析的优先级高于变量预解析的优先级
  • 函数名一样会覆盖
  • 函数名和变量名一样会忽略变量
  • 如果是表达式定义的函数,只会提升变量不会提升函数体
  • 解析三步走:第一步先解析函数,(函数内有代码则左局部解析),第二步:解析变量,第三步:按顺序执行
4.练习
// 不会预解析,变量前面没有var
alert(a);
a = 0;
alert(a);
var a = 0;
alert(a);
// 提升结果
var a;
alert(a);
a  = 0;
alert(a);
// 输出undefined和0 
console.log(a);
var a = '我是变量';
function a() {
	console.log('我是函数')
}
console.log(a);
// 提升结果
// 函数提升的优先级要高于变量提升的优先级
// 变量重名会忽略 >>> 函数名和变量名相同时,忽略变量名
function a(){
	console.log('我是函数')
}
var a;	//(此时的a是函数名a,因为跟变量名重复了,忽略了变量名)
console.log(a);		//输出函数体(因为a没有加括号,就是函数体)
a = '我是变量';
console.log(a);		//输出我是变量 
console.log(a);
a++;
console.log(a);
var a = '我是变量';
function a() {
	console.log('我是函数')
}
console.log(a)
// 提升结果
// 优先提升函数
function a(){
	console.log('我是函数')
}
var a;	//(此时的a是函数名a,同名忽略变量名)
console.log(a);		//输出函数体
a++;	
console.log(a);		//输出NaN(函数体++输出肯定是NaN啊)
a = '我是变量';
console.log(a);		//输出我是变量
console.log(a);
var a = 0;
console.log(a);
function fn() {
	console.log(a);
	var a = 1;
	console.log(a);
}
fn()
console.log(a); 
// 解析结果
// 函数内部也要做局部变量提升
 function fn(){
	var a;			//函数内部变量提升
	console.log(a);		//输出undefined
	a = 1;
	console.log(a);		//输出1
}
var a;
console.log(a);		//输出undefined
a = 0;	
console.log(a);		//输出0
fn()				//输出函数内的undefined和1
console.log(a);		//上一级的函数执行完了就自动销毁局部变量了,所以a的值要继续向上找(作用域链),输出0 
	console.log(a);
	var a = 0;
	console.log(a);
	function fn() {
		console.log(a);
		a = 1;
		console.log(a);
	}
	fn()
	console.log(a); 
	// 解析结果
	function fn() {
		// 函数内部没有带var的变量,不做预解析
		console.log(a);		//输出0(向上一级找变量,函数内没有变量提升)
		a = 1;
		console.log(a);		//输出1
	}
	var a;
	console.log(a);			//输出undefined
	a = 0;
	console.log(a);			//输出0
	fn()					//输出函数内的undefined和1
	console.log(a);			//向上一级找变量(作用域链),因为函数内的是全局变量,执行完后不自动销毁,找到a = 1就引用,输出1
// 函数名重复会覆盖
f1();
	function f1(){
		console.log(11111);
	}
	function f1(){
		console.log(22222);
	} 		
// 函数名和变量名重复
	var a = 1;
	function a(){
	}
	console.log(a);
	//解析结果
	// 并没有忽略变量,因为var a = 1在console.log前面
	function a(){
		
	}
	var a;
	a = 1;
	console.log(a);	


	console.log(a);
	var a = 1;
	function a(){
	}
	// 解析结果
	// 此时变量名和函数名重复,先提升函数,再提升变量,输出a,就忽略了a = 1;
	function a(){
			
	}
	var a;
	console.log(a);
	a = 1;

6.Javascript函数类型

1.具名函数

有名字的函数

function f1(){
				
	}
2.匿名函数

没有名字的函数

var f1 = function (){
				
	}
3.立即执行函数IIFE
1.书写方法

第一步,创建一个匿名函数

function(){
	console.log('谁在让我东张西望');
}

第二步,报错,说必须有一个函数名,解决方法给函数加一个圆括号

(function(){
	console.log('谁在让我东张西望');
})

第三步,然后在函数后面加一个空的圆括号

(function(){
	console.log('谁在让我东张西望');
})()
  • 其他IIFE的格式

前面加叹号,后面加圆括号

!function(){
	console.log('谁是你的新郎')
}();

前面加波浪号号,后面加圆括号

~function(){
	console.log('谁是你的新娘');
}();

前面加加号,后面加圆括号

+function(){
	console.log('哎嘿嘿');
}();

前面加减号,后面加圆括号

-function(){
	console.log('你快快来到我的身旁');
}();
2.IIFE的参数
// 参数的传递
+function(name){
	console.log('大家好我是' + name);
}('陈冠希'); //这是实参
3.特点

1.匿名函数自调用是在定义的时候同时执行函数

2.匿名函数只能执行一次

​ 如果一个函数可以多次执行,那这个函数必须是具名函数

​ 如果函数没有名字要想执行必须是自调用,但是只能执行一次

3.匿名函数自调用,函数整体不会发生预解析,函数内部还是要预解析的

4.作用

1.防止外部命名空间污染

  • 一个页面中会有很多重复的变量的名字,那么命名就冲突了,所以用匿名函数 自调用来隔离不同业务得同名变量

2.隐藏内部接口,避免暴露代码

  • 很多js文件只有引入路径,引入之后就可以直接用,看不到代码细节就保证了文件的安全

3.对项目初始化,只执行一次

  • 因为立即执行函数只执行一次,对于项目加载问价是很友好的,省略了很多加载时间

7.Javascript函数参数的高级

1.获取参数的个数
  • 获取函数实参的个数 >>> arguments对象只能在函数内可见,所以arguments.length只能在函数体内使用

  • 函数对象的length是获取函数形参的个数 >>> 该属性为只读属性,在函数体内外都可以使用

    // 函数对象的length是获取函数形参的个数
    console.log(f1.length);
    function f1(a,b,c,d,e,f,g){
    	// 获取函数实参的个数
    	console.log(arguments.length);
    }
    f1(1,2,3,4,5,6)
    
2.使用arguments对象
  • argumentss 是一个实参的数组

  • 这个数组是一个伪数组(不能调用数组的方法,但是可以通过下标来访问数组的元素)

  • // 通过修改length属性值,可以改变函数的实参个数。

    function f1(a,b,c,d){
    	var aList = arguments;
    	console.log(arguments[1]);
    	arguments.length = 100;
    	// 打印这数组,后面加了97个空
    	console.log(arguments);
    	// 打印数组的长度(100)
    	console.log(arguments.length);
    }
    f1(1,2,3);
    

案例1:使用arguments计算你传递过来的2个参数的和

function f1(){
	return arguments[0] + arguments[1];
}
console.log(f1(1,3));

案例2:输入一组数字,求平均值的函数
​ 无论输入的是多少个数字 那么我就要平均值。

function f2(){
	var sum = 0;
	var len = arguments.length;
	for(i = 0; i < len; i++){
		sum += arguments[i]
	}
	return sum / len;
}
console.log(f2(1,2,3,4,5,6,7,8,9,10));

案例3:如果传递过来的参数是2个话 那么就计算减法 如果传递过来的参数是3个参数 那么就计算加法 并且返回

function f3(){
	var len = arguments.length;
	if(len == 2){
		return arguments[0] - arguments[1];
	}else if(len == 3){
		return arguments[0] + arguments[1] + arguments[2];
		/* var sum = 0;
			for(i = 0; i < len; i++){
				sum += arguments[i];
			}
			return sum; */
		}
}
console.log(f3(2,3,6));

案例4:书写一个函数 计算 三个值的和

function f4(a,b,c){
	return a + b + c;
}
console.log(f4(11,22,33));

但是这里如果只传了两个实参,c就是undefined了,undefined转Number就NaN了,因为c没有参数,在求和的时候直接成NaN了
解决办法,给c设一个默认值=0,传两个的时候就是和0相加了

function f5(a,b,c = 0){
	console.log(typeof c);
	return a + b + c;
}
console.log(f5(11,22));

问题又出现了,当我不确定要不要传第三个参数的时候,c的默认值要不要,成了个问题
解决办法,在传了参数的时候,让c用传了了参数,当没传参的时候,让c默认为0

function f6(a,b,c){
	typeof c == "undefined" ? c = 0 : c
	// (c的数据类型)(如果等于)("undefined")	(那么c赋值为0)(否则)(c还是c)
	return a + b + c;
}
console.log(f6(11,22,33));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值