概念
原型:每个对象都含有对原型的引用(但是是内置属性,无法直接访问),当查找属性时,若对象本身不具有该属性,则会查找原型上是否有该属性。
Object.setPrototypeOf(yoshi, hattori) 将后者(对象hattori)设为前者(对象yoshi)的原型。当查找yoshi上没有的属性时,yoshi将查找过程 委 托 给hattori对象。
原型链:每个对象有一个原型,每个对象的原型又有一个原型也可以拥有一个原型,以此类推,形成一个原型链。
构造器和原型
构造函数构造新对象时,是如何使用原型的?
new 应用于构造函数之前,触发创建一个新对象分配。又,每个函数都有一个原型对象,该原型对象将被自动设置为通过该函数创建的对象的原型。
通过对象实例触碰到构造函数:const ninja2 = new ninja.constructor()
分清原型属性和实例属性
在构造函数内部,关键字this指向新创建的对象,所以在构造器内部添加的属性直接在新的ninja实例上。
如果在构造函数内部创建对象方法,会导致每个实例都拥有一个对象方法,方法都是一样的,但却占了空间,消耗了内存。所以只在函数的原型上创建对象方法,因为这样可以使得同一个方法由所有实例共享。
注意,如果需要私有对象变量,那就可以在构造函数内部指定方法。
js动态特性的副作用
const ninja1 = new Ninja()Ninja.prototype.swingSword = function(){return this.swung}Ninja.prototype = {pierce: function () {return true}}const ninja2 = new Ninja()
使用字面量对象完全重写Ninja的原型对象。
因为对象与对象原型之间的引用关系实在对象创建时建立的。所以重写后,尽管已经完全替换了Ninja的构造器原型,但是实例化后的Ninja对象仍然具有swingSword方法,因为对象ninja1仍然保持着对旧的Ninja原型的引用。新创建的实例ninja2拥有新原型的引用,不具有swingSword方法,仅具有pierce方法。
对象实例是通过哪个函数创建构造的?
操作符instanceof:检测一个实例是否由特定构造函数创建
constructor:说明该对象是从哪儿创建出来的
实现继承
JS中的继承即实现一个原型链,在原型链上,Ninja继承自Person。
创建这样的原型链最佳技术方案是一个对象的原型直接是另一个对象的实例。
Ninja.prototype = new Person()
这样做的好处在于在Person原型上所发生的所有变化不会同步到Ninja原型上,这是因为对象与对象原型之间的引用关系实在对象创建时建立的。
function Person(){}
Person.prototype.dance = function(){}
function Ninja(){}
Ninja.prototype = new Person()
const ninja = new Ninja()

重写原型导致的问题
丢失了Ninja与Ninja初始原型之间的联系,这会导致 constructor 属性丢失。
查找ninja.constructor。回到原型上,new Person() 上没有constructor属性,继续在原型链上追溯,在Person对象的原型上具有指向Person本身的constructor属性。事实上,如果我们询问Ninja对象的构造函数,我们得到的答案是Person,但是这个答案是错误的。这可能是某些严重缺陷的来源。
修复缺陷—解决constructor属性被覆盖的问题
重新构建ninja实例与Ninja构造器之间的联系,所以可以确定ninja实例是通过Ninja构造器创建的。
此外,如果遍历Ninja.prototype对象,可以确保不会访问到constructor属性。
function Person(){}
Person.prototype.dance = function(){}
function Ninja(){}
Ninja.prototype = new Person()
Object.defineProperty(Ninja.prototype, "constructor", {
emurable: false,
value: Ninja,
writable: true
})
const ninja = new Ninja()
instanceof 操作符
instanceof:检查操作符右边的函数的原型是否存在于操作符左边的对象的原型链上。
typeof:检测对象是否由某一个函数构造器构造。
ninja instanceof Ninja:js引擎检查Ninja函数的原型—new Person()对象,是否存在于ninja实例的原型链上。
class
class Person {
constrcutor(name) {
this.name = name
}
dance() {
return true
}
}
class Ninja extends Person {
constructor(name, level) {
super(name)
this.level = level
}
static compare(ninja1, ninja2) {
return ninja1.level - ninja2.level
}
}
