我用几句话写下了我所学到的内容,以真正理解原型和对象包装器是如何工作的。如果我错了请纠正我,如果我遗漏了其他细节,请告诉我。
JavaScript使用原型来查找对象的方法和属性。例如,如果您创建一个字符串"Hello"
,它是一个原始字符串值并尝试在其上应用方法split()
("Hello".split()
),字符串值将被强制转换为String对象,因此我们可以应用split()
方法。此String对象由String.prototype.constructor
创建。创建它之后,JavaScript会在原型对象中查找split()
方法。在应用该方法并返回值之后,不再需要String对象,因此它被牺牲给了垃圾收集之神。
答案 0 :(得分:2)
你本质上是正确的,虽然堆栈空间和继承是两个不同的问题,并且在像js这样的高级脚本语言中,垃圾收集的工作原理可能是不确定的。确实如此,在该行完成后,单个代码行的中间值将被销毁。
此外,String.prototype.constructor
与String
本身相同。 String
的任何“实例”都会收到.__proto__
引用,该引用将指向String.prototype
,从而创建一个继承链。如果发现对象属性未定义为对象x
本身,则JavaScript会自动检查x.__proto__
引用的对象,然后x.__proto__.__proto__
,一直到 - 在大多数情况下 - Object.prototype
。
请记住,__proto__
在JavaScript解释器之间的实现方式不同,不应手动操作。很高兴知道存在这样的参考来解释原型魔法,但是在任何情况下都不应该直接更改对象的__proto__
引用。相反,您应该通过new
运算符或Object.create
创建类的实例。 JavaScript中的完整超级/子类关系如下所示:
function Animal( name, weight ){
this.name = name, this.weight = weight;
this.alive = true;
this.hungry = true;
}
// At this point you could put in Animal.prototype = Object.create(Object.prototype); but JavaScript will set it automatically, so it’s unnecessary
Animal.prototype.kill = function(){
this.alive = false;
}
Animal.prototype.feed = function(){
this.hungry = false;
}
function Cat(name, weight){
Animal.call(this, name, weight);
this.lives = 9;
}
// Sometimes people instance a new parent like
// Cat.prototype = new Animal('doesntmatter', 420);
// The result is the same except that using Object.create saves the overhead
// of running a full constructor for an object that doesn’t need it
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.kill = function(){
this.lives--;
if(this.lives <= 0) this.alive = false;
};
var a = new Animal();
var c = new Cat();
/* a.feed and b.feed now reference the same function object,
but c.kill has been overridden since its prototype `__proto__` chain first
visits Cat.prototype, then Animal.prototype, then Object.prototype. */
最后,ES6引入了一个class
关键字,它是该系统的语法糖,并将构造函数抽象为init
方法。