嗟乎原型链

构造函数与实例

function Foo() {};

let instance = new Foo();

构造函数其实就是一个函数,只不过我们约定俗成:构造函数首字母大写

在江湖上混,有些黑话还是要遵守的

实例就是用new操作符执行构造函数返回的对象

prototype

js里面一切皆对象,所以函数也是一种对象

既然是对象就可以有属性,prototype就是函数的内置属性,而且只有函数才有prototype属性

为什么只有函数才有prototype属性?

因为所有的函数都可以充当构造函数,而所有的对象都是构造函数创建的。也就是说对象都是函数创建的

prototype属性是为了继承而生的,所有只需要函数有就够了

constructor

构造函数的prototype属性指向的是一个对象,这个对象就是我们说的原型

我们知道去的路,那也要知道回来的路吧!

constructor就是回来的路。它指向原型所在的构造函数,和prototype的方向正好相反

有一个问题

function Foo() {};

let instance = new Foo();

console.log(instance.constructor); // function Foo() {};

为什么实例的constructor属性也指向构造函数?

其实实例的constructor属性不是它自己的,是原型继承过来的

proto

__proto__是实例的属性,因为实例是一个对象,而所有对象都是函数创建的,于是所有对象都有__proto__属性

实例的__proto__属性指向它的构造函数的原型

一家人

有了这三个属性,实例、构造函数、原型就有了可以互相找到对方的路,从此这一家人互相之间再也不会失了音信

function Foo() {};

let instance = new Foo();

console.log(Foo.prototype); // 原型

console.log(Foo.prototype.constructor); // 构造函数

console.log(instance.__proto__); // 原型

实例有点可怜,它的联系是单向的,如果实例不主动呼出的话,构造函数和原型是找不到它的

Foo的构造函数

那么构造函数Foo的构造函数又是谁呢?

console.log(Foo.__proto__.constructor); // function Function() { [native code] }

看到那串[native code]没?它表示到这里止步,否则,你就知道的太多了

总之,这个function Function() { [native code] }略屌

Foo的构造函数的原型

console.log(Foo.__proto__); // function() { [native code] }

一样,我们得到一个这样的东西function() { [native code] }

Foo.prototype的构造函数

console.log(Foo.prototype.__proto__.constructor); // function Object() { [native code] }

也带了一串[native code],但至少我们知道它是个函数

再往上走两步

console.log(Foo.prototype.__proto__.constructor.__proto__.constructor); // function Function() { [native code] }

这是Foo.prototype的构造函数的构造函数,哟,见到老朋友了!

再再往上走两步

console.log(Foo.prototype.__proto__.constructor.__proto__.constructor.__proto__.constructor); // function Function() { [native code] }

诶,见鬼了!往上怎么还是这哥们?

你要是不晕,其实还可以再往上走两步,仍然是这哥们

自己生自己,是不是有点色即是空,空即是色的味道?

之前说了,所有对象都是函数创建的,这哥们就是函数始祖,是女娲用泥捏出来的

见到始祖,啥也别说,顶礼膜拜吧

Foo.prototype的构造函数的原型

console.log(Foo.prototype.__proto__); // {...}

打印出来是一个有一堆属性的对象

Foo的原型是由Object构造的,所以上面打印出来的就是Object.prototype

再往上走两步

console.log(Foo.prototype.__proto__.__proto__.constructor); // Uncaught TypeError: Cannot read property 'constructor' of null

诡异的事情发生了,怎么会报错呢?

原因在于,Foo.prototype.__proto__.__proto__指向null,也就是Object的原型的原型是null

那么,Object的原型并不是构造函数创建的,因为报错了嘛!难道是石头缝里蹦出来的?

燧人之世,大迹在雷泽,华胥履之,而生伏羲。是不是感觉越来越像神话了

龙生龙,凤生凤

天灵灵,地灵灵,来一张符咒防身

嗟乎原型链_第1张图片

看到没有,只要是(构造)函数,最终会走向Function,进而循环;只要是原型(对象),最终会走向Object,进而走向null

Function是爹,说Object是娘,你有意见吗?

instanceof

console.log(instance instanceof Foo); // true

instanceof的原理是:沿着instance__proto__上溯,同时沿着Fooprototype上溯,如果能相遇,就返回true,如果始终无法相遇,就返回false

来看一个例子

console.log(Function instanceof Object); // true

console.log(Object instanceof Function); // true

再次说明了,Function可不是像Array, Number, String, Boolean一样的小弟,它和Object有说不清道不明的关系

其实原型链并不长

乍一听原型链,好像总也望不到头,其实走两步就到死胡同了

没那么可怕

继承

原型链是怎么继承的呢?

再回过头去看看符咒

如果一个对象,它既是谁的原型,又是谁的实例,那么它就是原型链上的一个神经元,原型链就是通过这些神经元沟通起来的

A的原型是B的实例,好理解吧!

我们也可以手动继承

function Parent() {
    this.name = 'Abby';
}

Parent.prototype.getName = function() {
    console.log(this.name);
}

function Child() {

}

Child.prototype = new Parent();

var grandson = new Child();

console.log(grandson.getName()); // Abby

当然继承有很多种模式,这里不展开

github原文地址

嗟乎原型链

github博客

你可能感兴趣的:(prototype,javascript)