对象&函数进阶------2

对象

  • 对象的属性存储数据
  • 对象的方法执行语句块,无法存储数据

setter&getter

  • set方法有且仅有一个参数,参数是赋值时的值

  • get方法中不允许有任何参数

  • 函数本身是不允许存储任何值的,使用临时属性,在s执行set方法中,将赋予的值存储在临时属性值中,执行get方法时将临时变量返回

  • 如果仅有set没有get,这个属性就是只写属性;如果没有set只有get方法,这个属性是一个只读属性;可以利用set和get完成常量写入

    var obj={
        a:1,
        _c:0,
        b:function(){},
        // set有且仅有一个参数
        set c(value){
        	document.documentElement.style.backgroundColor="#"+value.toString(16);
        	this._c=value ;
        },
        // get不允许有任何参数
        get c(){
        	return this._c;
        }
    }
    setInterval(function(){
    	obj.c++;
    },16);
    
  • ES6中的常量设置

    class Box{
        // static const EVENT_ID="Event_Id";//ES6中不能写常量
        constructor(){
    
        }
        static get EVENT_ID(){
       		return "EVENT_ID";
        }
    }
    console.log(Box.EVENT_ID);
    
  • 对象在初始创建时有set和get方法,对象创建完成后,不能在对象中增加set和get方法,利用Object.defineProperty()给对象追加属性。

    var div =document.querySelector("div");
    
    Object.defineProperties(div,{
        _width:{
            writable:true,
            value:0
        },
        _height:{
            writable:true,
            value:0,
        },
        _bgColor:{
            writable:true,
            value:0
        },
        width:{
            enumerable:true,
            set:function(_value){
            	this.style.width=_value.toString().indexOf("px")>-1?_value:_value+"px";
            	this._width=_value;
        	},
            get:function(){
                return this._width;
            },
        },
        height:{
            enumerable:true,
            set:function(_value){
            	this.style.height=_value.toString().indexOf("px")>-1?_value:_value+"px";
            	this._height=_value;
        	},
            get:function(){
                return this._height;
            },
        },
        bgColor:{
            enumerable:true,
            set:function(_value){
            	this.style.backgroundColor=(typeof _value==="string")?_value:("#"+_value.toString(16).padStart(6,"0"));
           		this._bgColor=_value;
            },
            get:function(){
            	return this._bgColor;
            },
        },
    });
    
    setInterval(function(){
        div.width++;
        div.height++;
        div.bgColor+=100;
        console.log(div.bgColor)
    },100);
    
    • 当属性没有方法,只存储值时,不需要用set/get方法设置获取,直接用属性即可

    • set/get只能设置字符串/数,对象/数组等引用地址设置后无意义

      import Utils from "./js/Utils.js";
      var div=document.querySelector("div");
      var obj={
          _arr:[],
          set arr(value){
              if(!Array.isArray(value)) return;
              if(this._arr.join()===value.join())return;
              div.innerHTML="";
              for(var i=0;i<value.length;i++){
                  let ball=Utils.ce("div",{
                      width:"50px",
                      height:"50px",
                      backgroundColor:"red",
                      color:"#FFFFFF",
                      textAlign:"center",
                      lineHeight:"50px",
                      borderRadius:"50px",
                      float:"left"
                  },div);
                  ball.textContent=value[i];
              }
              this._arr=value;
          },
          get arr(){
          	return this._arr;
          }
      }
      var t=0;
      setInterval(animation,2000);
      
      function animation(){
          t++;
          obj.arr.push(t);
      }
      
      • obj.arr的引用地址时_arr,如果不重新给obj.arr赋值,重新设置其引用地址,obj.arr的引用地址就不会改变,调用obj.arr后就不会产生效果

      • 引用地址不变都不会触发obj.arr,只有将obj.arr重新赋值,改变引用地址,才可以触发

        import Utils from "./js/Utils.js";
        var div=document.querySelector("div");
        var obj={
            _arr:[],
            set arr(value){
                if(!Array.isArray(value)) return;
                if(this._arr.join()===value.join())return;
                div.innerHTML="";
                for(var i=0;i<value.length;i++){
                    let ball=Utils.ce("div",{
                        width:"50px",
                        height:"50px",
                        backgroundColor:"red",
                        color:"#FFFFFF",
                        textAlign:"center",
                        lineHeight:"50px",
                        borderRadius:"50px",
                        float:"left"
                    },div);
                    ball.textContent=value[i];
                }
                this._arr=value;
            },
            get arr(){
            	return this._arr;
            }
        }
        var a=[];
        var t=0;
        setInterval(animation,2000);
        
        function animation(){
            t++;
            a.push(t);
            obj.arr=a;
        }
        
        • 每一次调用obj.arr时,都要重新赋值,将引用地址指向需要添加的数组,以激活obj.arr
      • 对象深比较

        compareData(target,source){
            for(var prop in target){
            	if(typeof target[prop]==="object" && target[prop] !== null){
            	return this.compareData(target[prop],source[prop]);
            }else{
            	if(target[prop] !== source[prop]) return false;
            	}
            }
            return true;
        }
        

数据结构简介

  • 数据结构

    • 数据的结构性,指相互之间存在一种或多种特定关系的数据元素的集合。
    • 关系到数据处理的速度,进而影响数据的效率问题
  • 数组

    • 有序列表存储若干个无序的元素。

    • 插入和删除会影响数组的元素的位置和结构,速度较慢

    • 查找数组中的某个值时,需要遍历数组的每一个元素,时间复杂度极高,查找速度慢

    • 注意

      • 在刚创建时先设置长度,再根据长度存入数据时,效率较高
    • 普通数组类型

      • 创建时给定长度
      • 数组的内容数据类型相同
      • 尽量向尾部插入,不在前面或者中间插入
    • 二维数组可以通过经纬坐标获取值,效率较高

    • 二维数组类型

      • 多用于二维表格类型数据
      • 存入的数据时列表结构,在二维数组内部只存储表中的数据,没有表头数据
      • 可以很方便的找到上下级关系
      var arr1=["数学","语文","英语"];
      var arr2=["张三","李四","王五"];
      var arr=[
          [12,13,14],
          [42,43,44],
          [62,63,85]
      ]
      var index=arr2.indexOf("张三");
      var i=arr1.indexOf("语文");
      console.log(arr[index][i]);//张三的语文成绩
      index++;
      console.log(arr[index][i]);//李四的语文成绩
      index++;
      console.log(arr[index][i]);//王五的语文成绩
      
      • 当仅获取结果/值时,对象方法速度更快,但是当获取上下的数据时,数组的效率更高。

        var obj={
            张三:{数学:12,语文:13,英语:14},
            李四:{数学:42,语文:43,英语:44},
            王五:{数学:62,语文:63,英语:64},
        }
        console.log(obj["张三"]["语文"]);
        
  • 对象

  • Set

    • 本质是一个对象,但是Set中key与value相同

    • 仅存储数据

    • 无重复有序列表,属于散列结构,没有下标,不能使用下标循环遍历,无法通过上下关系直接获取上下的数据

    • 插入和删除不需要考虑位置的移动,插入和删除速度很快。

    • 会自动去除重复元素,元素存在唯一性,可以用于大量的不重复数据存储遍历查找速度也很快,略低于键值对类型(例如 对象)。

    • 集合

      • 不重复

      • 插入时考虑插入的位置,属于散列结构

      • 可以设置多重集

        let set=new Set([1,2,3,4,5]);//集
        let set1=new Set([2,3,4,5,6]);
        let set2=new Set([set,set1])//多重集
        console.log(set2);
        
    • 有长度size

  • weakSet

    • 可以存储多个不同引用地址的相同对象,销毁引用对象时,该数据也会被销毁
    • 弱引用类型
  • Map

    • 是一种有长度的键值对数据结构,具备数组的长度紧密性,又具有对象的键值对方法

    • 获取、删除、查询、遍历速度很快

    • 任何类型都可以作为key使用(对象的key只能是String或Symbol)

    • 可以直接枚举遍历键和值

    • 类似于hashMaphash表

      • 链式存储结构

        var o1={value:2};
        var o={value:1,next:o1};
        
    • 优点

      • 使用键值对存储
      • 查找速度快,
      • 可以使用引用地址作为key存储数据
      • 有长度
    • 尽量使用Map,减少使用对象存储数据

    • 缺陷

      • 无法获得上下级关系
  • weakMap

    • 使用弱引用对象类型作为key来存储数据,当对象被删除时,对象中的key和value同时被销毁
    • 某些指定的对象集在一起就是集合。
    • 一定范围的,确定的,可以区别的事物,当作一个整体来看待,就叫做集合,简称集,
    • 其中各事物叫做集合的元素或简称元。
    • Object就是集,对象下的属性就是元
    • 就是Set,Set是通过对象来封装的
    • 多重集
      • 多重集就是复杂对象
      • {1,2,3}是一个集合
      • {{1,1,1},{2,2},3}而不是一个集合,而是一个多重集。
    • 非线性数据结构,是元素按分支关系组织起来的结构
  • 特点

    • 每个元素有0个或多个子节点,没有父节点的节点称为跟节点

    • 每一个非根节点有且只有一个父节点,除了跟节点外,每个子节点可以分为多个不相交的子树

    • 类型

      • 二叉查找树(二叉排序树)
      • 先搜索左树,后查找右树
      • 平衡二叉树
        • 空树或左右两个子树的高度差值的绝对值不超过1
      • 自平衡二叉树(红黑树)
        • 避免二叉树退化成链表的结构
  • 链表

    • 是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

    • 链表由一系列节点(链表中的每一个元素称为节点)组成,节点可以在运行时动态生成。

    • 每个节点包括两个部分:一个是存储数据元素的数据域,一个是存储下一个节点地址的指针域。

    • 查找速度较慢

    • 插入删除速度快

    • 非连续性非顺序结构

    • 可以存储大量数据,可以快速改变数据结构

    • 单向链表

      var o={value:1};
      var o1={value:2,next:o};
      var o2={value:3,next:o1};
      var o3={value:3,next:o2};
      
    • 双向链表

      var o={value:1};
      var o1={value:2,next:o};
      var o2={value:3,next:o1};
      var o3={value:3,next:o2};
      o.prev=o1;
      o1.prev=o2;
      o2.prev=o3;
      
  • 堆栈结构

      • 先进后出
      • 使用一级缓存,通常是被调用时处于存储空间中,焦勇完毕立即释放
      • 可以看成一棵树
      • 存放在二级空间中,声明周期由虚拟机的垃圾回收算法来决定,并不是一旦称为孤儿对象就能被回收。所以调用这些对象的速度相对较慢。

函数

  • 参数

    • 参数是局部变量,优先级高于同名的全局变量

    • 作用

      • 为了解决函数的抽象化、多态化,让代码具备 模块化的功能

      • js是弱引用型语言,参数可以多样化改变,也因此造成函数中需要对参数做大量的判断

        function on(type,data,handler){
            if(data.constructor===Function){
                //当data是函数时,data作为handler使用,销毁data
                handler=data;
                data=null;
            }
        }
        
        on("click",function(){
        })
        
        on("click",{a:1,b:2},function(){            
        })
        
        • 参数是按位来的,不会因为少传入了参数就会将后面的参数移动到前面,如果中间少参,会补undefined,所以想要后面的向前移动,需要进行判断并做响应处理
      • 参数可以作为函数中的初始设置变量

        function fnc(num){
            //即使在调用fnc时不传参,在函数内部也会给参数设置初值
            if(num===undefined) num=0;
            num++;
            if(num<10) return fnc(num);
            return num;
        }
        
      • 在多函数中,参数可以被作为中介值被来回传递并且处理,减少全局变量

        function fn1(){
            var num=1;
            num=fn2(num);
            console.log(num);
        }
        function fn2(n){
            n++;
            return fn3(n);
        }
        function fn3(n){
            n*=n;
            return n
        }
        fn1();
        
    • js中参数没有初始值(ES5),参数没有类型区分(大量判断)

    • 参数的先后问题

      • 必要参数在前,不必要参数在后(ES5)
    • ES5参数没有若干(…arg),但是有arguments

  • return

    • 使用return跳出函数,结束当前内容

      • 条件作用时,使用return可以解决多分支结构,优化效果更好
      • 使用return跳出时直接跳出循环或条件,返回undefined
      • 使用return可以在setIterval或快速连续调用时用于防抖
      • 使用return可以完成函数的开关操作
    • 使用return返回数据

    • 工厂模式

      • 来料加工型的,给什么材料创造什么东西,根据不同数据创建不同的内容
      function ce(type,style){
          var elem=document.createElement(type);
          Object.assign(elem.style,style);
          return elem;
      }
      var div1=ce("div");
      var div2=ce("div");
      var p=ce("p");
      console.log(div1===div2);//false
      
      //返回对象
      function createObj(){
          return {
              a:1,
              b:2
          }
      }
      
      var o=createObj();
      
    • 单例模式

      • 仅创建一个内容

        var elem;
        function createElem(){
            if(elem) return elem;
            elem=document.createElement("div");
            return elem;
        }
        //上述代码可以改写为下面的形式
        function createElem(){
            if(!elem) elem=document.createElement("div");
            return elem;
        }
        
        var a=createElem();
        var b=createElem();
        console.log(a===b);//true
        
        class Box{
        static _instance;
        constructor(){
        }
        static getInstance(){
            if(!Box._instance) Box._instance=new Box();
            	return Box._instance;
            }
        }
        
        var a=Box.getInstance();
        var b=Box.getInstance();
        console.log(a===b);//true
        
        class Box{
            constructor(){
        
            }
            static get instance(){
                if(!Box._instance){
                    //给Box创建一个_instance属性,值为new Box(),不可枚举,不可修改,不可删除,第一次创建完成后不会发生变化
                                       Object.defineProperty(Box,"_instance",{
                    	value:new Box(),
                    });
                }
                return Box._instance;
            }
        
            play(){
            	console.log("play");
            }
            run(){
            	console.log("run");
            }
        }
        
        var a=Box.instance;
        var b=Box.instance;
        console.log(a===b);
        
        Box.instance.play();
        Box.instance.run();
        
    • 中介者模式

      export default class Model extends EventTarget{
          _data=0;
          constructor(){
              super();
          }
          static get instance(){
              if(!Model._instance){
                  Object.defineProperty(Model,"_instance",{
                      value:new Model(),
                  })
              }
              return this._instance
          }
          set data(value){
              this._data=value;
              Model.instance.b.play(value);
              var evt=new Event("data");
              this.dispatchEvent(evt);
          }
          get data(){
              return this._data;
          }
      }
      
      • model是中介
    • 返回源对象

      • 可以返回源对象,也可以不设置
      function fn(obj){
          obj.a=10;
          return obj;
      }
      var obj=fn({b:1});
      obj=fn(obj);
      console.log(obj);
      //类似于Object.assign()
      
    • 如果参数是函数,返回回调函数的结果

      function fn1(fn){
          return fn(5,6);
      }
      function fn2(a,b){
      	return a+b;
      }
      var sum=fn1(fn2);
      console.log(sum);
      
    • 返回数组或对象,用于返回多个元素

      function fn(){
          var a=1;
          var b=2;
          var c=3;
          return [a,b,c];
      }
      let [a,b,c]=fn();//解构
      console.log(a,b,c);
      
      function fn(){
          return{
              a:1,
              b:2,
              c:3
          }
      }
      let {a,b,c}=fn();//解构
      console.log(a,b,c);
      
    • 返回函数体

      function fn(){
          return function(){
          	console.log("aa");
          }
      }
      
      var f=fn();
      fn();
      
      • 将内部函数体存储在外部的全局变量中
    • 函数的length

      • 形参的数量

闭包

  • 有权访问另一个函数作用域中的变量的函数,创建的常用方式为在一个函数内创建另一个函数

    function fn1(){
        var a=1;
        // 返回的函数被存储在全局变量中,且这个返回的函数使用局部变量a,所以a被保存在堆中
        return function(){
            a++;
            console.log(a);
        }
    }
    
    var f=fn1();
    f();
    
    • 内存泄漏
      • 此时f是fn1返回的匿名函数,匿名函数中引用了fn1的局部变量a,原本fn1执行完成后,a会被销毁,但因为匿名函数引用了a,所以a会保存在堆中,造成内存的浪费。只有f销毁时,a才会被销毁,当a是对象时,及时f销毁时,a也不会被销毁,因为a没有设置为null
  • 缺点

    • 闭包必然会造成内存泄漏
  • 特点

    • 函数嵌套函数
    • 函数内部可以引用外部的参数和变量
    • 参数和变量不会被垃圾回收机制回收
  • 优点

    • 希望一个变量长期驻扎在内存中
    • 为了解决变量污染
    • 为了得到私有变量
  • 闭包的使用

    var Utils=(function(){
        var num=0;
        return{
            a:function(){
                num++;
                console.log(num);
            },
            b:function(){
            }
        }
    })();
    
    Utils.a();
    Utils.a();
    Utils.a();
    

柯里化

  • 解决实际的融合问题

  • 传参时收集参数进行存储,没有参数时返回结果

    function curry(fn){
        var arr=[];
        return function(){
            //当传入实参时,将传入的参数与arr连接,并将当前函数返回
            if(arguments.length>0){
            arr=arr.concat(Array.from(arguments));
            return arguments.callee;
            }else{
                //当不传参时,将arr作为参数带入curry(fn)的参数函数中,并执行该参数函数
                return fn.apply(null,arr);
            }
        }
    }
    function fns(){
        // 接收curry传进来的数组,进行相应的处理
        return Array.from(arguments).reduce((value,item)=>value+=item);
    }
    var s=fns(1,2,3,4,5);
    console.log(s);
    var sum=curry(fns);
    var s=sum(1)(1,2)(1,2,3)();
    console.log(s);
    

你可能感兴趣的:(JavaScript)