一塊兒學習面向對象——封裝

構造函數內部:

tips:

在構造函數內部經過this(用於指向當前對象)變量添加屬性或方法,
此處定義的屬性和方法都是爲對象自身所擁有,
每次經過類建立實例時, this指向的屬性都會獲得相應的建立.安全

var Person = function(name, sex) {
    // 私有屬性: 只能被【私有方法】和【特權方法】訪問
    var contact = 'xxxxx@qq.com';
    var number = '88888888';

    // 私有方法: 在構造函數裏聲明, 能被【私有函數】【特權方法】訪問, 只能訪問【私有方法】和【私有屬性】
    var getInfo = function(name, sex) {
        console.log('My name is ' + name + ', I’m a ' + sex + '!');
        console.log('My email is ' + contact);
    };

    // 公有屬性
    this.name = name;
    this.sex = sex;

    // 特權方法: 能夠訪問【私有屬性】【私有方法】【公有屬性】
    this.intro = function() {
        getInfo(name, sex);
    };
    this.getContact = function(number) {
        console.log(number);
    };

    // 構造器
    this.getContact(number);
};

構造函數外部:

tips:

經過點語法定義的屬性和方法不會添加到新建立的對象,所以類的實例沒法訪問, 只能經過類的自身(Person)訪問.閉包

// 類靜態公有屬性(對象不能訪)
Person.isChinese = true;

// 類靜態公有方法(對象不能訪問到)
Person.speak = function() {
    console.log('what???');
};

類的原型:

tips:

一種是爲原型對象屬性賦值, 另外一種是將一個對象賦值給類的原型對象.
經過prototype繼承的屬性或方法是每一個對象經過prototype訪問到的,
因此每次經過類建立實例時, 這些屬性和方法不會再次建立.函數

Person.prototype = {
    // 顯示指定對象的constructor屬性
    constructor: Person,
    // 公有屬性
    hobby: 'reading',
    // 公有方法
    sport: function() {
        console.log('run');
    }
};

// test:
var tony = new Person('Tony', 'man', '25');

console.log('--- 訪問【公有屬性】 ---');
console.log(tony.name);            // Tony
console.log(tony.sex);            // man

console.log('--- 訪問【特權方法】 ---');
console.log(tony.intro());        // My name is Tony, I’m a man!
                                // My email is xxxxx@qq.com

console.log('--- 訪問【類靜態公有屬性】和【類靜態公有方法】 ---');
console.log(tony.isChinese);     // undefined
console.log(tony.speak());        // undefined

console.log('--- 經過類自身訪問【類靜態公有屬性】和【類靜態公有方法】 ---');
console.log(Person.isChinese);    // true
console.log(Person.speak());    // what???

console.log('--- 訪問【公有屬性】及【公有方法】 ---');
console.log(tony.hobby);        // reading
console.log(tony.sport());        // run


// 經過閉包實現:
var Person = (function() {
    // 靜態私有變量
    var isChinese = true;

    // 靜態私有方法
    var speak = function() {};

    // 建立類
    var _person = function() {
        // 私有屬性: 只能被【私有方法】和【特權方法】訪問
        var contact = 'xxxxx@qq.com';
        var number = '88888888';

        // 私有方法: 在構造函數裏聲明, 能被【私有函數】【特權方法】訪問, 只能訪問【私有方法】和【私有屬性】
        var getInfo = function(name, sex) {
            console.log('My name is ' + name + ', I’m a ' + sex + '!');
            console.log('My email is ' + contact);
        };

        // 公有屬性
        this.name = name;
        this.sex = sex;

        // 特權方法: 能夠訪問
        this.intro = function() {
            getInfo(name, sex);
        };
        this.getContact = function(number) {
            console.log(number);
        };

        // 構造器
        this.getContact(number);
    };

    // 構建原型
    _person.prototype = {
        constructor: _person,
        // 公有屬性
        hobby: 'reading',
        // 公有方法
        sport: function() {
            console.log('run');
        }
    };

    // 返回類
    return _person;
})();

類的兩種寫法

  1. 標準原型寫法this

function Person() {}
Person.prototype.sayHi = function() {}

var me = new Person();
console.log(me.constructor === Person);    // true;
  1. 對象字面量prototype

function Person() {}
Person.prototype = {
    sayHi: function() {}
}
var me = new Person();
console.log(me.constructor === Person);    // false;
console.log(me.constructor === Object);    // true;

使用對象字面量的缺點:

使用對象字面形式改寫原型對象改變了構造函數的屬性,所以它如今指向Object而不是Person.code

緣由:

由於原型對象具備一個constructor屬性,這是其餘對象實例所沒有的.
當一個函數被建立時,它的prototype屬性也被建立, 且該原型對象的constructor屬性指向該函數.
當使用對象字面形式改寫原型對象Person.prototype時, 其constructor屬性將被置爲泛用對象Object.對象

解決:

在改寫原型對象時手動重置其constructor屬性.繼承

// 對象字面量修正:
    function Person() {}
    Person.prototype = {
        constructor: Person,
        sayHi: function() {
            console.log('Hi~');
        }
    }
    var me = new Person();
    console.log(me.constructor === Person);    // true;
    console.log(me.constructor === Object);    // false;

建立對象的安全模式

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

var tony = new Person('Tony', 'boy');
console.log(tony.name);     // Tony
console.log(tony.sex);        // boy

var anna = Person('Anna', 'girl');
console.log(window.name);     // Anna
console.log(window.sex);    // girl

console.log(anna);        // undefined
console.log(anna.name);        // Uncaught TypeError: Cannot read property 'name' of undefined

tips:

new能夠看做是對當前對象this不停地賦值,
若是沒有new, 則會直接執行函數, 由於函數在全局做用域中執行了,
因此在全局做用域中this指向的當前對象就天然是全局變量,
屬性都添加到window上面了;
另一個則由於Person類中沒有return語句,
則函數執行完沒有返回執行結果. 因此實例對象爲undefined;ip

// 建立對象的安全模式
var Person = function(name, sex) {
    // 判斷執行過程當中this是不是當前對象(若是是說明是用new建立的)
    if(this instanceof Person) {
        this.name = name;
        this.sex = sex;
    } else {
        // 不然從新建立這個對象
        return new Person(name, sex);
    }
}
相關文章
相關標籤/搜索