iuap-design / blog

📖 用友网络大前端技术团队博客
Apache License 2.0
941 stars 120 forks source link

简要分析ES5/6原型链继承 #73

Open onvno opened 8 years ago

onvno commented 8 years ago

Javascript 原型链继承

图片无法在issue中提交,原文在这里:onvno博客

简单实现继承

var a = {
      x: 10,
    calculate: function (z) {
        return this.x + this.y + z
      }
};

var b = {
  y: 20,
  __proto__: a
};

var c = {
  y: 30,
  __proto__: a
};

// call the inherited method
b.calculate(30); // 60
c.calculate(40); // 80

他们之间的继承关系:

1430231-2383de904a0ef8df

以上图,观察a可得到:

如果没有明确为一个对象指定原型,那么它将会使用proto的默认值-Object.prototype。Object.prototype对象自身也有一个proto属性,这是原型链的终点并且值为null。

以上代码,ES5实现方法:

var b = Object.create(a, {y: {value: 20}});
var c = Object.create(a, {y: {value: 30}});

如浏览器不支持,可用以下Polyfill

if(!Object.create){
    Object.create = function(obj){
        function F(){};
        F.prototype = obj;
        return new F();
    }
}

构造函数继承

// a constructor function
function Foo(y) {
  // which may create objects
  // by specified pattern: they have after
  // creation own "y" property
  this.y = y;
}

// also "Foo.prototype" stores reference
// to the prototype of newly created objects,
// so we may use it to define shared/inherited
// properties or methods, so the same as in
// previous example we have:

// inherited property "x"
Foo.prototype.x = 10;

// and inherited method "calculate"
Foo.prototype.calculate = function (z) {
  return this.x + this.y + z;
};

// now create our "b" and "c"
// objects using "pattern" Foo
var b = new Foo(20);
var c = new Foo(30);

// call the inherited method
b.calculate(30); // 60
c.calculate(40); // 80

// let's show that we reference
// properties we expect

console.log(

  b.__proto__ === Foo.prototype, // true
  c.__proto__ === Foo.prototype, // true

  // also "Foo.prototype" automatically creates
  // a special property "constructor", which is a
  // reference to the constructor function itself;
  // instances "b" and "c" may found it via
  // delegation and use to check their constructor

  b.constructor === Foo, // true
  c.constructor === Foo, // true
  Foo.prototype.constructor === Foo // true

  b.calculate === b.__proto__.calculate, // true
  b.__proto__.calculate === Foo.prototype.calculate // true

);

1430231-f99c16e43ea4bff1

注意:可得出constructor都指向构造函数本身,创建的实例b,c都指向构造函数的'prototype对象'

ES6的继承-类-extends

class Person {
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    sayHello(){
        console.log(`My name is ${this.name},i'm ${this.age} years old`)
    }
    toString(){
        ...
    }
}

class Student extends Person{
    constructor(name,age,cla){
        super(name,age); // 调用父类的constructor(name, age)
        this.class = cla;
    }
    study(){
        console.log(`I'm study in class ${this.class}`)
    }
    toString() {
        return this.class + ' ' + super.toString(); // 调用父类的toString()
    }
}

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

ES6入门

注意,子类中必须在constructor先使用super()来调用父类。

原因是子类通过super获取父类this实现继承,否则后边的this.class因获取不到this会报错。

super这个关键字,有两种用法,含义不同。

(1)作为函数调用时(即super(...args)),super代表父类的构造函数。

(2)作为对象调用时(即super.propsuper.method()),super代表父类。注意,此时super即可以引用父类实例的属性和方法,也可以引用父类的静态方法。

ES6可实现原生构造函数的继承。

参考链接

kvkens commented 8 years ago

家里的移动光纤竟然打不开github.io !!!怒了..