JavaScript創(chuàng)建對象方式及性能問題

通過Object構(gòu)造函數(shù)或者字面量創(chuàng)建對象

    var obj01 = new Object();
    var obj02 = {};
  • 弊端:無論通過Object來創(chuàng)建對象, 還是通過字面量來創(chuàng)建對象都存在一個弊端,每次創(chuàng)建都需要重新編寫一次, 如果創(chuàng)建的多個對象的屬性和方法名稱一樣,浪費時間

通過工廠函數(shù)創(chuàng)建對象

//所以我們可以通過工廠函數(shù)來創(chuàng)建對象
     */
    // 工廠函數(shù)
    function createPerson(name, age) {
        // 1.通過Object創(chuàng)建一個空對象
        // var obj = new Object();
        var obj = {};
        // 2.動態(tài)的給空對象添加屬性和方法
        obj.name = name;
        obj.age = age;
        obj.say = function () {
            console.log("hello");
        };
        // 3.將函數(shù)中創(chuàng)建的對象返回給調(diào)用者
        return obj;
    }
    var obj1 = createPerson("luodou", 13);
    var obj2 = createPerson("doudou", 18);
    console.log(obj1);
    console.log(obj2);

    console.log(typeof obj1); // object
    console.log(obj1.constructor); // ? Object() { [native code] }
  • 工廠函數(shù)實質(zhì)上是Object或字面量創(chuàng)建對象的封裝,調(diào)用函數(shù)即可創(chuàng)建對象
  • 弊端:通過Object對象, 或者通過字面量, 或者通過工廠函數(shù)創(chuàng)建的對象, 我們無法判斷這個對象是誰創(chuàng)建出來的,代碼最后一行constructor指向的是一個Object

通過構(gòu)造函數(shù)創(chuàng)建對象

  • 什么是構(gòu)造函數(shù)?

    • 構(gòu)造函數(shù)也是一個函數(shù), 只不過是專門用于創(chuàng)建對象的函數(shù)而已
  • 構(gòu)造函數(shù)和普通函數(shù)的區(qū)別?

    • 構(gòu)造函數(shù)的函數(shù)名稱首字母必須大寫
    • 構(gòu)造函數(shù)必須使用new 來調(diào)用
  • 構(gòu)造函數(shù)本質(zhì)上是對工廠函數(shù)的簡化

    • 在構(gòu)造函數(shù)中默認(rèn)會創(chuàng)建一個空的對象, 會將創(chuàng)建的對象賦值給this,會將創(chuàng)建的對象返回給調(diào)用者
  • 過去通過Object對象, 或者通過字面量, 或者通過工廠函數(shù)創(chuàng)建的對象, 我們無法判斷這個對象是誰創(chuàng)建出來的,但是通過構(gòu)造函數(shù)創(chuàng)建的對象, 我們可以判斷這個對象是誰創(chuàng)建出來的(見代碼里obj.constructor)

  • 默認(rèn)情況下每一個對象都有一個隱藏的屬性, 叫做constructor, 這個屬性指向了創(chuàng)建當(dāng)前對象的構(gòu)造函數(shù)

    // 1.自定義一個構(gòu)造函數(shù)
    function Person(name, age) {
        // 1.var obj = new Object();
        // 2.this = obj;
        this.name = name; // obj.name = name;
        this.age = age;
        this.say = function () {
            console.log("hello");
        }
        // 3.return obj;
    }
    /*
    new Person("luodou", 13);做了什么事情?
    1.會在構(gòu)造函數(shù)中創(chuàng)建一個空的對象
    2.將創(chuàng)建好的空對象賦值給this
    3.將創(chuàng)建好的對象返回給調(diào)用者
     */
    var obj = new Person("luodou", 13);
    console.log(obj);

    console.log(typeof obj); // object
    console.log(obj.constructor); // ? Person(name, age) {}

    // 判斷obj對象是否是Person構(gòu)造函數(shù)創(chuàng)建出來的
    // console.log(obj.constructor === Person); // 不推薦

    // 如果想判斷某個對象時候是某個構(gòu)造函數(shù)創(chuàng)建出來的
    // 可以使用 對象名稱 instanceof 構(gòu)造函數(shù)名稱, 來判斷
    console.log(obj instanceof Person); // true


    function Student(name, age, score) {
        this.name = name; // obj.name = name;
        this.age = age;
        this.score = score;
    }
    var obj2 = new Student("dou", 11, 99);
    console.log(obj2 instanceof Person);  //false
    console.log(obj2 instanceof Student); //true
  • 弊端:默認(rèn)情況下, 只要創(chuàng)建一個對象就會在對象中開辟一塊存儲空間,該存儲空間中會存儲對象的所有數(shù)據(jù),浪費空間
    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.say = function () {
            //           obj1.name, obj1.age
            //           obj2.name, obj2.age
            console.log(this.name, this.age);
        };
    }
    var obj1 = new Person("lnj", 13);
    obj1.say();

    var obj2 = new Person("zq", 18);
    obj2.say();

    // 這里的===是在判斷兩個函數(shù)的地址是否相同
    console.log(obj1.say === obj2.say);  //false
  • 解決方案:
    • 將方法定義在外面, 將定義在外面函數(shù)的地址賦值給屬性,每次創(chuàng)建對象, 對象中say保存的都是函數(shù)的地址, 就不會重復(fù)保存了
    /*
    注意點: 在JavaScript中, 函數(shù)也是一個對象
     */
    function say() {
        console.log(this.name, this.age);
    }
    // var say = function () {
    //     console.log(this.name, this.age);
    // };
    // var say = new Function("console.log(this.name, this.age);");

    // 定義了一個構(gòu)造函數(shù)
    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.say = say;
    }

    var obj1 = new Person("luodou", 13);
    obj1.say();

    var obj2 = new Person("dou", 18);
    obj2.say();

    // 這里的===是在判斷兩個函數(shù)的地址是否相同
    console.log(obj1.say === obj2.say); // true
  • 弊端:因為將函數(shù)定義在了全局作用域中, 所以如果定義了多個函數(shù), 會導(dǎo)致全局作用域的名稱匱乏

  • 解決方案2.0

    • 將所有函數(shù)都封裝到另外一個對象中, 這樣函數(shù)名稱就不在全局作用域中了, 這就不會導(dǎo)致全局作用域命名匱乏問題了,然后將對象中方法的地址復(fù)制給使用者即可
    var fns = {
        say: function() {
            console.log(this.name, this.age);
        },
        eat: function () {
        console.log("eat");
        }
    };

    // 定義了一個構(gòu)造函數(shù)
    function Person(name, age) {
        this.name = name;
        this.age = age;

        this.say = fns.say;
        this.eat = fns.eat;
    }

    var obj1 = new Person("luodou", 13);
    obj1.say();

    var obj2 = new Person("dou", 18);
    obj2.say();

    // 這里的===是在判斷兩個函數(shù)的地址是否相同
    console.log(obj1.say === obj2.say); // true

終極解決方案

前面的通通忘掉!

  • 在JavaScript中,每一個構(gòu)造函數(shù)都有一個默認(rèn)的屬性, 這個屬性叫做prototype,prototype屬性指向一個對象, 這個對象我們稱之為構(gòu)造函數(shù)的原型對象

  • 既然構(gòu)造函數(shù)的prototype就對應(yīng)一個對象, 所以我們就可以將方法都放到這個對象中

  • 注意點:所有通過同一個構(gòu)造函數(shù)創(chuàng)建出來的對象, 都可以訪問該構(gòu)造函數(shù)的原型對象,并且所有通過同一個構(gòu)造函數(shù)創(chuàng)建出來的對象, 訪問的都是同一個原型對象

    // 定義了一個構(gòu)造函數(shù)
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    /*
    私有成員(一般就是非函數(shù)成員)放到構(gòu)造函數(shù)中
    共享成員(一般就是函數(shù))放到原型對象中
    如果重置了 prototype 記得修正 constructor 的指向
     */
    Person.prototype.say = function () {
        console.log(this.name, this.age);
    };

    // console.log(Person.prototype);

    var obj1 = new Person("luodou", 13);
    obj1.say();

    var obj2 = new Person("dou", 18);
    obj2.say();

    // 這里的===是在判斷兩個函數(shù)的地址是否相同
    console.log(obj1.say === obj2.say); // true
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容