Skip to content

Instantly share code, notes, and snippets.

@allenfantasy
Forked from hayeah/gist:9757971
Last active June 2, 2016 15:42
Show Gist options
  • Save allenfantasy/1e666aedf134938d7802 to your computer and use it in GitHub Desktop.
Save allenfantasy/1e666aedf134938d7802 to your computer and use it in GitHub Desktop.
Implementation of inheritance in CoffeeScript
var __hasProp = {}.hasOwnProperty;
var __extends = function(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
function ctor() {
// why set the prototype's constructor to child?
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
@allenfantasy
Copy link
Author

第5到7行的代码的意义是?在Coffeescript的源码中child和parent都是构造函数,所以不明白将构造函数的属性复制给子构造函数的用意在哪里。

这段代码可以让通过Child函数创建的对象 继承 Parent的原型 的所有属性,同时保证了不会对 直接通过Parent创建的对象 造成污染。

但如果需要Child创建的对象 可以和 Parent创建的对象 有一样的属性值的话,还需要在Child函数中显式的调用Parent函数(通过apply)。在Coffeescript中的实现如下:

function Child() {
   // 注意这里的__super__的调用,可见extend函数中不能去掉第12行
   return Child.__super__.constructor.apply(this, arguments);
}

@allenfantasy
Copy link
Author

回答自己之前提出来的问题:child 和 parent 都是构造函数,但函数本身也可能带有属性(类似于基于类的OOP语言中的class variable ),所以需要复制给子构造函数。

避免子构造函数通过 prototype 污染 Parent 对象的方法的关键在于 ctor 。请看例子:

function Person() {
    this.age = 1;
    this.name = "foo";
}
Person.prototype.greet = function() {
    console.log("hello");
}
__extends(Student, Person);

function Student() {
    return Student.__super__.constructor.apply(this, arguments);
}
Student.prototype.greet = function() {
    console.log("hello, i am a student");
}

这段代码在最后尝试对 Student.prototype 进行修改,也就是我们所理解的重定义(override)。如果在 __extends 函数中不使用 ctor 作为过渡:

var __extends = function(child, parent) {
   // 省略前面复制属性的代码...
   child.prototype = parent.prototype; // 原来这里是用 ctor 的,现在不用了
   child.__super__ = parent.prototype;
   return child;
}

则会出现以下情况:

var p = new Person();
var s = new Student();

p.greet();  //=> hello, i am a student
s.greet();  //=> hello, i am a student

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment