js笔记13(函数的闭包&object的封装)


一、函数的闭包

        1、函数的执行&作用域链

        作用域:全局作用域:全局可用,但是容易被污染

                      和函数作用域:一次性的,用了就会释放

        函数的执行原理:

        1、程序加载时,创建执行环境栈ESC,保存函数调用的顺序的一个数组;首先会压入全局执行环境(全局EC),全局EC引用着全局对象window,window中保存着全局变量

        2、定义函数时:函数会封装着函数定义的内容,在函数对象中定义出scope(作用域)属性,全局函数的作用域都是window

        3、调用函数前:在执行环境栈ESC压入新的EC(函数的EC),然后回创建一个活动对象AO,AO保存着调用函数时使用的局部变量,并在函数EC中添加scope chain(作用域链)引用着AO;AO的parent属性为函数的scope引用的对象。

        4、调用时:函数就会优先使用自己的局部变量,没有的话再通过parent属性引用的函数的scope引用的对象(全局)

        5、调用完时:函数的EC会出执行环境栈ESC,AO也就没了,局部变量也就释放了

作用域链(scope chain):以EC中的scope chain属性为起点,经过AO逐级引用,形成的一条链式结果就称之为作用域链

        2、函数的闭包:

        闭包:希望保护一个可以反复使用的局部变量的一种词法结构;这个局部变量就可以反复使用,并且不会被污染;但是受保护的变量永远不会被释放,过多使用闭包会导致内存泄露(就是一直占用着内存)

        1、两层函数进行嵌套,

        2、外层函数创建出一个受保护的变量,并且要return出内层函数

        3、内层函数操作受保护的变量,并return出结果

        function cs(){
            var i=0;
            return function(){
                i++;
                return i;
            }
        }

闭包一般用在“防抖节流”上,体现在三个事件上:

        var h1 = document.getElementsByTagName('h1')[0];
        var inp = document.getElementsByTagName('input')[0];
        //鼠标移入事件
        h1.onmousemove = function () {
            f2();
        }
        var f2=f1();
        function f1() {
            //声明了变量未赋值,所以是一个undefined
            var timer;
            return function () {
            //判断timer,undefined为false    
                if (timer) {
            //假的就清空定时器
                    clearTimeout(timer)
                }
            //用timer创建一个定时器    
                timer = setTimeout(function () {
            //操作dom树的代码,会间隔1s才会执行        
                    return h1.innerHTML = parseInt(h1.innerHTML) + 1
                }, 1000)
            }
        }
        //inp事件
        inp.oninput=function(){
            a2();
            if(inp.value.length>=5){
                inp.style.borderColor="red";
           
            }
        }
        var a2=a1();
        function a1(){            
            var timer;
            return function(){
                if(timer){clearTimeout(timer)}
                timer=setTimeout(function(){
                    return inp.vlaue;
                },50)
            }
        }
			//屏幕尺寸变化事件
			window.onresize=function(){
				rs();
			}
			function fdjl(){
				var timer;//保存定时器的地方
				return function(){
					//判断有没有定时器,有的话就清空
					if(timer){clearTimeout(timer)}
					//在开启一个定时器
					timer=setTimeout(function(){
						if(innerWidth>996){
							console.log(1);
							d1.style.background="pink";
						}else{
							d1.style.background="purple";
						}
					},1000)
				}
			}
			var rs=fdjl();		
			window.onresize()

固定用法:

function fdjl(){
				var timer;//保存定时器的地方
				return function(){
					//判断有没有定时器,有的话就清空
					if(timer){clearTimeout(timer)}
					//在开启一个定时器
					timer=setTimeout(function(){
						//自己的操作
					},1000)
				}
			}
			var rs=fdjl();

			elem.on事件名=function(){
				rs();
			}

二、object

        面向过程:先干什么再干什么,逐步写下去

        面向对象:对象有属性和方法

        面向对象:三大特点:封装   继承   多态

        1、面向对象的封装的创建方式:

        直接量方式:var obj={"属性名":属性值,"方法名":function(){方法的操作}}

        构造函数方式:var obj=new Object();

        创建的是空对象,需要添加:obj.属性名=属性值;obj.方法名=function(){};

        自定义构造函数方式:可以同时创造多个对象

			function h52104(name,age,hobby){
				this.xingming=name;//
				this.nianling=age;//
				this.aihao=hobby;
			}
			var zhl=new h52104("张啊",18,"听歌猛男");
			var ddk=new h52104("啊",12,"哔哔");
			var zhn=new h52104("在",28,"测过");
			console.log(zhl);
			console.log(zhn)
			console.log(ddk)

封装的使用案例:

        var xxk={
            //创建一个属性,这个属性是dom树中所有的li,
            "lis":document.getElementsByTagName('li'),
            "ds":document.getElementsByTagName('div'),
            //创建一个方法:
            "init":function(){
            //这个方法中再次调用了一个方法,this指当前的这个对象
            //这个方法对象中没有,所以要创建一个
                this.bind();
            },
            //创建一个方法
            "bind":function(){               
                var me=this;
            //this还是值当前对象,lis是一个集合,需要循环才能分别绑定事件       
                for( var i=0;i<this.lis.length;i++){
                    this.lis[i].onclick=function(){
            //这里如果还用this的话,this指向的是绑定事件的元素了
            //所以上面用一个变量保存住对象的this,用对象在调用一个方法
            //这里调用的时候必须把当前点击事件的this做实参     
                    me.animate(this);
                    }         
            //当前this还是指当前的对象,给当前对象的属性lis绑定事件
                
                }
            },
            //这里的方法要有个形参,接住当前点击事件的元素this
            "animate":function(li){
            //先循环把所有的class名清空    
                for(var i=0;i<this.lis.length;i++){
                    this.lis[i].firstElementChild.className="";
                    this.lis[i].className="";                                        
                }
            //这里不能循环来获取点击事件的元素,只能用形参通过实参把点击事件的元素保存起来
            //不然不能单独操作点击事件的元素    
                li.firstElementChild.className="jh";
                li.className="a1";  
            }
        }
    xxk.init();

        对象中this的指向:

                  1、单个元素绑定事件:this->这个元素
                  2、多个元素绑定事件:this->当前元素
                  3、*函数中出现了this:this->谁调用的此方法,this就是谁
                  4、定时器中this永远指向window
                  5、构造函数中的this -> 当前正在创建的对象

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值