再说原型链

关于原型链,已经被无数次的提起,每次回顾都有新的理解,今天我们再来说说原型链。
我们知道,每一个javascript对象(除了null)在被创建的时候都会与另一个对象关联起来,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
好,问题来了,我们需要原型链来做些什么呐?

原型的作用
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.eat = function() {
    console.log(age + "岁的" + name + "在吃饭。");
  }
}

let p1 = new Person("小夏", 18);
let p2 = new Person("小夏", 18);

console.log(p1.eat === p2.eat); // false

呐,其实结果我们也预想到了,每次创建对象都会重新开辟出新的堆,所以p1和p2指向的地址是不一样的,以前的讨论基本到此为止,那么今天问一下,有没有什么办法,可以让他们指向同一个地址,节省内存呢?我们需要开辟出一块公共的区域,这个概念,就是我们所说的原型对象。

function Person(name) {
  this.name = name;
}

// 通过构造函数的 Person 的 prototype 属性找到 Person 的原型对象
Person.prototype.eat = function() {
  console.log("吃饭");
}

let p1 = new Person("小夏", 18);
let p2 = new Person("小夏", 18);

console.log(p1.eat === p2.eat); // true

上述就是我们通过原型实现对eat的公共管理,所有通过Person实例化的对象,都会继承eat属性。
关于显式原型prototype和隐式原型_proto_的概念,这边不再过多赘述,如果不太了解,请移步小夏的另一篇原型和原型链了解后再来看本篇。

普通对象和函数对象

对象可以分为两类,普通对象和函数对象。
普通对象
除了函数对象以外所有的对象都是普通对象,包括new 函数对象()产生的实例,普通对象没有prototype,也就没有继承和原型链这一说了。
函数对象
包括两种:

  • 由function创造出来的函数:
function f1(){}
var f2=function(){}
var f3=new Function('x','console.log(x)');
//以上都是函数对象
  • 系统内置的函数对象:Function、Object、Array、String、Number,还有正则对象RegExp、Date对象等等,它们在js中的构造源码都是function xxx(){[native code]},Function其实不仅让我们用于构造函数,它也充当了函数对象的构造器,比如Object对象的构造源码其实是Function Object(){[native code]},甚至它也是自己的构造器.
String._proto_===Function.prototype
//true
Object._proto_===Function.prototype
//true
Function._proto_===Function.prototype
//true

js中原型等式,对象._proto_===构造器.prototype,由此可以看出他们之间的关系。
问题来了,我们知道所有对象继承自Object对象,但是我们刚刚又说Object对象继承自Function,嗯???是不是有点矛盾了?Object和Function是相互继承的吗?从一定程度上来讲,可以这么理解。

Object和Function

一切对象都最终继承自Object对象,Object对象直接继承自根源对象null
我们可以发现,在原型链分析中,所有对象的原型链的最终都是=>Object.prototype=>null。一切对象都包含有Object的原型方法,Object的原型方法包括了toStringvalueOfhasOwnProperty等等,在js中不管是普通对象还是函数对象都拥有这些方法。
这条定律放在Function对象上依然成立,只不过Function的原型链稍微复杂了一点,它比较特别的地方就是它的构造器是自己,即直接继承了自己,最终继承于Object,什么玩意?怎么这么怪,对,就是这么怪,Function继承了他自己,最终继承了Object。

Function._proto_===Function.prototype
//true
Function.prototype._proto_===Object.prototype
//true
Object.prototype._proto_===null
//true
练习
var F = function() {

};
Object.prototype.a = function() {
    console.log('a()');
};
Function.prototype.b = function() {
    console.log('b()');
};
var f = new F();
f.a(); 
f.b(); 
F.a(); 
F.b();

//a()
//报错
//a()
//b()

根据分析可以画出下面的关系图:
在这里插入图片描述
可以看到在函数对象F的原型链中包含Function的原型方法和Object的原型方法,但是普通对象没有Function的原型方法,只有Object的原型方法。所以f.b()会报错。

拓展

new做了什么?
new关键字会进行如下操作:
1.创建一个空的简单js对象 (var a={})
2.为新创建的对象添加属性_proto_,将该属性链接到构造函数的原型对象(a._proto_=Foo.prototype)
3.将新创建的对象作为this的上下文(var b=Foo.call(a))
4.如果该函数没有返回对象,则返回this.(return b)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值