javaScript的原型机制

之前对于原型、原型链这部分比较模糊,最近刚好有时间,整理一下以加深理解记忆

一、相关知识介绍

1、属性

_proto_属性:对象特有的,由于js中一切皆对象,故函数中也包含_proto_属性。
在这里插入图片描述

2、对象

对象是由构造函数创建。js中一切皆对象。因此构造函数也是对象。
在这里插入图片描述

3、结论

(1)所有对象原型链的顶端是Object.prototype;
(2)所有对象的_proto_属性均指向Function.prototype。构造函数创建的对象都是Function的实例。
(3)除了Object,所有对象(即构造函数)的prototype均继承自Object.prototype。
在这里插入图片描述

二、原型机制设计

在JavaScript中,有两个祖先一样的对象:Function.prototype和 Object.prototype。

(1) Object.prototype是所有对象的根;

(2) Function.prototype是所有构造器的根(除Object外);

事实上所有对象都维护着一个{prototype}属性,这是一个内部的私有属性,无法通过对象来访问。不过在firefox等浏览器中提供了一个共有属性__proto__来访问这个私有属性。在Js中公有属性名和私有属性名可以相同。

1、Object.prototype

(1)通用属性

  1. Constructor:对创建对象的函数(构造器)的引用(指针),这里为Object,主要是为了Object.prototype也属于Object类型;设计的需要,实际上不是Object构造的。
  2. Prototype:私有的prototype属性,也就是__proto__的值,这里Object.prototype为null。

(2)通用方法

  1. hasOwnProperty(property):判断对象是否有某个特定的属性。必须用字符串指定该属性 (例如o.hasOwnProperty(”name”))。

  2. isPrototypeOf(object):判断该对象是否为另一个对象的原型。

  3. propertyIsEnumerable(property):判断给定的属性是否可以用for…in语句进行枚举。

  4. toString():返回对象的原始字符串表示。对于Object类,ECMA-262没有定义这个值,所以不同的ECMAScriipt实现具有不同的值。

  5. valueOf():返回最适合该对象的原值。对于许多类,该方法返回的值都与toString()的返回值相同。

2、Function.prototype

(1)通用属性

  1. 0…n属性:这是arguments取参数时的索引,0——n

  2. arguments属性:存储存进来所有参数,相当于可变参数参数列表。

  3. callee属性:引用当前函数对象,用于函数递归,特别是在匿名函数中特别有用。

  4. caller属性:返回调用某个函数的函数对象。

  5. constructor属性:Function.prototype的构造器是Function.

  6. length属性:当创建一个函数的实例时,函数的 length 属性由脚本引擎初始化为该函数定义中的参数数目。

  7. prototype属性:内部{Prototype}——也即__proto__,为Object.prototype。

(2)通用方法

  1. apply():用法同call()函数,不同点在于apply()仅接受数组传参,不接受单个参数传参。

  2. call():用来调用所有者对象作为参数的方法,用法a.call(b,c,d);意思是将a方法用于b对象,好像b对象也拥有a方法一样,其中c,d均为传递给a方法的参数。(仅接受单独传参,不能接受数组传参)

  3. toString():将对象转换成字符串。

  4. valueOf():可返回 String 对象的原始值。常由 JavaScript 在后台自动进行调用,而不是显式地处于代码中。

三、原型链

如有三个类,也即A,B,C(其实就是构造器——函数对象),如B继承A,C继承B,那么就等价于:

function A(){};    //A.prototype = Object.prototype     A.__proto__ = Function.prototype
function B(){};   //类推
function C(){};  //类推
B.protype = new A();
C.prototype = new B();
var c = new C();

c中维护着一个B的实例,而这个B的实例中又维护着一个A的实例的引用。等价于:

function A(){};
function B(){};
function C(){};
var a = new A();
B.prototype = a;
var b = new B();
C.prototype = b;
c = new C();

也即c中维护着一个B的实例b的引用,而b中维护着一个A的实例a的引用。即这里的继承其实也就是共享对象,而且可以形成共享链。

(a)没有继承之前:

function A(){};
function B(){};
function C(){};
var a = new A();
var b = new B();
var c = new C();

结构如图:
在这里插入图片描述
分析:

constructor是对创建对象的函数(构造器)的引用(指针)。
prototype是函数特有的属性,其中存储了要共享的属性和方法,不过prototype是一个私有属性,无法通过对象来访问。
_proto_属性指向创建对象的构造函数的原型prototype,故而可以借用_proto_访问私有属性prototype。

(b)继承之后:

function A(){};
function B(){};
function C(){};
var a = new A();
B.prototype = a;
var b = new B();
C.prototype = b;
c = new C();

结构如图:
在这里插入图片描述

由此更加能够表示,其实所谓的继承就是对象共享,是一种链式的间接访问,比如B知道a的地址,那么B的所有子孙也就知道a的地址,自然也就能访问。但是每个B的子孙知道的是同一个a,而不是a的副本。同理C知道b(B的一个实例)的地址,那么C的所有实例也知道b的地址,而b又知道a的地址。所以c(C的一个实例)能够访问b,通过b又能访问a。如果我们把对象看成一个集合的话,那么b={…,&a},c={…,b={…,a}};
也就是a的引用&a属于b,且包含于b;b的引用&b属于c,也包含于c。

原型链的表示为:b.proto = a;c.proto = b;c.proto.proto = a;

参考文献:https://www.2cto.com/kf/201401/269806.html

发布了33 篇原创文章 · 获赞 35 · 访问量 813

猜你喜欢

转载自blog.csdn.net/chaopingyao/article/details/104631570