原型和原型链

45 阅读2分钟

构造函数

什么是构造函数?

    var obj = new Object();     
    obj.name = 'abc';    

上面是创建对象的一种方法 其中Object是系统自带构造函数创建

  • 构造函数的本质就是一个函数
  • 命名规范 首字母大写
  • 默认返回this(也就是新的实例对象)
  • 用new关键字调用

构造函数内部原理

    function Student(name,age) {
        // var this ={
        //      _proto_ : Student.prototype   
        //};
        this.name = name;
        this.age = age;
        // return this;  隐式的返回this
    }
    console.log(new Student('xiaowang',180).age)    // 180

注释的内容皆是系统在构造函数中所发生的隐式的代码行为

自定义构造函数

        function myObj (name){
            this.name = name
        }
        const obj = new myObj('我是构造函数new出来的对象')
        console.log(obj);       //myObj {name: '我是构造函数new出来的对象'}    

原型

原型是什么?

原型是每个函数天生自带的一个对象空间,叫作prototype,一开始这个对象中只存放了指向构造器的属性 constructor: ƒ

        console.log(myObj.prototype);   //  {constructor: ƒ}
        console.log(myObj.prototype.constructor);   //function myObj (name)

原型的作用(为什么需要它?)

通过构造函数和new关键字,我们可以创建多个具有相同属性和方法的对象,如果我们将对象的方法写在构造函数中,会导致每个实例化的对象中的方法都会开辟一个新的内存空间来存放该函数方法(堆内存地址不同)。

        function myObj (name){
            this.name = name
            this.sayHi = ()=>{
                console.log('hi');
            }
        }
        const obj1 = new myObj('我是实例化对象1')
        const obj2 = new myObj('我是实例化对象2')
        console.log(obj1.sayHi===obj2.sayHi);   // false

而通过原型,就可以让实例化的每个的对象中的每个方法属性都指向同一块堆内存,极大的减少了内存的占用,并且弥补了构造函数创建对象的缺陷

        function myObj (name){
            this.name = name
        }
        myObj.prototype.sayHi = function () {
            console.log('hi');
        }
        const obj1 = new myObj('我是实例化对象1')
        const obj2 = new myObj('我是实例化对象2')
        console.log(obj1.sayHi===obj2.sayHi);   // true

结论:当我们写构造函数时,属性写在构造函数中,将方法写在原型上

原型链

为什么需要原型链

为了实现继承,简化代码,实现代码重用

如何实现

原理:让一个子类的原型存放一个指向父类实例化对象的地址,利用实例化对象可以调用原型中的方法,将父子类关联起来 es5实现:

        function People (type){
            this.type = type
        }
        People.prototype.eat = function(){
            console.log(`${this.type}在吃东西`);
        }
        function Student (name){
            this.name = name
        }
        Student.prototype = new People('人类')
        Student.prototype.sayhi = ()=>{
            console.log('hi');
        }
        const xialuo = new Student('夏洛')
        xialuo.number = 100
        xialuo.eat();   //人类在吃东西
        xialuo.sayhi()  //hi
        console.log(xialuo);    //Student {name: '夏洛', number: 100}

原型链.png

es6 实现:

        class People {
            constructor(type) {
                this.type = type
            }
            eat(){
                console.log(`${this.type}在吃东西`);
            }
        }
        class Student extends People{
            constructor(name){
                super('人类')
                // 调用父类的方法
                super.eat()     //人类在吃东西
                this.name = name
            }
            sayhi(){
                console.log('hi');
            }
        }
        const xialuo = new Student('夏洛')
        xialuo.number = 100
        xialuo.sayhi()      //hi
        console.log(xialuo);   //Student {type: '人类', name: '夏洛', number: 100}