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

Object对象

原型链

  • 在类中定义的方法存储在原型链中,对象实例化后,通过点语法增加的方法保存在该实例化对象中,是该实例化对象独有的方法

    class Box{
    	constructor(){
    	}
    	play(){
    	}
    	run(){
    	}
    }
    var b=new Box()
    b.abc=function(){
    }
    console.log(b);
    
  • 类继承基类时,当前类的原型中存在基类的原型,实例化对象后,通过点语法添加的属性属于该实例化对象独有。

    class Box{
    	constructor(){
    	}
    	play(){
    	}
    	run(){
    	}
    }
    class Ball extends Box{
    	constructor(){
    		super();
    	}
    	action(){
    
    	}
    }
    
    var e=new Ball();
    e.a=10;
    console.log(e);
    
  • 万物皆对象

    • 具有属性和方法的都是对象

    • 所有的对象都有原型链

      //数组
      var arr=[1,,2,4]
      console.log(arr);
      //日期对象
      var date=new Date();
      console.dir(date);
      //正则
      var reg=/a/;
      console.dir(reg);
      //DOM元素
      var div=document.createElement("div");
      console.dir(div);
      //Symbol
      var s=Symbol();
      console.log(s);//不能显示
      console.log(s.__proto__);//可以显示
      //字符串
      var str="aaa";
      console.log(str.__proto__);
      
  • 原型

    • 类实例化新对象时会将类中的对象也赋给新对象,所以在类中的方法都存储在–proto–原型中,而实例化对象增加的方法,是属于实例化对象个体的,不会存储在原型中
    • 类中constructor()构造函数中的属性和方法都是在创建实例化对象时产生的,属于实例化对象自身的属性和方法,不是存储在–proto–中
    • 对象中的–proto–
    • 任何对象都可以调用其原型下的属性和方法
  • 所有的对象都会继承Object对象,都会存在Object的原型–proto–

    • DOM对象继承了多层基类,在改动DOM对象时,会将原型链进行重绘,耗费性能
  • 特殊处理的对象(五种)

    • 存储在栈中的类型也是对象,调用方法时,会去堆中调用响应的方法
    • String
    • Number
    • Boolean
    • null
    • undefined
  • 对象的创建

    • 字面量创建

      var obj={a:1}
      
    • 构造函数创建法

      • 对象中的key必须是String或Symbol类型,如果不是就会隐式转换为String类型
      var obj= new Object();
      obj.a=10;
      var c="c";
      obj[c]=20;
      console.log(obj);
      
      • 对象增加属性

        obj.b=10;//b是字符串
        var c="c";
        obj[c]=20;//c是变量
        
        //key为对象
        var o={a:2};
        obj[o]=10;
        console.log(obj[{b:3}]);//10
        //key为数组
        var arr=[0];
        obj[arr]=100;
        console.log(obj[0]);
        console.log(obj[0,12]);
        
        • 对象在转换为字符串时会转换为[Object Object],所以所有的对象都会转换成相同的字符串
        • 数组在转换为对象时,会将数组的每一项以,连接,转换成一个字符串,作为key值
    • 以原有对象为原型创建新对象

      //以o为原型创建o1
      var o={a:1};
      var o1=Object.create(o);
      var o2=Object.create(o);
      

    console.log(o,o1,o2)
    o.a=10;
    console.log(o,o1,o2)
    o1.b=10;
    o2.c=10;
    console.log(o,o1,o2)
    o1.a=10;
    o2.a=11;
    console.log(o,o1,o2)
    console.log(o1.proto===o);

    
    - 原型指向原有对象,使用原有对象的引用地址,当原有对象的属性或方法改变时,新对象的原型也会发生改变,新对象可以使用原有对象的属性和方法
    - 当设置对象属性时,直接设置的是对象的自身属性(对象属性),获取时首先查看该对象有没有这个名称的对象属性,如果有,直接返回这个属性值;如果没有向下查找紧邻的原型链中的属性,是否具有该属性名,查找到距离该对象__最近__的原型链中的属性名后返回其值。
    - 以相同原型创建的新对象是独立存在的,没有关系;原型改变时会影响所有新对象
    - 任何对象都能通过--proto--修改原型链的属性
    
    
  • 对象创建时的特征

    • 对象的属性下使用this,this指向对象外的this指向,在对象的方法中使用this,this指向该对象

      var c=0;
      var obj={
      	a:1,
      	b:function(){
      		console.log(this.a);
      	},
      	[c]:10,
      	c:100,
      	d:this.c
      }
      //执行obj.b()时,obj已经创建完成,this指obj
      obj.b();//1
      //对象属性中的this,对象还没有创建完成,this还没有形成,所以this指向对象外this指向
      console.log(obj.d);//0
      
    • 对象没有长度length

对象的assign

  • 对象的浅复制
    • 仅把第一层的属性复制到新对象中,如果第一层的属性值是引用类型,则会把引用地址复制

    • o={…o1}

      • …是解构o1
      • 将o1的所有属性解构产生新对象赋值给了o
      • 地址会发生改变
      var o5=o4={h:10};
      o4={...o1,...o2,...o3};
      console.log(o4===o5);//false 引用地址发生了改变
      
    • obj=Object.assign(新对象,原对象1,原对象2,…)

      • 将一个或者多个对象中的可枚举属性复制到第一个参数对象中,如果后面的对象的属性与前面对象的属性相同,会覆盖前面的对象的属性
      • ​ 浅复制,仅能把第一层的属性复制到新对象上,如果第一层的属性值是引用类型,则会把引用地址赋值
       var o={
      	a:1,
      	b:2,
      	c:{
      		d:1
      	}
      }
      var o1=Object.assign({},o);
      console.log(o1);
      o.c.d=10;
      console.log(o1);
      
      • 原对象中增加复制的属性,引用地址不改变
      var o1={a:1,b:2,c:3};
      var o2={d:4,e:5,f:6};
      var o3={a:7,e:8,c:9};
      var o0=o={h:10};
      Object.assign(o,o1,o2,o3);
      console.log(o===o0);//true
      

对象的属性相关方法

  • Object.defineProperty(对象,属性名,该属性的描述对象)

  • 属性的描述对象

    • configurable: true,//该属性是否可以删除,并且该属性的描述对象是否可以更改,默认false

    • enumerable: true,//该属性是否可以枚举,默认false

    • writable: true,//该属性是否可写(不是只读),默认false

    • value: 10,//该属性的值

      var obj={};
      Object.defineProperty(obj,"a",{
      	configurable:true,//可删除
      	enumerable:true,//可枚举
      	writable:true,//可删除
      	value:2//值为2
      })
      //也可写成以下写法
      Object.defineProperty(obj,"b",{
          configurable:true,
          enumerable:true,
          set:function(_v){},
          get:function(){}
      })
      console.log(obj);
      
      • writable和value与set和get冲突,不能同时设置
    • Object.defineProperties(对象,属性名,该属性的描述对象)

      • 同时设置多个属性
      Object.defineProperties(obj,{
      	a:{
              enumerable:false,
              writable:true,
              configurable:true,
              value:20
      	},
      	b:{
              writable:true,
              configurable:true,
              value:function(){
              }
      	},
      	c:{
              configurable:true,
              value:100
      	}
      })
      
    • Object.getOwnPropertyNames(对象)

      • 获取对象的所有对象属性名
      
      Object.defineProperties(obj,{
          a:{
          	value:1
          },
          b:{
              enumerable:true,
              value:2
          },
          c:{
              writable:true,
              value:3
          }
          });
          obj.d=10;
          obj.e=100;
      
          var arr=Object.getOwnPropertyNames(obj);
          console.log(arr);
          for(var i=0;i<arr.length;i++){
          console.log(arr[i],obj[arr[i]]);
          var disc=Object.getOwnPropertyDescriptor(obj,arr[i]);
          console.log(disc);
      }
      
    • Object.getOwnPropertyDescriptor(对象,属性)

      • 获取属性的描述对象
      • 返回数组
      var disc=Object.getOwnPropertyDescriptor(obj,"a");
      
    • Object.freeze()

      • 冻结

      • 对象属性不可修改,不可删除

      • 可以将该对象下所有属性转换为常量

      • 冻结数组

        • 数组的每一项不可修改
        var arr=[1,2,3,4];
        Object.freeze(arr);
        arr[2]=100;
        console.log(arr);
        
      • 冻结对象

        • 所有属性不可修改、不可删除
        • 将该对象下所有属性正式转换为常量
        Object.freeze(obj)
      • 冻结函数

        • 函数内部的数据或方法不可修改
    • Object.is(a,b)

      • 判断某个内容是不是指定值
        • 返回true/false
        • 类似于=的比较,但是NaN=NaN,此时等同于isNaN()
    • Object.isExtensible(obj)

      • 判断对象是否可以扩展
        • 冻结后,不可扩展,不可以增加新属性
    • Object.isFreeze(obj)

      • 判断对象是否冻结
    • Object.hasOwnProperty(“a”)

      • 判断当前对象的对象属性,原型链上的属性不属于对象属性

        var o={a:1,b:2};
        var o1=Object.create(o);
        o1.c=10;
        var o2=Object.create(o1);
        console.log(o1.hasOwnProperty("a"));
        console.log("a" in o1)
        
        • 原型链上的属性不是该对象的属性
        • 通过in判断时,可判断原型链上的属性
    • obj.isPrototypeOf(o)

      • 判断对象是否在指定对象的原型链下,指定对象的父类中是否有当前对象

      • o对象的父类是否有obj

        var o={a:1,b:2};
        var o2=Object.create(o1);
        console.log(o.isPrototypeOf(o2));
        
        class Box{
        	constructor(){
        
        	}
            play(){
                if(parent.constructor===String) parent=document.querySelector(parent);
                               if(HTMLElement.isPrototypeOf(parent.constructor)) parent=document.body;
                parent.appendChild(this.elem);
            }
        }
        class Ball extends Box{
            constructor(){
            	super();
            }
            run(){
        
            }
        }
        console.log(Box.isPrototypeOf(Ball));//true
        var b=new Ball();
        console.log(Box.isPrototypeOf(b.constructor));//true
        
        console.log(document.documentElement);
        var div=document.createElement("div");        console.log(HTMLElement.isPrototypeOf(div.constructor));//判断是不是HTML标签
        
    • obj.propertyIsEnumerable(属性)

      • 判断该对象的某个属性是否是不可枚举属性
      • 空类型不属于对象
    • instanceof

      • 类别
      class Box{
      	constructor(){
      
      	}
          play(){
              if(parent.constructor===String) parent=document.querySelector(parent);
                             if(HTMLElement.isPrototypeOf(parent.constructor)) parent=document.body;
              parent.appendChild(this.elem);
          }
      }
      class Ball extends Box{
          constructor(){
          	super();
          }
          run(){
      
          }
      }
      var b=new Box();
      console.log(b instanceof Box);//true
      console.log(b instanceof Ball);//false
      console.log(b.constructor===Box);//true
      
    • null不属于对象类型

    • 但是typeof null === Object

      var b=null;
      console.log(typeof b);
      console.log(b instanceof Object);
      console.log(b.constructor===Object);//报错
      

函数

  • 函数的执行

    • call/apply

      • 可以改变函数中this的指向,当传入对象参数时,函数中的this会指向参数,如果参数不是对象,会将参数转换成对象
      • call的第一个参数是函数中this的指向,后面会按顺序带入参数
      • apply只有两个参数,第一个参数是函数中的this指向的对象,第二个参数是函数所需的所有参数的数组/列表
      function fn(a,b,c){
      	console.log(this,a+b+c);
      }
      var obj={a:1};
      fn.call("5");
      fn.call(obj,1,2,3);
      fn.apply(obj,[1,2,3]);
      
      • 只要调用call和apply,函数就会执行
      • 所有的回调函数如果需要替换this都不能使用call和apply,需要使用bind()方法
      var obj={a:1}
      setTimeout((function(){
      	console.log(this);
      }).call(obj),1000);//使用call,不能延时执行,因为回调函数被立即执行
      
      var obj={
          a:1,
          b:function(){
          	document.addEventListener("click",this.clickHandler.call(this));//此时直接执行clickHandler,点击时没有效果
          },
          clickHandler:function(e){
          	console.log(this);
          }
      }
      obj.b();
      
      function fn(a,b,c){
      	console.log(this,a+b+c);
      }
      
      fn();//this  window
      var obj={a:1};
      fn.call(obj);//将obj带入到函数替代函数中this的指向,原有的this会被指向obj
      fn.apply(obj);//和call一样
      
      • 获取数组中的最大最小值
      var arr=[1,2,3,4,5];
      var min=Math.min.apply(null,arr);
      var max=Math.max.apply(null,arr);
      console.log(min,max);
      
      • 重写Math的min/max函数
      var Maths={
          min:function(){
              if(arguments.length===0) return;
              var min=arguments[0];
              if(arguments.length===1)  return arguments[0];
              for(var i=0;i<arguments.length;i++){
              	min=min>arguments[i]?arguments[i]:min;
              }
              return min;
          },
          max:function(){
              if(arguments.length===0) return;
              var max=arguments[0];
              if(arguments.length===1)  return arguments[0];
              for(var i=0;i<arguments.length;i++){
              	max=max<arguments[i]?arguments[i]:max;
              }
              return max;
          }
      }
      var arr=[1,2,3,4,5];
      console.log(Maths.min.apply(null,arr),Maths.max.apply(null,arr));
      
      • 重写Array的slice()方法
      class Arrays{
          constructor(){
          }
          slice(start,end){
              if(start === undefined) start=0;
              if(end===undefined) end=this.length;
              var arr=[];
              for(var i=start;i<end;i++){
              	arr.push(this[i]);
              }
              return arr;
          }
      }
      
      var arr=new Arrays();
      console.log(arr.slice.call(document.getElementsByTagName("div")));
      
    • bind()

      • 绑定要传入的参数,不会执行函数
      • 调用bind()函数后,会返回一个新的函数,函数中所有的this都会指向参数
      function fn(){
      	console.log(this);
      }
      var f=fn.bind({a:1});
      fn();//window
      f();//{a:1}
      
      • 进行回调的传参,this就是bind()绑定的内容
        • 在侦听事件时,绑定的函数已经被更改了,每一次调用事件侦听的函数都会重新生成一个新的函数,所以无法删除侦听事件
        • 需要将事件侦听的函数单独保存出来,再进行删除
      var obj={a:1};
      setTimeout((function(){
      	console.log(this);
      }).bind(obj),1000)//1秒后打印{a:1}
      
      var obj={
          a:1,
          b:function(){
          	document.addEventListener("click",this.clickHandler.bind(this));
          },
          clickHandler:function(e){
          	console.log(this);
              document.removeEventListener("click",this.clickHandler);//这种写法,没有办法删除事件
          }
      }
      obj.b();
      
      var obj={a:1};
      setTimeout((function(){
      	console.log(this);
      }).bind(obj),1000)//1秒后打印{a:1}
      
      var obj={
          a:1,
          b:function(){
          	this.handler=this.clickHandler.bind(this);
              document.addEventListener("click",this.handler);//这种写法,没有办法删除事件
          },
          clickHandler:function(e){
          	console.log(this);
              document.removeEventListener("click",this.handler)
          }
      }
      obj.b();
      
  • this

  • ES5非严格模式,全局中的this和函数中的this都指向window

    console.log(this);
    function fn(){
    	console.log(this);
    }
    fn();
    
    • ES5严格模式,ES6全局中this仍然指向window,函数中this指向undefined

      "use strict";
      console.log(this);
      
      function fn(){
      	console.log(this);
      }
      fn();
      
    • 对象中的this

      • 对象中的函数的this指向当前对象自身obj

      • 对象中的属性中的this指向对象外this的指向(对象外上下文环境中this的指向)

        • 对象没有创建完成时,this还没有生成,this就指向对象外this的指向
        var obj={
        	a:1,
        	b:function(){
        	console.log(this);//this不会因为变量引用改变而改变
        	// this指向当前对象自身obj
        	console.log(obj.a);//变量会发生引用改变
        },
        	c:this.a
        	//this指向对象外this的指向
        	//对象没有创建完成时,this还没有生成,this就指向对象外this的指向
        }
        
    • 回调函数中的this

      • 如果直接执行的回调函数,this指向最外层的window

      • 如果通过arguments直接使用参数执行函数,this则指向执行当前函数的arguments

      • 如果回调函数通过call/apply/bind重新指向了新的对象时,this就是这个重新指向的新对象

        var obj = {
        	a: function () {
        		console.log(this,"____");
        		var self=this;
        		function fn1(fn) {
        			// fn();
        			// arguments[0]();//arguments
        			fn.call(self);
        		}
        		function fn2() {
        			console.log(this);//window 回调函数中
        		}
        		fn1(fn2);
        	},
        };
        
    • 事件中的this

      • 事件中是特殊的回调函数
      • addEventListener()侦听事件时,this指向事件的侦听对象(只要不使用箭头函数,就都是侦听对象) e.currentTarget
      • IE8,attatch()侦听事件时,this指向window
      var obj={
          b:1,
          a:function(){
              //   特殊的回调函数
              document.addEventListener("click",this.clickHandler);
          },
          clickHandler:function(e){
          	console.log(this);//事件侦听的对象 e.currentTarget
          } 
      } 
      
      var obj={
          b:1,
          a:function(){
              //   console.log(this);
              //   特殊的回调函数
              document.addEventListener("click",this.clickHandler);
              //   document.attachEvent("onclick",this.clickHandler);
          },
          clickHandler:function(e){
              console.log(this===document);//addEventListener事件侦听的对象 e.currentTarget
              console.log(this===window);//IE8 attachEvent侦听事件时,this指向window
          } 
      } 
      obj.a();
      
    • ES6类的this

      • 普通方法中,this指向被实例化的对象
      • 静态方法中是当前类名也是构造函数,静态方法中无法获取到实例化对象的this
      class Box{
          static _instance;
          constructor(){
          	console.log(this);//指向被实例化的对象
          }
          static getInstance(){
              if(!Box._instance){
              	Box._instance=new Box();
          	}
      		return Box._instance;
          }
          play(){
          	console.log(this,"|");//指向被实例化的对象
          }
          static run(){
              // console.log(this);
              console.log(this===Box,"____");
          return this;
      	}
          static plays(){
              // this.getInstance().play();
              var o=this.getInstance();
              var o1=this.getInstance();
              console.log(o===o1);
          }
      }
      
    • ES5面向对象中的this

      • 类中的this指向window或undefined
      • 面向对象方法中的this指向执行该方法的实例化对象
      • 面向对象静态发方法中的this指向该类的类名
      function Box(){
      	console.log(this);
      }
      Box.prototype.play=function(){
      	console.log(this);//this是指向执行该方法的实例化对象
      }
      
      Box.run=function(){
      	console.log(this);//Box
      }
      
      // Box();//this是window或者undefined
      var b=new Box();// this是实例化后b对象
      b.play();
      
    • 箭头函数中的this

      • this是箭头函数外this的指向
      • 上下文环境
        • 方法外的环境
        • 上下文环境中this的指向
      var obj = {
          a: function () {
              setTimeout(() => {
                  console.log(this);//this是箭头函数外this的指向
                  // 上下文环境中this的指向
              }, 2000);
          },
      };
      obj.a();
      
    • call apply bind

      • this指向绑定的参数对象
      • 如果使用call apply bind带入的参数是null,将会把this重新指向window
      var obj={
          a:function(){
               function fn(){
              	console.log(this);
              }
         		fn();
          	console.log(this);//window 如果是call apply bind 带入的是null,将会把这里的this重新指向window
          }
      }
      obj.a.call(null);
      

    // Box();//this是window或者undefined
    var b=new Box();// this是实例化后b对象
    b.play();

    
    
    
    - 箭头函数中的this
    - this是箭头函数外this的指向
    - 上下文环境
      - 方法外的环境
      - 上下文环境中this的指向
    
    ```js
    var obj = {
        a: function () {
            setTimeout(() => {
                console.log(this);//this是箭头函数外this的指向
                // 上下文环境中this的指向
            }, 2000);
        },
    };
    obj.a();
    
    • call apply bind

      • this指向绑定的参数对象
      • 如果使用call apply bind带入的参数是null,将会把this重新指向window
      var obj={
          a:function(){
               function fn(){
              	console.log(this);
              }
         		fn();
          	console.log(this);//window 如果是call apply bind 带入的是null,将会把这里的this重新指向window
          }
      }
      obj.a.call(null);
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值