乐趣区

关于javascript: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__ 指向实例原型

因为所有对象都继承于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
退出移动版