持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
结论:prototype 指向函数的原型对象,__proto__
是指针。原型链则是通过 __proto__
指向其原型对象,串联起链表。主要解决对象的继承问题。
什么是原型 prototype
JS 中的函数也是对象。如何证明函数也是对象?函数作为表达式被创建,并且可以添加任意的属性。
function fn() {} fn.sex = 'male' console.log(fn.sex) // male 函数可以添加任意的属性 // 利用 Object.create 方法,这个方法只有对象才能使用 function fn() {} const obj = Object.create(fn); // Object.create('') 则会报错,报错内容: Object prototype may only be an Object or null console.log(Object.getPrototypeOf(obj) === fn); // true
在 JS 中,每当定义一个对象的时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个 prototype
属性,这个属性指向函数的原型对象。
使用原型对象的好处是所有对象实例共享它所包含的属性和方法。在做构造函数的时候经常会用到这个特性。
什么是原型链?什么是__proto__
__proto__
是指针。原型链则是通过__proto__
串联起来的链表。主要解决对象的继承问题。
先来看一段代码:
function Parent (name) { this.name = name } Parent.prototype.showName = function() { console.log(this.name) } const p = new Parent('kane') p.showName() console.log(p.__proto__ === Parent.prototype) // true
构造函数 Parent、Parent.prototype 和 实例 p 之间的关系:
每个实例对象都拥有一个原型对象,通过 __proto__
指向其原型对象,并从中继承方法和属性。
同时原型对象也可能拥有他的原型对象,这样一层一层,最终指向 null(Object.proptotype.__proto__
指向的是 null
)。这种关系被称为原型链 (prototype chain)。
通过原型链,一个对象可以拥有定义在其他对象中的(继承过来的)属性和方法。
prototype
和 __proto__
区别是什么?
prototype
是构造函数的属性。
__proto__
是每个实例都有的属性,可以访问 [[prototype]]
。
实例的 __proto__
与其构造函数的 prototype
指向的是同一个对象。
function Parent (name) { this.name = name } Parent.prototype.showName = function() { console.log(this.name) } const p = new Parent('kane') p.showName() console.log(p.__proto__) console.log(Object.getPrototypeOf(p)) console.log(Parent.prototype); console.log(p.__proto__ === Parent.prototype) // true class Human { constructor(name) { this.name = name; } say() { console.log('hello'); } } class Man extends Human { constructor(name) { super(name); } run() { console.log('running') } } const man = new Man('kane') man.say() man.run() console.log(Object.getPrototypeOf(man) === Man.prototype) // true console.log(Object.getPrototypeOf(man) === Human.prototype) // false
如何实现 instanceof
特点
- 可以准确的判断复杂数据类型,但是不能正确判断基本数据类型
- 在原型链上的结果未必准确
- 不能检测
null
,undefined
。
通过原型链判断的,A instanceof B
:
- 在 A 的原型链中层层查找,是否有原型等于
B.prototype
。 - 如果一直找到 A 的原型链的顶端 (
null
; 即Object.prototype.__proto__
), 仍然不等于B.prototype
,那么返回 false,否则返回 true。
// L instanceof R function myInstanceOf(L, R) {// L 表示左表达式,R 表示右表达式 let O = R.prototype;// 取 R 的显式原型 L = L.__proto__; // 取 L 的隐式原型 // L = Object.getPrototypeOf(L) // 获取对象的原型 while (true) { if (L === null) // 已经找到顶层 return false; if (O === L) // 当 O 严格等于 L 时,返回 true return true; L = L.__proto__; // 继续向上一层原型链查找 } } let a = [1,2,3] console.log(myInstanceOf(a, String)); // false