美文网首页
ES5构造函数与ES6类

ES5构造函数与ES6类

作者: 仔崽06 | 来源:发表于2020-10-15 14:01 被阅读0次

    ES5

    es5并没有类class,我们只能用构造函数来模拟类.

    构造函数

    构造函数用new操作符一起使用.new具体做了以下事情.
    1.new在内存中创建了一个新的空对象.
    2.让this指向了这个对象.
    3.执行构造函数里的代码,给这个新的对象增加属性和方法.
    4.返回这个新对象,隐式return.

    //构造函数
    function Animal(){
        this.name='动物' //实例属性 
    }
    //每个创建出的实例身上都带有name属性,this指向这个实例创建的对象.
    let animal=new Animal();  
    animal.name='动物1'
    let animal1=new Animal();
    console.log(animal1.name) //动物
    
    //如果手动返回一个引用类型this就会指向这个引用类型
    function Animal(){
       this.name='动物'
       //this指向返回这个对象
       return {
           a:2
       }
    }
    
    let animal=new Animal(); //{a:2}
    console.log(animal.name) //undefined
    

    静态属性

    function Animal(){
    }
    //静态属性
    Animal.attr='12'
    //静态方法
    Animal.say=function(){
       return 11111
    }
    console.log(Animal.attr)  //12
    console.log(Animal.say()) //11111
    

    原型prototype(每个类都有prototype,是一个对象)

    function Animal(){
    }
    //公共方法 每个实例上都会带有这方法
    Animal.prototype.say=function(){
       return 'say'
    }
    Animal.prototype.attr='attr'
    
    let animal=new Animal();
    let animal1=new Animal();
    console.log(animal.say===animal1.say) //true 所有的实例都指向这个地址
    console.log(animal.say()) //say
    console.log(Animal.prototype) //Animal { say: [Function], attr: 'attr' }
    
    

    _ _proto _ _ (实例 _ _ proto _ _ 指向所属类的原型,用来查找属性和方法)

    console.log('123'.__proto__)
    console.log({}.__proto__)
    let num=123
    console.log(num.__proto__)
    let bol=true;
    console.log(bol.__proto__)
    //结果
    //[String: '']
    //{}
    //[Number: 0]
    //[Boolean: false]
    //null undefined error
    
    function Animal(){
    
    }
    
    Animal.prototype.say=function(){
       return 'say'
    }
    Animal.prototype.attr='attr'
    
    let animal=new Animal();
    console.log(animal.__proto__);// Animal { say: [Function], attr: 'attr' }  指向实例所属类的原型对象
    // 查找顺序先找自身 自身没有再去查找所属类的原型对象
    console.log(animal.__proto__===Animal.prototype); //true
    

    构造函数constructor(prototype里包含一个constructor属性)

    function Animal(){
    
    }
    let animal=new Animal()
    console.log(animal.__proto__.constructor)//[Function: Animal]
    console.log(Animal.prototype.constructor) //[Function: Animal]
    

    原理

    无标题.png

    Object.prototype

    无标题.png
    class Animal{
      
    }
    let animal=new Animal()
    console.log(Animal.prototype.__proto__===animal.__proto__.__proto__) //true
    console.log(Animal.prototype.__proto__===Object.prototype) //true
    console.log(animal.__proto__.__proto__===Object.prototype) //true
    console.log(Function.prototype.__proto__===Object.prototype) //true
    console.log(Array.prototype.__proto__===Object.prototype) //true
    console.log(Function.__proto__===Object.__proto__) //true
    console.log(Object.prototype.__proto__) //null Object已经是顶层了
    

    继承

    1.实例属性继承

    function Animal(name){
        this.name=name
    }
    
    function Tiger(){
        //this指向Tiger实例
        Animal.call(this,'老虎')
    }
    
    let tiger=new Tiger();
    console.log(tiger.name)  //老虎
    

    2.原型继承

    function Animal(name){
        this.name=name
    }
    Animal.prototype.say=function(){
        return 'say'
    }
    function Tiger(){
        //this指向Tiger实例
        Animal.call(this,'老虎')
    }
    //这种方式不可采 把Tiget的指向Animal.prototype会造成子类和父类同引用一个内存地址 子类原型改变会影响父类
    Tiger.prototype=Animal.prototype 
    
    //这样不会改变子类的原型 先从子类查找 子类查找不到再去父类原型查找 不会污染父类 可以在自己子类原型增加方法
    Tiger.prototype.__proto__=Animal.prototype
    
    let tiger=new Tiger();
    console.log(tiger.__proto__) //Tiger {}
    console.log(tiger.say()) //say
    
    

    2.1 object.create继承

    function Animal(name){
        this.name=name
    }
    Animal.prototype.say=function(){
        return 'say'
    }
    function Tiger(){
        //this指向Tiger实例
        Animal.call(this,'老虎')
    }
    //tiger.constructor指向的是父类
    Tiger.prototype=Object.create(Animal.prototype)
    //设置constructor tiger.constructor指向自己
    Tiger.prototype=Object.create(Animal.prototype,{constructor:{value:Tiger}})
    let tiger=new Tiger();
    console.log(tiger.__proto__.constructor)
    console.log(tiger.say())
    
    

    2.2 模拟object.create

    function Animal(name){
        this.name=name
    }
    Animal.prototype.say=function(){
        return 'say'
    }
    function Tiger(){
        //this指向Tiger实例
        Animal.call(this,'老虎')
    }
    function create(prototypes,constr){
        function Fn(){
    
        }
        Fn.prototype=prototypes;
        if(constr&&constr.constructor.value){
           Fn.prototype.constructor=constr.constructor.value
        }
        return new Fn()
    }
    
    Tiger.prototype=create(Animal.prototype,{constructor:{value:Tiger}});
    Tiger.prototype.say=function(){
        return 'Tiger say'
    }
    let tiger=new Tiger();
    console.log(tiger.__proto__.constructor) //[Function: Tiger]
    console.log(tiger.say()) // Tiger say
    console.log(Animal.prototype.say()) //say
    
    

    object.create实现原理

    无标题.png

    es6类(class)

    class Animal{
    
    }
    let animal=new Animal();
    console.log(animal)
    

    静态属性(通过类自身调用)

    class Animal{
       static attrs='attrs'
       static say(){
           return 'say'
       }
    }
    console.log(Animal.attrs) //attrs
    console.log(Animal.say()) //say
    
    class Animal{
        static attrs='attrs'
        constructor(){}
        say(){
            return 'say'
        }
        
    }
    class Tiger extends Animal{
       constructor(){
    
       }
    }
    
    console.log(Tiger.attrs) //attrs
    

    实例属性

    //没有写contructor情况下 增加属性 会默认执行constructor把属性添加到实例上
    class Animal{
        attrs='attrs'   // 注意!!这里定义的不是在prototype上的属性,而是给实例初始化的 实例属性
    }
    
    let animal=new Animal();
    console.log(animal.attrs)
    
    
    class Animal{
       constructor(){
           this.attrs='attrs'  //实例属性
       }
    }
    
    let animal=new Animal();
    console.log(animal.attrs)
    

    prototype(定义在类里 es6的原型是不可枚举的)

    class Animal{
        constructor(){}
        say(){
            return 'say'
        }
        
    }
    let animal=new Animal();
    console.log(Animal.prototype.say) //[Function: say]
    

    私有属性(ES2020实验草案中,增加定义私有类字段功能,使用# ,私有属性无法在类的外部调用)

    //私有属性
    class Animal{
         #privateValue="私有"
    }
    
    //私有方法
    class Animal{
         #privateValue(){
            return 'private'
         }
    }
    //私有静态属性
    class Animal{
        statci  #privateValue="私有"
    }
    //可以在类的内部使用,无法在类的外部使用
    
    calss Animal{
        #attrs='11111'
        #bac(){
            Animal.#attrs="22222"
        }
    }
    
    console.log(Animal.#bac) //error
    

    继承(extexds)

    //子类不写constructor会默认执行父类的constructor
    class Animal{
        constructor(attrs){
           this.attrs=attrs
        }
        say(){
            return 'say'
        }
    }
    
    class Tiger extends Animal{
    
    }
    
    let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
    console.log(tiger.__proto__.say) //[Function: say]
    
    //子类写constructor,默认走子类的构造函数
    class Animal{
        constructor(attrs){
           this.attrs=attrs
        }
        say(){
            return 'say'
        }
    }
    
    class Tiger extends Animal{
       constructor(attrs){
          super(attrs)  //等同于 Animal.call(this,attrs) 不调用super会报错
       }
    }
    
    let tiger=new Tiger('tiger attrs');
    console.log(tiger) //Animal { attrs: 'tiger attrs' }
    console.log(tiger.__proto__.say) //[Function: say]
    
    //子类和父类定义相同的方法,会先执行子类 子类没有才会向类查找
    class Animal{
        constructor(attrs){
           this.attrs=attrs
        }
        say(){
            return 'say'
        }
    }
    
    class Tiger extends Animal{
       constructor(attrs){
          super(attrs)  //等同于 Animal.call(this,attrs)
       }
       say(){
           return 'tiger say'
       }
    }
    
    let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
    console.log(tiger.say()) // tiger say
    
    //子类调用父类方法
    class Animal{
        constructor(attrs){
           this.attrs=attrs
        }
        say(){
            return 'say'
        }
    }
    
    class Tiger extends Animal{
       constructor(attrs){
          super(attrs)  //等同于 Animal.call(this,attrs)
       }
       say(){
           return super.say()  //等用于 Animal.prototype.say()  //super===Animal.prototype
       }
    }
    
    let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
    console.log(tiger.say()) //say
    
    //静态方法调用
    class Animal{
        constructor(attrs){
           this.attrs=attrs
        }
        static say(){
            return 'say'
        }
    }
    
    class Tiger extends Animal{
       constructor(attrs){
          super(attrs)  //等同于 Animal.call(this,attrs)
       }
       static say(){
           return super.say()  //super等用于Animal类  //super===Animal
       }
    }
    
    console.log(Tiger.say()) //say
    

    抽象类(只可继承,不可被实例化new)

    1.new.target实现抽象类

    class Animal{
        constructor(){
            //执行两次 1.new.target=[Function: Animal] 2.new.target[Function: Tiger]
            if(new.target===Animal){
                throw new Error('not new')
            }
        }
    }
    
    class Tiger extends Animal{
    
    }
    new Animal()  //Error: not new
    let tiger=new Tiger();
    

    es5构造函数模拟实现es6(原型属性不可枚举)

    function handleConstructor(Constructor,protoProperties){
        for(let i=0;i<protoProperties.length;i++){
            let property=protoProperties[i]
            Object.defineProperty(Constructor,property.key,{
                 //是否可以删除
                 configurable:true,
                 //是否可以枚举
                 enumerable:false,
                 ...property
            })
        }
    }
    
    // console.log(Eat.prototype) //不可枚举
    function definePrototype(Constructor,protoProperties,staticPorto){
        if(Array.isArray(protoProperties)){
           handleConstructor(Constructor.prototype,protoProperties)
        }
        if(Array.isArray(staticPorto)){
            handleConstructor(Constructor,staticPorto)
        }
    }
    
    
    //es5的类 模拟es6的类 不可枚举 Object.definprototype
    let Animate=(function(){
        function Animate(){
             if(!(this instanceof Animate)){
                 throw new Error('not new')
             }
        }
        //改变原型不可枚举  babel编译出es6的类就是这样写的
        definePrototype(Animate,[
            {
                key:'say',value:function(){
                    console.log('say')
                }
            }
        ],[
            //静态属性
           {
                key:'eat',value:function(){
                   return 'eat'
                }
            }
        ])
        return Animate
    })()
    
    console.log(Animate) //[Function: Animate]
    console.log(Animate.prototype) //Animate {}
    console.log(Animate.eat()) //eat
    

    instanceof

    instanceof运算符是用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上.

    //obj instanceof Object 检测Object.prototype是否存在与参数obj的原型链上.
    function Person(){}
    let p=new Person();
    //p.__proto__==Person.prototype
    console.log(p instanceof Person) //true
    

    hasOwnProperty()操作符

    hasOwnProperty检查一个属性是否是实例属性.

    //实例属性
    function Animal(){
        this.name='name'
    }
    
    let animal=new Animal();
    console.log(animal.hasOwnProperty('name')) //true
    
    //不查看原型属性,只看实例属性
    function Animal(){
        
    }
    Animal.prototype.name='123'
    
    let animal=new Animal();
    console.log(animal.hasOwnProperty('name')) //false
    

    in操作符

    有两种方法能使用in操作符:单独使用for-in循环使用.在单独使用时,in操作符会通过对象能够访问给定属性返回true,无论属性存在(实例)还是(原型中).

    function Animal(){
        this.name='name'
    }
    
    let animal=new Animal();
    console.log('name' in  animal) //true
    
    function Animal(){
        
    }
    Animal.prototype.name='123'
    
    let animal=new Animal();
    console.log('name' in  animal) //true
    
    function Animal(){
        
    }
    let animal=new Animal();
    console.log('name' in  animal) //false
    

    相关文章

      网友评论

          本文标题:ES5构造函数与ES6类

          本文链接:https://www.haomeiwen.com/subject/jecwpktx.html