在讲原型之前,我们先说说js的数据类型,有一下几种
原始数据类型:String、Number、Boolean、Null、undefined、Symbol(ES6)、BigInt(ES10)
引用类型:Object
JS 中 typeof 输出分别是什么呢?
1)基础数据类型
typeof 'a' // 'string'
typeof 12 // 'number'
typeof false // 'boolean'
typeof null // 'object'
typeof NaN // 'number'
2)引用数据类型
typeof Object //'function'
typeof Number //'function'
typeof String //'function'
typeof Boolean //'function'
typeof Function //'function'
这个时候有人肯定会有疑问,为啥引用类型这里输出的function,我们知道任何几个结果的输出都是有原因的,我们先在这里埋下一个伏笔。接下来我们进入主题,讲讲原型
一、构造函数创建对象
我们先使用构造函数创建一个对象
function Person (name, age) {
this.name = name
this.age = age
}
var person = new Person('zbq', 28)
我们创建了一个Person构造函数,然后通过new来创建来一个实例person,接下来我们开始进入主题
prototype属性
每个函数都有一个prototype属性,指向实例原型,构造函数与实例原型的关系如下图所示:
__proto__属性
每个对象都有一个__proto__属性,指向实例原型,该实例与实例原型的关系如下入所示
因此person的__proto__属性与Person构造函数的prototype的属性指向的是同一个实例原型 Person.prototype,我们来验证一下
person.__proto__ === Person.prototype // true
补充说明:绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto__ 时,可以理解成返回了 Object.getPrototypeOf(obj)。
constructor属性
我刚说了构造函数与实例原型的关联,以及实例与实例原型的关联,那实例原型与构造函数有啥关联呢?这就是我们接下来要说的
实例原型的constructor属性,它是指向构造函数的,我们用代码验证一下
Person.prototype.constructor === Person //true
它的关系图如下所示:
接下来有人肯定要问了,那Person.prototype它有指向的是谁呢?这就是我们接下来要讲的原型与原型之前的关联了
二、原型与原型
前面我们说过每个对象都有一个__proto__属性,而实例原型也不例外,它也有一个__proto__指向上一个实例原型对象,因此就有如下的Person.prototype.__proto__指向Object.prototype。
三、原型链
原型与原型之间通过__proto__建立的的关联就是原型链(下图的蓝色线条),这里再补充一下Object.prototype指向的原型是null
我们可以用代码验证一下
Person.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true
四、拓展
我们先记住一个知识点,instanceof 它表示是一种继承关系。然后我们再看看以下的一个例子
Object instanceof Function // true
Function instanceof Object // true
Function instanceof Function // true
肯定很多人一脸的疑惑,在想为什么?疑惑是正常的。不过我们先来一步步分析吧!
1、首先我们先看一个函数的创建
// 方式一:传统方式来新建一个函数
function add1 (a, b) {
return a + b
}
// 方式二:通过new的方式来创建(平时不推荐使用)
var add2 = new Function ('a', 'b', 'return a + b')
根据此可以得出一个结论:
1) 函数也是对象,所以也有__prototype__属性
2) Function是一个构造函数 function Function () {....}
关系图如下:
2、创建对象
// 方式一:对象字面量的形式
var obj1 = {}
// 方式二:new方式来创建
var obj2 = new Object()
obj1.__proto__ === Object.prototype // true
obj2.__proto__ === Object.prototype // true
根据以上可以得出一个结论:
1) 对象字面量的创建方式只是new方式的一种快捷创建方式
2) Object也是一个构造函数 function Object () {...}
3) Object也是Function的一个实例
Object.__proto__ === Function.prototype // true
以上实例的关系图如下:
所以你现在是不是能懂的为啥以下的例子的结果都是返回true,以及开篇文章中 typeof Object === 'function'
Object instanceof Function // true
Function instanceof Object // true
Function instanceof Function // true
小结:
1、每个函数都有一个prototype属性
2、每个对象都有一个__proto__属性
3、任何函数皆对象
以上文章是参考至:
https://segmentfault.com/a/1190000008959943
https://www.cnblogs.com/wangfupeng1988/tag/%E5%8E%9F%E5%9E%8B