JS原型以及類

類與原型

class Person {
    constructor(x,y) {
        this.x = x
        this.y = y
    }
    add() {
        return this.x + this.y
    }
}
let person = new Person(1,2)
console.log(person.add()) // 3

經過類Person的構造函數實例化了一個對象personperson繼承了類的add方法
ES6以前是沒有類的概念,因此要實現上面的操做,須要function出馬函數

function Person(x, y) { // 首字母大寫表示它是個類函數
    this.x = x
    this.y = y
    this.add = function() {
        return this.x + this.y
    }
}
let person = new Person(1,2)
console.log(person.add())  // 3

這樣雖然實現了,可是明顯有缺點,上面ES6類的構造函數僅初始化了x,y,默認繼承了add方法,而function方式的須要初始化全部,因此須要優化優化

function Person(x, y) {
    this.x = x
    this.y = y
}
Person.prototype.add =  function() {
    return this.x + this.y
}
let person = new Person(1,2)
console.log(person.add()) // 3

很明顯,經過Person.prototype實現了classthis的做用,這就叫實例原型實例對象自己就是從類實例化而來,可不就是實例原型
既然與ES6 class掛上了鉤,這時還缺乏一個constructor,巧了,實例原型剛好有一個屬性constructor指向構造函數自己
並且爲了造成一個閉環,實例對象也有一個屬性__proto__指向實例原型
image.pngthis

由於全部對象都繼承於 Object,因此會有下面的一部分

繼承

ES6 繼承

class Father{
    constructor(name,age) {
        this.name = name
        this.age = age
    }
    // 此處的方式實際上是掛載在prototype屬性上的,反推上面的ES5 語法
    sayName() {
        console.log(this.name + this.age)
    }
}
class Child extends Father{
    constructor(name, age, job) {
        super(name,age) // 必須調用super方法,而且必定要在使用this以前調用,至關於Father.prototype.constructor.call()
        this.job = job
    }
    sayJob() {
        console.log(this.job)
    }
    // 覆蓋父類的方法
    sayName() {
        console.log('hello world') // 調用父類的屬性,輸出:hello world
    }
}
let kid = new Child('nike','20','teacher')
kid.sayJob()  // teacher
kid.sayName() // hello world

其中的關鍵是supersuper做爲一個方法在調用父類的構造函數,同時也能夠做爲一個對象,指向父類的prototype對象,而上面的調用父類屬性會出現undefined,由於name並無掛載在父類的prototype上,從新改造一下spa

class Father{
    constructor(name,age) {
        Father.prototype.name = name
        this.age = age
    }
}

由於sayName方法是掛載在prototype屬性上的,因此能夠直接super.sayName()調用,並且調用方法執行的上下文this是指向子類的prototype

class Father{
    constructor(name,age) {
        this.name = name
        this.age = age
        this.job = 'Hello world'
    }
    sayJob() {
        console.log(this.job)
    }
}
class Child extends Father{
    constructor(name, age, job) {
        super(name,age) // 必須調用super方法,而且必定要在使用this以前調用
        this.job = job
    }
    sayJob() {
        super.sayJob() // teacher
    }
}
let kid = new Child('nike','20','teacher')
kid.sayJob()  // teacher

原型鏈繼承

從上面的分析可知,xxx.prototype做爲實例原型,它擁有跟實例對象同樣的屬性和方法,因此只須要把父類的實例對象賦值給子類的prototype屬性,那麼不就繼承了code

function Father(name) {
    this.name = name
}
function Child(age) {
    this.age = age
}
Child.prototype = new Father('nike') // 將父類的實例對象賦值給Child的prototype
let kid = new Child(20) // 實例子類對象
console.log(kid.name) // nike
console.log(kid.age) // 20

構造函數繼承

由於ES5的是個函數,因此藉助函數的特性能夠實現另一種繼承對象

function Father(name) {
    this.name = name
}
function Child(age) {
    Father.call(this, 'nike')
    this.age = age
}
let kid = new Child(20)
console.log(kid.name) // nike

這兩個就夠了,其餘方式都是多此一舉繼承

判斷一個對象是否另外一個對象的原型

person instanceof Person  // true
person instanceof Object  // true
Person.prototype.isPrototypeOf(person) // true
Object.prototype.isPrototypeOf(person) // true
相關文章
相關標籤/搜索