美文网首页
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 继承比较:

    ES5构造函数和继承: ES6构造函数和继承:

  • Js 中的类

    ES5中,使用构造函数是这样的: ES6中,构造函数 上面中constructor就是构造方法。注意定义类的方法时...

  • JS基础:面向对象编程

    目录一. 类与对象 1. ES5里的构造函数(constructor)与对象的生成 2. ES6里的类(class...

  • es5实现class类

    es5没有类,只有构造函数。ES6新增了class,用于创建类。本文通过es5来实现es6的class(一个Ani...

  • ES6 的知识点学习笔记(2) - class 静态方法 继承

    在之前的 ES5 中, 是没有类 (class) 的概念的,例子: ES5 构造函数 Person ES6 cla...

  • ES6——类(Class)

    ES5关于类 JavaScript 语言中,生成实例对象的传统方法是通过构造函数。 ES6关于类 ES6 提供了更...

  • ES的类与继承

    ES5中的类与继承 构造函数继承,原型继承,组合式继承 静态方法,静态属性,实例方法,实例属性 ES6中的类与继承...

  • js 中的类

    ES5 中定义一个类 ES6以后的语法(可以看做是ES5的语法糖) ES6 的类,完全可以看作构造函数的另一种写法...

  • 26- class 类与继承

    1、ES5 中基于原型的构造函数 2、ES6 的 class关键字 ES6 引入了 Class(类)这个概念,作为...

  • ES6 类和ES5 构造函数

    ES5的构造函数和ES6的Class区别 ES5的构造函数的原型上的属性和方法可以遍历/ES6 不能够遍历 ES6...

网友评论

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

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