運用 new 操作符內部到底在做什麼

從對象聲明最先一步步引見

1.一般對象聲明

起首建立自定義對象的最簡樸體式格局就是建立一個Object的實例,然後在為他們增加屬性和要領,以下所示:

var person = new Object();        //建立對象
person.name = "Nicholas";        //增加屬性
person.age = 29;
person.job = "teacher";
person.sayName = function(){    //增加要領
    return this.name
};

this的寄義:

  1. this示意當前作用域下的對象;
  2. this示意new Object()實例化出來的誰人對象;
  3. this要放在一個作用域下,比方person.sayName()person下的要領,可用this示意要領自身。

瑕玷:要建立一個相似的對象會發生大批的代碼。

為了處理多個相似聲明的題目,用一種工場形式,這類要領是為了處理實例化對象發生大批反覆的代碼。

2.工場形式

用函數來封裝以特定接口建立對象的細節。

function createPerson(name,age,job){    //建立對象
    var obj = new Object();                //增加屬性
    obj.name = name;
    obj.age = age;
    obj.job = job;
    obj.sayName = function(){            //增加要領
        return this.name
    };
    return obj;                            //返回對象援用
}

var person1 = createPerson("Zhangsan",29,"Teacher");    //實例化第一個對象
var person2 = createPerson("Lisi",34,"Doctor");        //實例化第二個對象
console.log(person2 instanceof Object)        //true

this的寄義:
1.thisnew Object(),實例化出來的誰人對象;
2.this要放在一個作用域下,比方obj.sayName(){},這是obj作用域下的的要領,能夠用this來示意obj自身。

瑕玷:集合實例化函數,處理了大批反覆的代碼;從上面例子我們能夠看出sayName是共有屬性,而我們每實例化一個函數都邑建立sayName,這也形成了反覆。

3.組織函數形式

組織函數可用來建立特定範例的對象,相似Object範例。

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        return this.name
    };
}

function Person2(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        return this.name
    };
}

var person1 = new Person("Zhangsan",29,"Teacher");
var person2 = new Person("Lisi",34,"Doctor");    
var person3 = new Person2("Wangwu",34,"Police");

alert(person1 instanceof Person);        //true,person1從屬於Person
alert(person2 instanceof Person);        //true,person2從屬於Person
alert(person3 instanceof Person2);        //true,person3從屬於Person2
alert(person1 instanceof Person2);        //false,由於這裏person1是從屬於Person

alert(person1.sayName() == person2.sayName());    //true,組織函數的要領的值是想等的
alert(person1.sayName == person2.sayName);    //false,比較的是援用地點

我們運用new操作符,究竟是在做什麼

  1. 不必建立暫時對象,由於 new 會幫你做(你運用「this」就能夠接見到暫時對象);
  2. 不必綁定原型,由於 new 會幫你做(new為了曉得原型在哪,所以指定原型的名字為 prototype);
  3. 不必 return 暫時對象,由於 new 會幫你做;
  4. 不要給原型想名字了,由於 new 指定名字為 prototype。
  5. persen1 和 person2 的 constructor 屬性都指向 Person

瑕玷:每次實例化 Person,共有屬性 sayName 都邑反覆建立,和工場形式題目一樣。

3.1把要領移動到組織函數外部

把 sayName 要領移至 Person 表面,如許每次實例化 Person 內部的 sayName 只是全局 sayName 的援用,如許避免了反覆。

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

function sayName(){            //把組織函數內部的要領經由過程全局來完成,援用地點一致
    return this.name
}

var person1 = new Person("Zhangsan",29,"Teacher");
var person2 = new Person("Lisi",34,"Doctor");    

瑕玷:

  1. 全局 sayName 函數和 Person 之間聯絡不嚴密,假如它們中心有許多代碼,sayName 就不曉得是幹嗎用的了;
  2. 假如要領許多,每一個都是全局函數,就沒封裝可言了;
  3. 用全局函數很輕易掩蓋全局變量。

4.原型形式

運用原型對象的優點是能夠讓一切對象實例同享它所包括的屬性和要領。

  1. 假如是實例要領,差別的實例化,它們的要領和地點是不一樣的,是唯一的;
  2. 假如是原型要領,那它們的地點是同享的,人人都一樣。
function Person(){}        //組織函數什麼體內什麼都沒有,假如有叫做實例要領,氣力屬性

Person.prototype.name = "Zhangsan";
Person.prototype.age = 29;
Person.prototype.job = "Teacher";
Person.prototype.sayName = function(){
    return this.name
};

var person1 = new Person();
person.sayName()     //Zhangsan

var person2 = new Person();
person.sayName()     //Zhangsan

alert(person1.sayName === person2.sayName);    //true

瑕玷:反覆敲Person.prototype,形成大批的反覆輸入。

4.1字面量體式格局建立原型

function Person(){}//運用字面量的體式格局建立原型對象,這裏的`{}`就是對象,是`Object`,`new Object`相當於`{}`

Person.prototype = {
    constructor:Person,    //強行指向實例
    name: "Zhangsan",
    age: 29,
    job: "Teacher",
    sayName: function(){
        return this.name
    }
};

var person = new Person();

注重:

  1. 實例化后重寫原型對象,會割斷現有實例和新原型之間的聯絡
  2. 不能重寫原型中的屬性,如 person.name = ‘Lisi’,它會變成 person 的實例屬性。

瑕玷:constructor不在指向實例,而會指向Object。新對象的constructor重寫Person本來的constructor,因此會指向新對象。
處理要領:在原型內部,能夠設置constructor強行實行實例。

4.2組合組織函數形式和原型形式

組織函數形式用於定義氣力屬性,原型形式用於定義要領和同享屬性

function Person(name,age,job){        //堅持自力的運用組織函數
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Xiaoming","Fangfang"];
}

Person.prototype = {        //保留同享的運用原型
    constructor: Person,
    sayName: function(){
        return this.name
    }
}

var person1 = new Person("Zhangsan",29,"Teacher");
var person2 = new Person("Wangwu",34,"Doctor");

person1.friends.push("Xiaohong");
alert(person1.friends);    //"Xiaoming,Fangfang,Xiaohong"
alert(person2.friends);    //"Xiaoming,Fangfang",援用範例沒有運用原型,所以沒有同享
alert(person1.friends == person2.friends);    //false
alert(person1.sayName == person2.sayName);    //true

注重:實例化的私有屬性是自有的

5.動態原型形式

動態原型形式,把一切信息都封裝在了組織函數中。

function Person(name,age,job){        //堅持自力的運用組織函數
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Xiaoming","Fangfang"];
    
    if(typeof this.sayName != "function"){    //僅在第一次時初始化
        Person.prototype.sayName = function(){
            console.log(this.name);
        };
    }
}

原型的初始化,只需第1次初始化,就能夠了,沒必要每次組織函數實例化的時刻都初始化,能夠將原型封裝在函數里。
注重:運用動態原型形式時,不能運用對象字面量重寫原型。假如在已建立了實例的情況下重寫原型,那末就會割斷現有實例與新原型之間的聯絡。

proto 和 prototype

__proto__:是實例化后的原型屬性
prototype:是 JS 內部供應的原型屬性

上面例子中
person1.__proto__ === Person.prototype
person1.__proto__.__proto__ === Object.prototype

之前寫過一篇文章論述它們之間的差別:前端進修筆記之原型——一張圖申明prototype__proto__的區分

    原文作者:UCCs
    原文地址: https://segmentfault.com/a/1190000014560330
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞