构造函数的继承

instancof运算符

instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例

    function Vehicle() { }
    var v = new Vehicle()
    console.log(v instanceof Vehicle) // true

上面代码中,对象v是构造函数Vehicle的实例,所以返回true。

instancof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。隐藏,下面两种写法是等价的。

    v instanceof Vehicle
    // 等同于
    Vehicle.prototype.isPrototypeOf(v)

由于instanceof检查整个原型链,因此同一个实例对象,可能会对多个构造函数都返回true。

    var d = new Date()
    console.log(d instanceof Date) // true
    console.log(d instanceof Object) // true

上面代码中,d同时是Date和Object的实例,因此对这两个构造函数都返回true。

由于任意对象(出了null)都是Object的实例,所以instanceof运算符可以判断一个值是否为非null的对象。

    var obj = {
      foo:123
    }
    console.log(obj instanceof Object) // true
    console.log(null instanceof Object) // false

上面代码中,除了null,其他对象的instancof Object的运算结果都是true。

instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。

    var obj = Object.create(null)
    console.log(typeof obj) // object
    console.log(obj instanceof Object) // false

上面代码中,Object.create(null)返回一个新对象obj,它的原型是null。右边的构造函数Object的prototype属性,不在左边的原型链上,因此instanceof就认为obj不是Object的实例。但是,只要一个对象的原型不是null,instanceof运算符的判断就不会失真。

    var x = [1,2,3]
    var y = {}
    console.log(x instanceof Array) // true
    console.log(x instanceof Object) // true
    console.log(y instanceof Object) // true

上面代码中,instanceof运算符判断,变量x是数组,变量y是对象。

注意,instanceof运算符只能用于对象,不适用原始类型的值。

    var s = 'hello'
    console.log(s instanceof String) // false

上面代码中,字符串不是String对象的实例(因为字符串不是对象),所以返回false。

此外,对于undefined和null,instanceof运算符总是返回false。

    console.log(undefined instanceof Object) // false
    console.log(null instanceof Object) // false

利用instanceof运算符,还可以巧妙的解决,调用构造函数时,忘了加new命令的问题。

    function Fubar(foo, bar) {
      if (this instanceof Fubar) {
        this.foo = foo
        this.bar = bar
      } else {
        return new Fubar(foo, bar)
      }
    }
    var f = Fubar(1,2)
    var f1 = new Fubar(3,4)
    console.log(f) //Fubar {foo:1,bar:2}
    console.log(f1 instanceof Fubar) // true

构造函数的继承

让一个构造函数继承另一个构造函数,是非常常见的需求。这可以分成两步实现。第一步是在子类的构造函数中,调用父类的构造函数。

    function Super() {}
    function Sub(value) {
      Super.call(this)
    }

上面代码中,Sub是子类的构造函数,this是子类的实例。在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性。

第二步,是让子类的原型指向父类的原型,这样子类就可以继承父类原型。

    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.prototype.method = '...'

上面代码中,Sub.prototype是子类的原型,要将它赋值为Object.create(Super.prototype),而不是直接等于Super.prototype。否则后面两行对Sub.prototype的操作,会连父类的原型Super.prototype一起修改掉。

另外一个写法是Sub.prototype等于一个父类实例。

    Sub.prototype = new Super()

上面这种写法也有继承效果,但是子类会具有父类实例的方法。有时,这可能不是我们需要的,所以不推荐这种写法。

    function Shape() {
      this.x = 0
      this.y = 0
    }
    Shape.prototype.move = function (x, y) {
      this.x += x
      this.y += y
      console.log('shape moved')
    }

我们需要让Rectangle构造函数继承Shape。

    // 第一步,子类继承父类的实例
    function Rectangle() {
      Shape.call(this)
    }
    // 另一种写法
    function Rectangle() {
      this.base = Shape
      this.base()
    }

    // 第二步,子类继承父类的原型
    Rectangle.prototype = Object.create(Shape.prototype)
    Rectangle.prototype.constructor = Rectangle

采用这样的写法以后,instanceof运算符会对子类和父类的构造函数,都返回true。

    var rect = new Rectangle()
    console.log(rect instanceof Rectangle) // true
    console.log(rect instanceof Shape) // true

上面代码中,子类是整体继承父类。有时只需要单个方法的继承,这时可以采用下面的写法。

    function ClassA() {

    }
    ClassA.prototype.getName = function () {
      console.log(this.name)
    }

    function ClassB(name) { this.name = name }
    ClassB.prototype.getName = function () {
      ClassA.prototype.getName.call(this)
      //some code
    }
    var b = new ClassB('test')
    b.getName() // test

上面代码中,子类B的getName方法先调用父类A的getName方法,再部署自己的代码。这就等于继承了父类A的getName方法。

多重继承

JavaScript不能提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。

    function M1() {
      this.hello = 'hello'
    }
    function M2() {
      this.world = 'world'
    }

    function S() {
      M1.call(this)
      M2.call(this)
    }

    // 继承M1
    S.prototype = Object.create(M1.prototype)
    // 继承链上加入M2
    Object.assign(S.prototype, M2.prototype)

    // 制定构造函数
    S.prototype.constructor = S

    var s = new S()
    console.log(s.hello) // hello
    console.log(s.world) // world

上面代码中,子类S同时继承了父类M1和M2。这种模式又称为Mimin(混入)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值