工廠方法、建構函式、原型物件——JS基礎學習筆記(四)

梭梭醬加油鴨發表於2019-02-17

案例一:使用工廠方法建立物件

function createPerson(name,age,gender){
    //建立一個新物件
    var obj = new Object();
    //向物件新增屬性
    obj.name = name;
    obj.age = age;
    obj.gender = gender;
    obj.sayName = function(){
        alert(this.name);
    };
    //將新的物件返回
    return obj;
}

var obj2 = createPerson("豬八戒",28,"男");
var obj3 = createPerson("白骨精","16","女");
var obj4 = createPerson("蜘蛛精","18","女");

obj3.sayName();

複製程式碼

建構函式的執行流程

  1. 立刻建立一個新的物件
  2. 將新的物件設定為函式中this,在建構函式中可以使用this來引用新建的物件
  3. 逐行執行函式中的程式碼
  4. 將新建的物件作為返回值返回

使用同一個建構函式建立的物件,我們稱為一類物件,也將一個建構函式稱為一個類。比如如下的Person和Dog就是兩個類。

通過一個建構函式建立的物件叫做該建構函式的一個例項。

案例二:使用建構函式建立物件

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

function Dog(){
    
}
    
var per = new Person("孫悟空",18,"男");
var per2 = new Person("白骨精",16,"女");
var per3 = new Person("蜘蛛精",18,"女");

var dog = new Dog();

console.log(per);//Person……
console.log(dog);//Dog

//使用instanceof可以檢查一個物件是否是一個類的例項,如果是則返回true。
console.log(per instanceof Person);//true

console.log(dog instanceof Object);//true所有通過建構函式建立的物件都是Object類的例項,都是true
複製程式碼

關於this

  1. 當以函式形式呼叫時,this是window
  2. 當以方法形式呼叫時,誰呼叫this就是誰
  3. 當以建構函式形式呼叫時,this就是新建立的那個物件。

建構函式的優化

//建構函式每執行一次就會建立一個新的sayName方法,也就是所有例項的sayName都是唯一的。這就導致建構函式每執行一次,就會建立一次方法。

function Person(name , age , gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.sayName = fun;
}
    
function fun(){
        alert("Hello大家好,我是:"+ this.name);
    }
var per = new Person("孫悟空",18,"男");
var per2 = new Person("豬八戒",16,"女");

console.log(per.sayName==per2.sayName);
//得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。
複製程式碼

原型物件

我們所建立的每一個函式,解析器都會向函式中新增一個屬性prototype,這個屬性對應著一個物件,這個物件就是我們所謂的原型物件。

如果函式作為普通函式呼叫,prototype沒有任何作用。

當函式以建構函式的形式被呼叫時,它所建立的物件中都會有一個隱含的屬性,指向該建構函式的原型物件,我們可以通過__prto__來訪問該屬性。

工廠方法、建構函式、原型物件——JS基礎學習筆記(四)

原型物件就相當於一個公共的區域,所有同一個類的例項都可以訪問這個原型物件,我們可以將物件中共有的餓內容,統一設定到原型物件中。

當我們訪問物件的一個屬性或方法時,它會先在物件自身中尋找,如果有則直接使用,如果沒有則會去原型物件中尋找,如果找到則直接使用。

建立建構函式時,可以將那些物件共有的屬性和方法,統一新增到建構函式的原型物件中,這樣不用分別為每一個物件新增,也不會影響到全劇作用域。

function MyClass(){
    
}

//向MyClass原型中新增屬性a
MyClass.prototype.a = 123;

//向MyClass原型中新增一個方法
MyClass.prototype.sayHello = function(){
    alert("hello");
};

var mc = new MyClass();

var mc2 = new MyClass();

//console.log(MyClass.prototype);
//console.log(mc2.__proto__ == MyClass.prototype);

//向mc新增a屬性
mc.a = "我是mc中的a";

//console.log(mc2.a);這裡的結果就不是123了,因為mc2物件本身有一個a屬性,所以不再向建構函式的原型物件查詢

mc.sayHello();
複製程式碼
function Person(name , age , gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
    //this.sayName = fun;
}

//將sayName方法在全劇作用域中定義
/*將函式定義在全域性作用域,汙染了全域性作用域的名稱空間,而且也不安全*/

/* function fun(){
        alert("Hello大家好,我是:"+ this.name);
    };*/
    
//向原型中新增sayName方法
Person.prototype.sayName = function(){
        alert("Hello大家好,我是:"+ this.name);
    };
var per = new Person("孫悟空",18,"男");
var per2 = new Person("豬八戒",16,"女");
per.sayName();//Hello大家好,我是:孫悟空
per2.sayName();//Hello大家好,我是:豬八戒

console.log(per.sayName==per2.sayName);
//得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。
複製程式碼

toString方法

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

//修改Person原型的toString
Person.prototype.toString = function(){
    return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
}

//建立一個Person例項
var per = new Person("孫悟空",18,"男");
var per2 = new Person("豬八戒",16,"女");

//當我們直接在頁面中列印一個物件時,實際上是輸出的物件的toString()方法的返回值
//如果我們希望在輸出物件時,不輸出[object object],可以為物件新增一個toString()方法
/*per.toString = function(){
    return "我是一個快樂的人";
};*/

//var result = per.toString();
//console.log("result = " + result);
//console.log(per.__proto__.__proto__hasOwnProperty("toString"));
console.log(per);


console.log(per.sayName==per2.sayName);
//得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。

相關文章