JavaScript Prototype原型原型链详解

Prototype属于比较底层的知识,学习之前我要先说一句话.

构造函数.prototype 是个对象(有唯一例外,Function.prototype),__proto__指向创建他的构造函数的原型对象。
如果没理解这句话,就说明没有理解原型。
开门见图,很关键!!
这里写图片描述

下面很多知识点都是重复的,就当巩固了吧。

  • 新建实例

万物皆对象,每个对象都有一个属性叫 __proto__,但是prototype属性只有通过Function方式新建的对象才有,这种对象称为函数对象,他们会有一个prototype属性。

function foo(){}  或者
let foo = new Function();

其他创建方式,比如

function foo(){}   //前提
let a = new foo()  或者
let a = new Object(); 或者
let a = {}

都没有prototype属性。那这两个属性是什么意思呢?
答:prototype指向函数的原型对象,__proto__指向创建它的构造函数的原型对象。看代码。

function foo(){}
foo.prototype 为 Object(即原型对象)[注:这里指的是,是个对象而不是foo.prototype === Object]

let foo1 = new foo();  //创建foo1的构造函数是foo
foo1.__proto__ => foo.prototype;
  • 构造函数
function foo(){}   foo就是一个构造函数
let foo1 = new foo();
let a = {}//等同于 new Object()

foo1.constructor===foo  //true
a.constructor===Object   //true   a为执行方法得到的结果,Object为方法本身

上述代码可知:实例的构造函数指向构造函数(有点像屁话)。

foo.prototype.constructor === foo

foo1.constructor === foo

foo1.__proto__===foo.prototype
foo1.prototype  undefined 前面说了,只有通过Function方式新建的对象才有`prototype`

稍微总结一下:构造函数的原型对象是构造函数的一个实例,是一个对象。


问:foo.prototype.__proto__ 是什么?
答:foo.prototype是一个foo的实例对象,所以他的构造函数是Object,
所以答案是Object.prototype
这里升华一下,让我们看看构造的起源在哪里?
JS中有两个根构造器,ObjectFunction.他们的__proto__都是Function.prototype,自定义一个构造器
function foo(){}
foo.__proto__也是Function.prototype。因为Function是foo的构造函数。
最后
Function.prototype.__proto__ === Object.prototype
这里说一句,Function.prototype是一个对象,构造函数是Object,所以等式成立。
- 作用:
原型对象主要是用来实现继承的。

function cat(food){this.food = food}
cat.prototype.say = function(){
    alert("I love eat"+this.food);
}
var test = new cat("fish");
test.say();  //I love eat fish
cat.say();   //undefined

test从原型链继承了say方法。而且从上面cat.say();//undefined 来看,原型是服务于继承的属性,本身是访问不到的。__proto__的源头是Object.prototype,内置函数都定义在其中。

  • 再议prototype
    prototype保存着所有的实例方法,我们知道JS内置了方法,toString(),valueOf等。
    首先,刚才说过,对象的起源是Function.prototype下面看代码。
foo.__proto__ === Function.prototype
然后打印Function.prototype发现是一个空函数{这是唯一一个.prototype为函数的存在}
然后你再打印一个
Function.prototype.__proto__ 你会发现这个里面存在着需要的所有方法,这些都是继承下来的!!

所有的追根溯源都是通过__proto来进行的,当读取变量或函数时,顺序如下

foo1.name  
foo1.__proto__.name 即 foo.prototype.name
foo1.__proto__.__proto__.name =>Object.prototype.name
foo1.__proto__.__proto__.__proto__=>null 读到null为顶端

最后说一句话,当你探索的时候,过程是痛苦的,但是等到你探索成功之后,你会发现所有的困惑都会慢慢趋向清晰。

猜你喜欢

转载自blog.csdn.net/run_youngman/article/details/79000209