美文网首页
Prototype - 不一样的 Class

Prototype - 不一样的 Class

作者: 萧沪椿Helson | 来源:发表于2017-08-27 16:07 被阅读0次

我第一次接触面向对象时,使用的是 Python,运用 def __init__(self, *args): 这种 magic method 来完成自身参数的初始化。 JS 当中也有类似的构造器 constructor 。

我先用 ES6 中新引入的 class 语法来定义一个类,因为这样容易理解。

class Student {
  constructor(name) {
    this.name = name;
  }
  
  hello() {
    return 'Hello, ' + this.name + '!';
  }
}

再定义一个类来继承

class PrimaryStudent extends Student {
  constructor(name, grade) {
    super(name); // 调用父类的构造函数
    this.grade = grade;
  }
  
  myGrade() {
    return 'I am at grade ' + this.grade;
  }
}

看似与 Python 极为相似,难怪我直接用 React 写应用的时候并没有发现不对。这种新的语法简化了 JS 原本复杂的原型 (prototype) 继承,也让直接了解新语法的我忽略了它的本质及特性。

(为了学习)回归原本的面貌

function Student(name) {
  this.name = name;
}

Student.prototype.hello = function() {
  return 'Hello, ' + this.name + '!';
}

var kitty = new Student('kitty');
var daisy = new Student('daisy');

可以观察到我们并不在 Student 中直接写 hello 函数,而是写在了它的 prototype 中。只要我们给 prototype 定义了函数,那么 Student 生成的对象就都可以调用这个函数,省去每个对象再独自生成函数的操作。

我们把 Student.prototype 想象成一根树枝,kitty 和 daisy 就是生出的绿叶了,它们共用树枝上的器官,不必自己再生出相同的器官来消耗资源。此时 kitty 和 daisy 的原型指向 Student.prototype。

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。

进一步,为了避免生成对象的时候漏写 new,可以封装一下。

function Student(props) {
    this.name = props.name || '匿名'; // 默认值为'匿名'
    this.grade = props.grade || 1; // 默认值为1
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
};

function createStudent(props) {
    return new Student(props || {});  // 兼顾没有参数的情况
}

然后直接调用 createStudent() 就可以了。

Student.prototype 的继承应该如何写呢?

function PrimaryStudent(props) {
    // 调用Student constructor构造函数,绑定this变量
    Student.call(this, props);
    this.grade = props.grade || 1;
}

别以为这就结束了。

Student.call(this, props); 这句代码,确实和 Student 搭上边了,但此时 PrimaryStudent.prototype 是谁?

我们的目标是构造一个 PrimaryStudent.prototype ,令它指向上层的 Student.prototype。

有谁是这种关系?kitty 和 daisy 的原型好像就是。

我就不想了,前辈的方法是这样的。

function F() {
}

F.prototype = Student.prototype;

PrimaryStudent.prototype = new F();

// 把PrimaryStudent原型的构造函数修复为PrimaryStudent(因为上一句修改了constructor)
PrimaryStudent.prototype.constructor = PrimaryStudent;
  • 构造一个函数 F ,令 F.prototype = Student.prototype
  • 生成一个中间对象,那么这个对象的 prototype 就可以指向 Student.prototype

这不就是我们想要的吗?我们把该对象赋给 PrimaryStudent.prototype ,那么就可以实现 PrimaryStudent.prototype —> Student.prototype 的指向连接了。

// 继续在PrimaryStudent原型(就是new F()对象)上定义方法:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

// 创建xiaoming:
var xiaoming = new PrimaryStudent({
    name: '小明',
    grade: 2
});
xiaoming.name; // '小明'
xiaoming.grade; // 2

// 验证原型:
xiaoming.__proto__ === PrimaryStudent.prototype; // true
xiaoming.__proto__.__proto__ === Student.prototype; // true

// 验证继承关系:
xiaoming instanceof PrimaryStudent; // true
xiaoming instanceof Student; // true

封装它

function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

Child.uber = Parent.prototype; 意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。(uber是一个德语词,意思是"向上"、"上一层"。)这等于在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。

参考资料

廖雪峰的三篇文章(个人感觉有些晦涩,最好再去看看别的资料)

推荐阮一峰的三篇文章,由简入深,非常不错。

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

相关文章

  • prototype class

    1

  • Prototype - 不一样的 Class

    我第一次接触面向对象时,使用的是 Python,运用 def __init__(self, *args): 这种 ...

  • R--S4 Class

    S4Class 泛型函数 setClass(Class,representation(),prototype = ...

  • 2019-06-18 JS 中继承的写法

    使用 prototype 如何继承 使用 class 语法糖如何继承 ``` class Human{ ...

  • 关于class与prototype

    es6 中的class,与js中的prototype 有什么关系 ES6 为了进一步缩减代码的简写,和简化代码的逻...

  • ES6里玩接口

    OOP里,class和interface是很有用的两个东西,废话。在JS/ES中,class被prototype取...

  • ES6中的Class

    ES6的class语法 不是一种新的“类”机制,class基本上只是现有 [[prototype]]链(委托)机制...

  • ES6之class

    class基本语法: 1.实质: ​ class只是一个语法糖,类的所有方法都定义在类的prototype...

  • JS之面向对象

    JavaScript是基于原型(prototype), 没有python中class 的概念。 构造函数在Java...

  • 原型与原型链

    关键字 prototype constructor __proto__ Object 在没有ES6的Class之...

网友评论

      本文标题:Prototype - 不一样的 Class

      本文链接:https://www.haomeiwen.com/subject/mgzbdxtx.html