JavaScript學習筆記第四天_面向對象編程

1. 基礎

JavaScript不區分類和實例的概念,而是經過原型來實現面向對象編程。
Java是從高級的抽象上設計的類和實例,而JavaScript的設計理念,聽起來就比如Heros裏的Peter,能夠複製別人的能力。JavaScript就是別人的全部屬性都拷貝過來,成爲本身的一部分,並可以保留自身的能力。java

看廖老師的圖片,應該就能感受出咋回事了,xiaoming這個實例把本身的__proto__指向Student就實現了繼承,這種繼承關係是脆弱的,也是動態能夠修改的。
l編程

可是JavaScript是不推薦直接使用__proto__進行繼承的。提供了一個Object.creat(原型)來建立對象。這是JavaScript的一種原型繼承的方法,以下實例。瀏覽器

var Student = {
    name : "robot",
    height:180,
    run:function(){
        console.log(this.name + " is running");
    },
    grade:()=>"4"+"grade"
};
function createStudent(name){
    var s = Object.create(Student);
    // init new object
    s.name = name;
    return s;
};
var xiaoming = createStudent("xiaosfsffsfsf");

2. 建立對象

當咱們用obj.xxx訪問一個對象的屬性時,JavaScript引擎先在當前對象上查找該屬性,若是沒有找到,就到其原型對象上找,若是尚未找到,就一直上溯到Object.prototype對象,最後,若是尚未找到,就只能返回undefined。函數

以上說明JavaScript引擎有個追朔系統,優先使用當前域的進行查找,不行則向上一個原型內進行查找。工具

除了使用{...}進行建立對象,還可使用new 的方法,須要先定義一個構造函數,以下所示。若是使用new那麼這個函數就會默認返回this這個對象,若是不是用new,直接調用,那麼這個函數就返回undefined,像普通的函數同樣。this

function Student(name){
    this.name = name;
    this.hello = function(){
        alert('hello'+name);
    }
}
var stu = new Student('XiaoMing');

新建立的stu的原型鏈是spa

stu ----> Student.prototype ----> Object.prototype ----> null

用new Student建立的對象stu,還從Student上繼承了constructor屬性,它指向Student自己。prototype

stu.constructor === Student.prototype.constructor; // true
Student.prototype.constructor === Student; // true
Object.getPrototypeOf(stu) === Student.prototype; // true
stu instanceof Student; // true

這個原型鏈仍是盜用liaoxuefeng老師的圖
l
能夠看出實際上Student,xiaoming,xiaohong的原型都是指向Student.prototype。當前每一個對象的hello方法都是不一樣的,屬於不一樣的對象。但根據方法查找規則,若是把hello放在Student.prototype上,就能夠實現共用同一個方法,節省內存。即:設計

function Student(name) {
    this.name = name;
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
};

另外,注意到構造函數裏的屬性,都沒有通過var進行初始化,而是直接使用this.xxx進行綁定。因此若是沒用new,而是直接調用構造函數,那麼將會使this指向window,而後內部的各個屬性都將添加到window上,無心中添加全局變量。而且在strict模式下,構造函數沒有使用new進行調用,也會致使報錯。code

***調用構造函數千萬不要忘記寫new。爲了區分普通函數和構造函數,按照約定,構造函數首字母應當大寫,而普通函數首字母應當小寫,這樣,一些語法檢查工具如jslint將能夠幫你檢測到漏寫的new。***

練習

function Cat(name) {
    this.name = name;
}
Cat.prototype.say = function(){
    return "Hello, "+this.name+"!";
}

在此基礎上,咱們還能夠建立一個createCat()函數,在內部封裝全部的new 操做。

function Cat(props) {
    this.name = props.name || '波斯貓';
    this.color = props.name || '黑白';
}
Cat.prototype.say = function(){
    return "Hello, I am " + this.color + this.name+"!";
}

function createCat(props){
    return new Cat(props || {});
}

這樣就不須要new 操做了,參數也很靈活,能夠不傳入,也能夠傳少許的,其餘的屬性將會由默認的值替代。並且參數不須要考慮順序,可對收到的JSON直接生成對象。

3. 原型繼承

JavaScript的原型繼承實現方式就是:
定義新的構造函數,並在內部用call()調用但願「繼承」的構造函數,並綁定this;
藉助中間函數F實現原型鏈繼承,最好經過封裝的inherits函數完成;
繼續在新的構造函數的原型上定義新方法。

廖老師的一張圖簡單扼要說明這個繼承模型。
l

4. class繼承

其實3是不過重要的,由於ES6已經推出了class這個關鍵字來解決繁瑣的原型鏈繼承的複雜性,就像java同樣好,但底層其實仍是原型鏈繼承實現,這一點並無變化。

class Cat extends Animal{

constructor(name){
    super(name);
}

say(){
    return 'Hello, '+this.name+'!';
}

}

say()方法,實例依然是共享的。but,這個須要較新的瀏覽器支持,通常還用不了,可是可使用Babel這個庫去兼容這個玩意,其實我不瞭解這是個啥庫。

相關文章
相關標籤/搜索