构造函数创建对象带来的问题

上一篇文章介绍了JavaScript创建对象的几种方法,都有各自的优缺点。
构造函数看起来好像很好,但是它也有一个问题,那就是创建出来的每一个实例对象的方法都是一个独立的函数,即使他们的内容是完全相同的,这是不符合函数的代码复用原则的,而且也不能够统一的修改已被创建的实例的方法。

    function Person(name, age, sex) {
        this.name = name;
        this.age  = age;
        this.sex  = sex;
        
        this.introduce = function () {
            console.log("我叫" + this.name + ", 今年" + this.age + "岁.");
        };
    }
    
    var jerry = new Person("Jerry", "21", "M");
    var julia = new Person("Julia", "27", "F");

    console.log(jerry.introduce === julia.introduce);        // false

上述代码中的jerry对象和julia对象的introduce()方法是两个独立的函数,数据不共享,如果对象创建更多就浪费了大量的内存空间。

JavaScript原型解决方案

在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个 prototype 属性,这个属性指向函数的原型对象。

那么,这个原型对象有什么作用呢?
构造函数是一个函数对象,所以就会有一个 prototype 属性,也就有了一个原型对象,既然这是一个对象,那么久可以为它添加属性和方法。而这个原型对象作为这个构造函数的一个属性,是被其创建出来的所有实例共享的。

所以上面的代码我们可以这样改写

    function Person(name, age, sex) {
        this.name = name;
        this.age  = age;
        this.sex  = sex;
    }

    Person.prototype.introduce = function () {
        console.log("我叫" + this.name + ", 今年" + this.age + "岁.");
    };

    var jerry = new Person("Jerry", "21", "M");
    var julia = new Person("Julia", "27", "F");

    console.log(jerry.introduce === julia.introduce);        // true

这样就解决了数据共享的问题,达到了代码复用的目的,无论通过此构造函数创建了多少个对象,introduce 方法只会占用一份内存空间。
且可以统一修改所有 Person 构造函数创建的实例对象的 introduce 方法。

原型对象中的方法是可以相互调用的

    function Dog(name, age) {
        this.name = name;
        this.age = age;
    }

    Dog.prototype.play = function () {
        console.log("小狗玩耍");
        this.bark();
    };

    Dog.prototype.bark = function () {
        console.log("小狗叫");
    };

    var tom = new Dog("Tom", 3);
    
    tom.play();// 小狗玩耍    小狗叫

普通小猪
4 声望0 粉丝

「Stay hungry. Stay foolish.」