instanceof
JS中可以通过instanceof操作符来判断某个对象是否为某个类的实例。其原理为从实例开始,遍历其自身/原型/原型的原型....由下至上追溯__proto__属性,
其实现如下:
function instanceof (instance, class){
var proto = class.prototype
var insProto = instance.__proto__
while(true){
if(insProto === null){
return false
}
if( insProto === proto){
return true
}
insProto = insProto.__proto__
}
}
注意
- 完全重写原型对象,如下:这样写虽然使用instanceof依然可以判断sub是subType()的实例,但是subType的constructor属性已经不存在了,因此要手动去修复这个属性,值得注意的是,在要使用Objesct.defineProperty,因为默认constructor属性是不可枚举的(enumberable:false)
function subType = (){
}
subType.prototype ={ }
var sub = new subType()
- 红宝书P157,注意添加原型链的时机:给原型添加方法的代码 一定要在替换原型对象之后 否在会被新的对象覆盖掉
function Person(){
}
var friend = new Person()
Person.prototype={
constructor:Person,
name:"xjm",
age:25,
sayName(){
console.log(this.name)
}
}
friend.sayName() //报错,找不到sayName属性/方法
new.target:指向被new调用的【构造函数】
在创建实例dog的时候,调用了Dog的构造函数,Dog类和Animal的构造函数都运行,而且输出的new.target都是Dog。
class Animal {
constructor(name, age) {
console.log(new.target) //Dog
if (new.target === Animal) {
throw new Error('Animal class can`t instantiate');
}
//模仿抽象方法
if (new.target !== Animal && !new.target.prototype.hasOwnProperty('getName')) {
throw new Error('please overwrite getName method');
}
this.name = name
this.age = age
}
// 其他代码
//...
}
class Dog extends Animal {
constructor() {
console.log(new.target) //Dog
super('dog', 1)
}
}
const dog = new Dog()
在js中是没有抽象类的概念的,因此可以使用new.target来模仿抽象类/抽象方法。 在js中一切都可以是对象,但是对象的类型只有在运行的时候才确定个,因此虽然这个方法可以模拟抽象类/抽象方法,但是只有到了函数运行的时候才会报错。
class person{
constructor(){
if(new.target === 'person'){
throw new Error('不能实例化抽象类')
}
if (new.target !== person && !new.target.prototype.hasOwnProperty('getName')) {
throw new Error('没有重写抽象方法getName');
}
}
}