在讲原型和原型链之前,我们需要先了解下函数
函数
函数分为三种,他本身是一个普通函数,他又可以说是一个构造函数也可以称为类,同时他又是一个对象
- 普通函数
- 构造函数,又称为自定义
类
- 对象
普通函数和构造函数本质没有分别,不同点是:
- 构造函数会约定首字母大写(非强制)
- 通过
new
关键字生成一个对象,这个对象叫做实例,如果没有返回值默认会返回这个实例 - 构造函数中的
this
就是当前实例本身
function fn(){}; fn() // 普通函数
fn.name // 函数对象
function Fn(){}; // 构造函数
const f = new Fn();
原型
- 每一个函数都有一个
prototype
的属性,这个prototype
的属性,就是这个函数的原型对象
function Fn(){};
Fn.prototype // {...}
Fn.prototype.age = 18 // 手动为prototype赋值
- 原型对象上有一个
constructor
的属性,他指向当前所属类(构造函数)本身
Fn.prototype.constructor === Fn // true
- 私有属性:实例可以获取到当前构造函数执行时this的方法和属性
function Fn(a,b){
this.a = a; // 私有属性
this.b = b;
this.getValue = function(){ return 'what' }; // 私有方法
}
const f = new Fn('a', 'b');
f.a // 'a'
f.b // 'b'
f.getValue() // 'what'
- 公有属性:实例可以通过
proto
隐式原型方法获取到当前所属类(构造函数)prototype
上的所有属性和方法,会先找私有属性和方法,再找公有属性和方法
function Fn(){};
Fn.prototype // {...}
Fn.prototype.age = 18
const f = new Fn()
f.age // 18 会先判断私有属性再找公有属性
原型链
定义:如果私有属性和公有属性都没有这样的属性和方法呢,会继续向上查找,一直找到没有为止,这个查找的过程就上原型链的查找
- 原型链主要是通过
__proto__
这个隐式属性来不断的向上查找,查找的方式是:找到所属类的原型
function Fn(){}
Fn.prototype.age = 18;
const f = new Fn()
f.__proto__.age === f.age // true 18
- 这里面实例f查找公有属性通过
__
proto__
进行查找 - 如果我们再原有的属性找没有找到,会继续向上查找,通过隐式查找属性
__
proto__
function Fn(){}
Fn.prototype.age = 18;
const f = new Fn()
f.__proto__.age === f.age // true 18
Object.prototype.height = '100kg'
f.height // 100kg
Object.prototype.__proto__ // null
let obj1 = {};
let obj2 = new Object();
obj1.height //100kg
obj2.height //100kg
-
我们发现继续向上查找会直接找到
Object.prototype
对象上的属性值,Object类上的原型也有一些方法,比如toString
之类的方法,但是对象所属类还是对象,所Object.prototype
指向所属类的原型就为null,不然就会是死循环 -
刚刚我们讲了函数类,也是一个函数对象,他身上也有
__proto__
对象,那么他指向哪里呢?
-
类本身是一个函数,其次才是一个对象,所以他所属的类还是函数类,所以类如果通过
__proto__
对象【指向所属类的原型的话】那就是指向的是函数类的原型,确切的说,任何类的原型链都可以指向函数类的原型
function Fn(){}
Function.prototype.type = 'func';
Object.type // func
Fn.type //func
Function.type //func