javascript奇怪的知识点

javascript奇怪的知识点

闭包与高阶函数

闭包与高阶函数的特性属于函数式编程语言,虽然javascript是一门完整的面向对象的编程语言,但这完全不会影响他函数式的特点。
本次奇怪知识点就走进js的闭包与高阶函数
闭包的形成与变量的作用域密切相关,什么是作用域呢?其实就是指的变量的有效范围,当在函数中声明一个变量时,如果没有用到var,那么这个变量就会变成全局作用域,当我们在函数内部声明一个变量,在函数外面时访问不到的。

function  foo(){
   b; // b被挂载到了window下面
   let a = 1;
   alert(a) // 1
}
alert(a)

在这里插入图片描述
在外面访问,a是未声明的状态。

变量的生存周期

对于全局变量来说,就像上面的b,他是一直存在的,除非页面销毁,而对于局部变量比如:

function foo (){
let a = 1
}
foo() // 当foo调用结束,a将随函数一起销毁

但是有一种意外的情况:

let foo1 =  function(){
	 let a = 2 ; 
	 return function () {
	  a++;
	  alert( a )
	 }
}; 
let f = foo1();
f(); // 3
f() // 4

奇怪的知识点就在这里,难道a没有消失吗?
因为 f 指向了 foo1(),这是一个引用,f是可以调起函数产生时的环境,这时a就被保存在那个环境中,没被
销毁,由此局部变量的生命周期得到了延长。

闭包的经典应用

<ul>
			<li>1</li>
			<li>2</li>
			<li>3</li>
			<li>4</li>
			<li>5</li>
		</ul>
------------------
	var aLi = document.getElementsByTagName("li");
			for(let i = 0; i < aLi.length; i++){
				aLi[i].onclick = function(){
					console.log(i);
				}
			}

会发现始终在打印5,因为点击事件是异步的,当点击事件触发时,for循环已经走完了,当点击事件找到i的时候为5,for会把点击事件推送至事件队列,所以打印会执行5次,但每次都打印5.

闭包更多作用

闭包可以保留私有变量

 var mult = (function(){
	  var cache = {} ;
	  return function()
		 {
			 var args = Array.prototype.join.call( arguments, ',');
			 if( args in cache ){
			 	return cache[args]
			 }
			 var a = 1;
			 for( var i = 0 , k  = arguments.length ; i < k,i ++ ){
			  a = a * arguments[i];
			 }
			 return cache[ args ] = a;
		 } 
 })()

高阶函数

高阶函数有这样的定义:

  1. 函数可以作为参数被传递
  2. 函数可以作为返回值被输出

作为参数被传递:

let appendiv = function( callback ) {
	 for(let i =0;i<100;i++){
	 var div = document.createElement('div');
	 div.innerHTML = i;
	 if( typeof(callback) === 'function' ){
	  callback( div )
	 }
	  }
};
appendiv( function( node){
	node.style.display = 'none'
} ) 

作为返回值被输出:

我们来一个简单的例子:

let getsingle =  function( fn){
   let ret;
   return function() {
    return ret || ( ret = fn.apply( this,arguments ) )
   }
};
let getsomething = getsingle( function(){
 return document.createElement('script')
} );
let scri = getsomething()
let scrr = getsomething() 
Object.is( scri,scrr ) //true

高阶函数实现AOP:

什么是AOP?,其主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,然后再通过动态插入的方式混入具体的业务模块中去。
我们来看一个例子:
我们通过扩展Function.prototype来进行一些好玩的事情:

Function.prototype.before = function( beforefn ) {
	let _this = this;
	return function(){
		beforefn.apply(this. arguments  ); // 修正this
		return _this.apply( this,arguments )
	}
};
Function.prototype.after= function( afterfn ) {
	let _this = this;
	return function(){
	let ret = _this.apply( this , arguments )
		afterfn .apply(this. arguments  ); 
		 _this.apply( this,arguments )
		 return ret
	}
};
let func = function(){
 console.log( 2)
}
func  = func .before( function(){
console.log(1)
} ) .after( function(){
console.log(3)
} )

高阶函数的其他应用:

  1. curring(函数柯里化)
    直接上例子:
let month = 0;
let  cost = function (money) {
month += money
};
cost( 1000 )
cost( 2000 )
cost( 3000 )
cost( 4000 )
alert( month ) 

这不是对函数柯里化的实现,只是表达柯里化的思想
下面是柯里化的实现:

let currying = function(fn){
	let arg = [];
	 return function(){
	 	 if (arguments.length == 0){
	 	 	return fn.apply(this,args);
	 	 }else{
	 	 	[].push.apply(args,arguments);
	 	 	return arguments.callee;
	 	 }
	 }
};
let cost = (function(){
	let money = 0;
	return function()
		{
			for( let i =0,k = arguments,length;i<k;i++ ){
				money += arguments[i];
			}
			return money;
		}
})();

let cost = currying( cost ) // 函数柯里化
cost( 100 );
cost( 200 );

cost() // 求值并输出:300

函数节流:

函数节流的方式有许多种,再次提供一种思路:
即将被调用的函数设置一个setimeout延迟一段时间执行,当该函数被再次触发时,如果延迟没结束,则不执行。

let throttle =  function( fn , interval){
	let _self = fn,timer,fistTime = true ; 
	return function () {
	 let args = arguments , 
	 _me = this ; 
	 if( fistTime ){
	 	_self.apply(  _me ,args );
	 	return fistTime = false ;
	 }  
	 if( timer ){
	 	return false ;
	 } 
	 timer = setTimeout( function(){
	 	clearTimeout( timer );
	 	timer = null ; 
	 	_self.apply(_me,this);
	 },interval || 500);
	};
 };
 window.onresize = throttle( function(){
 	console.log(1)
 } ,500);

分时函数:

有时候,页面有大量的数据需要渲染,浏览器会因为此而崩溃,为了放置这种情况的发生,我们需要分时函数经行安全防范。
比如:有一个函数,让原本需要1秒内渲染1000次的操作改为200毫秒10次。

let timethunk = function(ary , fn , count){
	let obj,t;
	let len = arr.length;
	let start = function(){
	 for( let i = 0; i < Math.min(count || 1,arr.length ); i++){
	 	 let obj =ary.shift();
	 	 fn( obj );
	 }
	};
	return function(){
		t = setInterval( function(){
		 if(ary.length === 0){ //如果全部节点创建完毕
		 	return clearInterval(t)
		 }
		 start();
		},200)
	}
};

let arr = [];
 for( let i =0;i<=1000;i++){
 	ary.push(i)
 };
 let render = timethunk( ary,function(n){
  let div = document.createElement('div');
  div,innerHTML = n;
  document.body.appendChild( div ) ;
 },10);
 render()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁锅炖大鹅(e)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值