深入理解 JavaScript 对象的 Property 与 Prototype 链

作者:代码拾荒

时间:2026-10-30

浏览:397

本文详细解析 JavaScript 中 Native Object 与 Host Object 的区别,重点阐述对象属性(Property)的读写机制以及原型(Prototype)链的工作原理。通过具体代码示例,说明赋值与取值操作在对象自身属性与原型链查找过程中的差异,揭示 JavaScript 面向对象编程的核心机制。

文章目录

JavaScript 对象类型概述

ECMAScript 标准将对象划分为两类:一类是 Native Object,属于语言规范范畴;另一类是 Host Object,由运行环境提供,例如 document 对象。


Dom Node 等


Native Object 具有松散的结构,支持动态添加属性(property)。每个属性都包含一个名称和一个值,该值可以是另一个对象的引用。


或者是一个内置的数据类型(String、Number、Boolean、Null 或 Undefined)。


以下简单示例展示了 JavaScript 对象如何设置属性值以及如何读取属性值。


对象属性的赋值操作

赋值操作


创建对象属性非常简单,直接通过赋值操作即可完成属性的创建。



var objectRef = new Object(); //create a generic javascript object.


可以这样创建一个名为 testNumber 的属性。



objectRef.testNumber = 5;


/* - or:- */


objectRef["testNumber"] = 5;


如果复制的属性名称已经存在,则不会再次创建该属性,赋值操作仅仅是重新设置属性的值。



objectRef.testNumber = 8;


/* - or:- */


objectRef["testNumber"] = 8;


JavaScript 对象的原型(prototype)本身也可以是一个对象,并且可以拥有属性(property)。对 JS 对象 prototype 的赋值操作与普通对象属性的创建方式没有区别。


没什么不同。


对象属性的取值与原型链机制

取值操作


在取值操作中,property 和 prototype 的行为有所不同,先来看最简单的 property 取值操作。



/*为一个对象的属性赋值,如果这个对象没有这个属性,那么在赋值操作后,这个对象就有这个属性了 */


objectRef.testNumber = 8;


/* 读出这个属性的值 */


var val = objectRef.testNumber;


/* 现在val 就得到了刚才赋予objectRef的值8了*/


Prototype 链的工作原理

prototype揭密


所有对象都可以拥有 prototypes,prototypes 本身也是对象,因此它们也可以拥有自己的 prototypes。这样循环下去便形成了一个 prototype 链,当链中对应的 prototype 为 null 时中止(Object 的默认 prototype 是 null)。


这个链当他遇到链中队形的prototype是null时中止。(Object的默认的prototype是null)



var objectRef = new Object(); //create a generic javascript object.


创建一个新的 JS 对象时,该对象的 prototype 为 Null,因此 objectRef 的 prototype 链仅包含一个对象 Object.prototype。


我们在看下面的



/* 构建MyObject1这个类型的构造函数


MyObject1 - type.


*/  

function MyObject1(formalParameter){


/* 为者对象创建一个属性名字叫testNumber


    */  

this.testNumber = formalParameter;


}   

/* 构建MyObject2这个类型的构造函数


MyObject2 - type:-


*/  

function MyObject2(formalParameter){


/* 为者对象创建一个属性名字叫testString*/


this.testString = formalParameter;


}   

/* 下一步的操作会用MyObject1对象替换掉MyObject2默认的prototype属性*/


MyObject2.prototype = new MyObject1( 8 );


/* 最后我们创建MyObject2类型的一个对象*/


var objectRef = new MyObject2( "String_Value" );


objectRef 这个 MyObject2 类型的对象拥有一个 prototype 链,链中的第一个对象是 MyObject1 对象。MyObject1 对象也有 prototype,


这个 prototype 是 Object 默认的 prototype,Object.prototype 的 prototype 是 null,至此这条 prototype 链结束。


当一个取值操作发生时,objectRef 的整个 prototype 链就开始工作



var val = objectRef.testString;


objectRef 这个对象有一个属性叫做 testString,那么这句会把 testString 的值赋给 val



var val = objectRef.testNumber;


在 objectRef 这个对象里并没有 testNumber 这个属性,但是 val 却得到了值 8,而不是 undefine。这是因为解释器在没有在当前对象找到要找


的属性后,就会去检查这个对象的 prototype。objectRef 的 prototype 是 MyObject1 对象,这个对象有 testNumber 这个属性,所以 val 得到 8 这个值。



var val = objectRef.toString;


现在 val 是个 function 的引用,这个 function 是 Object.prototype 的 property。由于 MyObject1 和 MyObject2 都没有定义 toString 这个 property


所以 Object.prototype 返回。



var val = objectRef.madeUpProperty;


最后 val 是 undefined,因为 MyObject1 和 MyObject2,还有 Object 都没有定义 madeUpProperty 这个 property,所以得到的是 undefine。


读写操作对原型链的影响

读操作会读取在 obj 自己和 prototype 链上发现的第一个同名属性值


写操作会为 obj 对象本身创建一个同名属性(如果这个属性名不存在


这就意味着 objectRef.testNumber = 3 会在 objectRef 对象上创建一个 property,名字是 testNumber。当下一次在要读取 testNumber 时


propertype 链就不会工作,仅仅会得到 objectRef 的 property 3,而 MyObject1 的 testNumber 属性并不会被修改。下面的可以验证



/* 构建MyObject1这个类型的构造函数


MyObject1 - type.


*/  

function MyObject1(formalParameter){


/* 为者对象创建一个属性名字叫testNumber


    */  

this.testNumber = formalParameter;


}   

/* 构建MyObject2这个类型的构造函数


MyObject2 - type:-


*/  

function MyObject2(formalParameter){


/* 为者对象创建一个属性名字叫testString*/


this.testString = formalParameter;


}   

/* 下一步的操作会用MyObject1对象替换掉MyObject2默认的prototype属性*/


var obj1 = new MyObject1( 8 );


MyObject2.prototype = obj1;


/* 最后我们创建MyObject2类型的一个对象*/


var objectRef = new MyObject2( "String_Value" );


alert(objectRef.testNumber);


objectRef.testNumber = 5;


alert(objectRef.testNumber);


alert(obj1.testNumber);

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章