原型、原型链
假设场景,我是一款游戏的作者,需要批量生产工具人NPC,已知基础属性有头发属性、肤色、性别以及着装等,如果每次生产的时候都需要重零打造,这样会比较耗时,这样我们会想到要构建一个模型原型,这个原型可以批量复制生产,之后再对单一属性进行个性化定制。
同样的情况在代码里的也有体现,当我们需要构造一批部分具有相同属性,但是又可以个别定制的对象时,如果我们每次都以原始的对象字面量方法来创建对象的话,就会比较耗费时间。所以在JavaScript里,我们通常会利用构造函数来创建一个对象原型,然后进行批量生产。在每一个构造函数的内部都设置有一个 prototype、__proto__、constructor 属性,
- prototype: 包含了所有共享属性(遗传性质)
- __proto__: 指向对象的原型(父亲)
- constructor:指向构造函数
构造函数、原型的修改和重写
创建原始NPC通用原型
// 创建原始NPC通用原型
function Person(name) {
this.name = name
this.HP = 1000
// others...
}
const npc1 = new Person('Jack')
const npc2 = new Person('Nick')
console.log(npc1) // Person {name: 'Jack', HP: 1000}
console.log(npc2) // Person {name: 'Nick', HP: 1000}
// 通过构造函数生成了两个除名字外,其他参数均相同的NPC角色
修改原型、重写原型
// 对NPC进行定制,比如另一个种族的NPC,他们比普通NPC的生命值更大
// 修改原型
Person.prototype.setHP = function(hp) {
this.HP = hp
}
const npc1 = new Person('Jack')
const npc2 = new Person('Nick')
npc1.setHP(1500)
console.log(npc1) // Person {name: 'Jack', HP: 1500} 血量值修改成功
console.log(npc2) // Person {name: 'Nick', HP: 1000} 血量值不受影响,原有继承属性值不变
// 重写原型
Person.prototype.HP = 3000
const npc1 = new Person('Jack')
const npc2 = new Person('Nick')
// 共享遗传基础属性变更为3000
console.log(npc1) // Person {name: 'Jack', HP: 3000}
console.log(npc2) // Person {name: 'Nick', HP: 3000}
原型链的指向
npc1.__proto__ // __proto__指向原型(共有属性对象)
npc1.__proto__ === person.prototype
npc1.prototype // undefined 没有自己的共享属性
npc1.constructor === person
Person.__proto__ // 构造函数的原型是js里的标准内置函数
Person.__proto__ === Function.prototype // true
Person.constructor === Function
// js是单继承的,Object.prototype是原型链的顶端,但是Object本身也是构造函数,函数的继承的是函数的标准对象(不是顶层对象是Function)
Function.prototype.__proto__ == Object.prototype
Person.prototype.__proto__ === Object.prototype
==> Function.prototype.__proto__ === Person.prototype.__proto__
==> Person.prototype === npc1.__proto__
==> npc1.__proto__.__proto__ === Object.prototype
// 比较有意思的特点
// js是面向对象变成的,即一切皆对象
Function === Object.constructor // 内置函数继承于内置对象
Function.constructor === Function // 内置函数的构造函数等于他本身
==> Function.constructor === Object.constructor
Function.__proto__ === Object.__proto__
// 根据上述等式推论测试练习
npc1.constructor.__proto__ === Function.prototype
npc1.constructor.prototype.__proto__ === Object.prototype
person.constructor.__proto__ === Object.prototype
原型链的终点
获取原型、判断是否在属于原型属性
- 获取原型Object.getPrototypeOf()
- 判断是否属于原型上的属性hasOwnProperty()