JS原型以及类

yingmhd

类与原型

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.png

因为所有对象都继承于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上,重新改造一下

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

因为sayName方法是挂载在prototype属性上的,所以可以直接super.sayName()调用,而且调用方法执行的上下文this是指向子类的

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属性,那么不就继承了

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
阅读 252

英目频道
名乎利乎,道路奔波休碌碌;来者往者,溪山清净且停停

路漫漫其修远兮,吾将上下而求索

61 声望
4 粉丝
0 条评论

路漫漫其修远兮,吾将上下而求索

61 声望
4 粉丝
文章目录
宣传栏