2015-02-24 47 views
6

我正在阅读关于Javascript原型属性如何与继承一起工作,然后开始查看Angular.js代码并提出了一些问题。为什么将Something分配给Something.prototype.constructor?

首先,我读到prototype属性指向的对象具有“构造函数”属性,该属性指向用于创建对象的原始函数。因此,例如:

// This is the constructor 
function Shape() { 
    this.position = 1; 
} 

// The constructor points back to the original function we defined 
Shape.protoype.constructor == Shape; 

原型还包含已经由我们或JavaScript语言本身上定义的任何其他方法或属性,而这些是由对象的所有实例共享。如果您想要一个名为Square的对象从Shape继承,您需要将Square的原型设置为等于Shape的新实例,因为Square.prototype的内部[[prototype]]属性设置为Shape.prototype属性的公共对象值。

function Square() {} 
Square.prototype = new Shape(); 
var square = new Square(); 
square.position; // This will output 1 

这一切都对我有意义。

但是,我有一个问题的Angular.js代码似乎与所有这些有关,但做了一些我不明白的事情。它似乎没有处理继承问题,所以我可以理解为什么会有差异,但我只是好奇他们为什么按照他们的方式编写它。

在Angular.js中,有一个HashMap对象和一个Lexer对象,但是它们的定义有所不同,但似乎是以相同的方式实例化和使用。首先定义Lexer构造函数,然后将原型设置为包含应该由Lexer的所有实例共享的方法的对象字面值。这一切都有道理。我不明白的是为什么他们指定“构造函数”属性,并将它设置为“Lexer”,而不是下面的HashMap。

var Lexer = function(options) { 
    this.options = options; 
}; 

// Notice they specify Lexer as the constructor even though they don't for HashMap below 
Lexer.prototype = { 
    constructor: Lexer, 
    lex: function(text) { ... }, 
    is: function(ch, chars) { ... }, 
    peek: function(i) { ... }, 
    isNumber: function(ch) { ... }, 
    isWhitespace: function(ch) { ... }, 
    isIdent: function(ch) { ... }, 
    isExpOperator: function(ch) { ... }, 
    throwError: function(error, start, end) { ... }, 
    readNumber: function() { ... }, 
    readIdent: function() { ... }, 
    readString: function(quote) { ... } 
}; 

然后,如果你看一下HashMap的代码,他们这样做只是它们不指定constructor属性同样的事情。为什么是这样?它看起来工作完全一样,我测试了构造函数仍然被调用。

// The HashMap Constructor 
function HashMap(array, isolatedUid) { 
    if (isolatedUid) { 
     var uid = 0; 
     this.nextUid = function() { 
      return ++uid; 
     }; 
    } 
    forEach(array, this.put, this); 
} 

HashMap.prototype = { 
    put: function(key, value) { ... }, 
    get: function(key) { ... }, 
    remove: function(key) { ... } 
}; 

原来是constructor属性可选当没有继承,所以可能只是一个人写的词法分析器和另一个HashMap和一个决定指定构造?

+0

另请参阅[定义Javascript原型](http://stackoverflow.com/q/17474390/1048572) – Bergi 2015-02-24 20:30:55

+0

@Bergi谢谢,这有帮助。 – Triad 2015-02-24 22:27:34

回答

8

默认情况下,每个原型都具有constructor属性,该属性引用它“所属”的函数。

function A() { 
 
} 
 

 
console.log(A.prototype.constructor === A); // true

如果覆盖其全部与对象文本或与其他一些构建原型样机,这constructor价值将得到擦干,并留下未定义或与其他一些价值。

function A() { 
 
} 
 
A.prototype = { 
 
    greeting: "Hello!" 
 
}; 
 

 
console.log(A.prototype.constructor === A); // false

是不需要的原型constructor属性,以便构造正常运行,但人们往往会为了保持一致性,重新分配prototype.constructor回其初始值,这就是你正在寻找Lexer

考虑:

function A() { 
 
} 
 

 
function B() { 
 
} 
 

 
B.prototype = Object.create(A.prototype); 
 

 
var b = new B(); 
 

 
console.log(b.constructor === A); // true 
 
console.log(b.constructor === B); // false 
 

 
B.prototype.constructor = B; 
 

 
console.log(b.constructor === A); // false 
 
console.log(b.constructor === B); // true

人们只能猜测,为什么这被排除在外的HashMap。我怀疑这是出于任何理由而做的,可能只是一个疏忽。

+0

感谢您解决这个问题。我觉得有点愚蠢,因为没有看到这一点,但我之前以不同的眼光看待它,因为我为什么把“构造函数:Lexer”而不是“构造函数:新Lexer()”弄糊涂了,但我现在明白了为什么没有意义在所有。它是SubConstructor.prototype = new Constructor(),它应该有“new”关键字,然后会自动将“SubConstructor.prototype.constructor”属性赋值给“Constructor”,这是与上面的Angular不同的场景。 – Triad 2015-02-24 20:25:15

+1

@Triad是的,这是正确的。请记住,使用'SubConstructor.prototype = new Constructor()'来创建原型现在是一个过时的做法。现在它会是'SubConstructor.prototype = Object.create(Constructor.prototype);' – JLRishe 2015-02-24 20:30:57

+0

啊,很高兴知道,再次感谢。 – Triad 2015-02-24 22:20:31

相关问题