原型和原型链
对于原型和原型链,我们要知道一下这几个:
- 函数对象——就是平时的对象;
- 实例对象——new出的对象或者{ };
- 原型对象——所有的函数对象都有一定有一个对应的原型对象,所有的原型对象都是被Object函数对象创建出来的。
一、原型
原型是一个对象,是函数的一个属性 prototype ;通过该函数实例化出来的对象都可以继承得到原型上的所有属性和方法
原型对象默认有一个属性constructor ,值为对应的构造函数;另外,有一个属性__proto__,值为Object.prototype
二 、原型链
在JavaScript中万物都是对象,对象和对象之间并不是独立存在的,对象和对象之间有一定关系。通过对象__proto__属性指向函数的原型对象(函数.prototype)一层一层往上找,直到找到Object的原型对象(Object.prototype)为止,层层继承的链接结构叫做原型链(通过proto属性形成原型的链式结构,专业术语叫做原型链)
instanceOf 的原理就是不断遍历左边变量的原型链,并不断判断右边变量是否在左边变量的原型链上,如果查找失败,则返回false,意为左边变量不是右边变量的实例对象。
// 能手动实现一下instanceof的功能
//核心: 原型链的向上查找。
function myInstanceof(left, right) {
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
//getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(left);
while(true) {
//查找到尽头,还没找到
if(proto == null) return false;
//找到相同的原型对象
if(proto == right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
缺点:
- instanceof是不能直接判断基本类型数据的类型,因为实例是一个对象或函数创建的,是引用类型,所以需要通过基本类型对应的 包装对象 来判断。所以对于
null
和undefined
这两就检测不了了 - 会把数组都识别为 Object 对象,所有引用类型的祖先都是 Object 对象
拓展
Object.prototype.toString.call()
- 优点:判断数据类型的“万能”方法,会返回一个形如 “[object XXX]” 的字符串
- 缺点:
- a. Object.prototype.toString()本身是允许被修改的
- b. 实例对象有可能会自定义toString()方法,会覆盖Object.prototype.toString(), 所以在使用时,最好加上call()
- c. 不能准确判断person是Person类的实例,而只能用instanceof 操作符来进行判断
-
isArray()
是Array类型的一个静态方法,使用它可以判断一个值是否为数组。