js中的原型对象

一、JavaScript为什么要设计原型对象

构造函数其实就是普通函数,但是其内部使用了this变量。对构造函数使用new运算符,就能生成实例对象。

但是使用构造函数生成实例对象有一个缺点,就是无法共享属性和方法。每一个实例对象都是构造函数的副本,虽然内容相同但是没有任何关联。进一步说,对一个实例进行更改,其他实例不会发生变化。

function Foo () {
    this.name = "cat";
}
var f1 = new Foo();
var f2 = new Foo();
f1.name = "dog";
console.log(f1.name);
console.log(f2.name);

打印结果显示,f2中的name属性并没有被改变。

构造函数打印结果

因此为了能让实例对象相互之间进行通信,方便共享数据,JavaScript中引入了原型这一概念。

函数都有原型对象属性(即prototype):该原型对象保存着所有实例对象的公共属性和方法。
1)实例会继承构造函数的原型对象中的属性

Foo.prototype = {name: "cat"};
function Foo () {};
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.name);    //cat
console.log(f2.name);    //cat

我们在Foo.prototype中定义了name属性,属性值为“cat”。结果显示,该构造函数构造出的实例都继承了name属性。

2)更改原型对象上的属性,所有实例中的属性都会跟着改变

Foo.prototype = {name: "cat"};
function Foo () {};
var f1 = new Foo();
var f2 = new Foo();
Foo.prototype.name = "dog";
console.log(f1.name);    //dog
console.log(f2.name);    //dog

3)我们可以通过实例来修改构造函数原型对象中的属性

Foo.prototype = {name: "cat"};
function Foo () {};
var f1 = new Foo();
var f2 = new Foo();
f1.__proto__.name = "dog";
console.log(f1.name);
console.log(f2.name);
在原型对象打印结果

使用构造函数创建实例对象之后,就有了两种不同的属性和方法:一种是私有化的属性和方法,书写在构造函数中,对其中一个实例进行更改,不会影响到其他实例,每一个实例中的属性和方法互不干扰;另一种是公有化的属性和方法,存放在原型对象中。所有实例都共享这些属性和方法,如果该原型属性中的方法和属性发生了变化,就会影响到所有的实例对象。

二、探究实例、构造函数、构造函数的原型之间的关系

还是以一下代码为例

Foo.prototype = {name: "cat"};
function Foo () {};
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.name);
console.log(f2.name);

我们再来看一下这几个属性的定义

1)prototype

函数都具有prototype(原型对象)属性,该原型对象保存着所有实例对象的公共属性和方法,也就是共享的属性和方法。

2)__proto__

每个JavaScript对象(除了null,包括构造函数创造出来的实例对象和原型对象)都具有__proto__属性,该__proto__属性指向创造该对象的构造函数的原型对象(prototype)

3)constructor

原型对象都有constructor属性,指向拥有该原型对象的构造函数

1.f1.__proto__指向谁

实例f1.__proto__的指向

1、实例f1由构造函数Foo使用new构造出来

2、Foo.prototype是函数的原型对象,因此函数Foo的prototype属性指向Foo.prototype

3、根据定义,Foo.prototype的constructor属性指向拥有该原型对象的构造函数,因为Foo拥有Foo.prototype,所以Foo.prototype指向Foo。

4、f1是一个实例对象,根据定义,对象的__proto__属性指向创建该对象的构造函数的原型,因为f1是由Foo创建的,所以f1.__proto__指向Foo.prototype

验证一下

2.Foo.prototype.__proto__指向哪里

新增了 Foo.prototype.__proto__指向

Foo.prototype也是一个对象,而对象都是由构造函数Object构造的,因此Foo.prototype.__proto__指向的是构造函数Object的原型对象,也就是Object.prototype

验证一下

根据这个线索我们同样也可以知道构造函数Object的prototype属性指向Object.prototype,Object.prototype的constructor属性指向构造函数Object本身。

3.Object.prototype.__proto__指向哪里

Object.prototype.__proto__也是一个对象,而对象都是由构造函数Object构造出来的,因此Object.prototype.__proto__指向的是构造函数Object的原型对象,也就是Object.prototype。

咦?难道Object.prototype.__proto__指向自己吗?

验证一下

验证一下发现,Object.prototype.__proto__指向为null,也就是说Object.prototype.__proto__没有原型。

换句话说,所有的对象可以使用__proto__属性,通过原型链找到Object.prototype,虽然Object.prototype本身也是对象,但这个对象并不是构造函数Object构造的,而是引擎自己构造了Object.prototype。

新增了 Object.prototype.__proto__指向

4.function Object.__proto__指向哪里

我们知道,Function是所有函数的构造函数,所有的函数都是通过Function生成的.而Object()本身也是一个函数,Object()是由function构造出来的,因此Object().__proto__指向的是Function.prototype

验证一下

因此,Function的prototype属性指向Function.prototype;Function.prototype的constructor属性指向Function

新增了 functionObject.__proto__指向

5.Function.__proto__指向哪里

Function()是所有函数的构造函数,那么它自己是由谁生成的呢?我们验证之后发现Function.__proto__指向的是Function.prototype

Function.__proto__指向

其实这个结论可以这样理解:所有函数都可以通过__proto__属性找到Function.prototype(就像前面的function Object()一样),而Function自己本质上也是一个函数(虽然它是其它所有构造函数的爸爸),因此按照这个逻辑,函数Function()__proto__指向Function.prototype也是可以解释的通的。

Function.prototype直接创建了一个函数Function(),除此之外的其余所有的函数都是由函数Function()创建的。因此其它函数的通过__proto__属性找到的都是Function.prototype;同样,Function()函数自己的__proto__属性也是指向Function.prototype。

其实Function.prototype也是由引擎自己创建的。首先引擎创建了Object.prototype,然后创建了Function.prototype,并且通过__proto__将二者联系起来。使得Function.prototype.__proto__指向Object.prototype

新增了 Function.__proto__指向

 

6.Foo.__proto__的指向

因为function Foo()是一个函数,而所有函数都是由Function()构造出来的,因此function Foo()指向的是Function.prototype.

新增了 function Foo.__proto__指向

总结一下:

1)function Object() 是所有对象的爸爸,因此所有对象都可以通过__proto__找到Object.prototype。

2)Function是所有函数的爸爸,所有函数都可以通过__proto__找到Function.prototype

3)引擎首先创造了Object.prototype,又创造了Function.prototype,同时让Function.prototype的__proto__指向Object.prototype.其中Function.prototype又是一个函数

4)除了上面两个,其他对象都是被Object构造出来的

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值