JavaScript原型属性修改机制与值传递详解

作者:半夏

时间:2026-10-27

浏览:513

本文深入解析JavaScript中修改原型属性的两种行为:直接赋值会切断引用并在实例中创建新属性,而修改引用类型成员则影响所有实例。通过Person实例测试,阐明值传递与引用传递的区别,指出直接修改原型值类型的误区及正确实践。

文章目录

JavaScript原型属性修改机制与值传递详解

在JavaScript中,原型(prototype)用于定义特定类型所有实例共享的属性和方法。许多开发者在尝试重新赋值原型属性时容易犯错,导致不可预知的结果。本文通过具体测试案例,对这一知识点进行梳理和总结,帮助初学者避免常见陷阱。



首先定义一个基本类型的原型结构:


代码如下:

 
function Person(){}
Person.prototype={
constructor:Person,
name:"person",
age:100,
friends:["a","b"],
getName:function(){
return this.name;
} 
}; 

原型属性覆盖测试:值类型属性的修改行为

接下来定义两个Person实例,并尝试修改定义在原型中的name属性。测试代码如下:


代码如下:

 
var p1=new Person();
var p2=new Person();
document.write(p1.name+"<br/>"); //person
document.write(p2.name+"<br/>"); //person
p1.name="p1";
document.write(p1.name+"<br/>"); //p1
document.write(p2.name+"<br/>"); //person
document.write(p1.hasOwnProperty("name")+"<br/>"); //true 属于对象
document.write(p2.hasOwnProperty("name")+"<br/>"); //false 属于原型
document.write(Object.keys(p1)+"<br/>"); //name
document.write(Object.keys(p2)+"<br/>"); // 空
document.write(Object.getOwnPropertyNames(Person.prototype)+"<br/>"); //constructor,name,age,friends,getName
document.write(Person.prototype.name+"<br/>"); //person

值传递与引用切断机制分析

通过上述测试可以发现,执行p1.name="p1"并没有修改原型中name的值,而是在实例p1中创建了一个新的同名属性,从而覆盖了从原型继承的name属性。后续判断证实,此时p1的name已成为实例属性而非原型属性。Object.keys(p1)的结果也表明,p1实例中多了一个name属性,而p2没有。在JavaScript中,所有赋值操作都是值传递,这里的“值”是指向引用类型的指针。因此,等号赋值并非修改原对象,而是切断了原有引用关系并指向了新对象。下文将通过代码进一步说明这一机制。


代码如下:

 
var obj=new Object();
obj.name="obj";
function changeObj(o){
o.name="changed";
o=new Object();
o.name="newObj";
} 
changeObj(obj);
document.write(obj.name); //changed

在changeObj函数内部,执行o=new Object()并没有修改传入参数obj的值,而是让局部变量o指向了新对象,切断了与原obj的引用联系。因此最终输出结果是“changed”而非“newObj”。



引用类型属性的共享与覆盖测试

接下来测试修改第一个例子中原型上的friends属性,该属性为引用类型(数组)。


代码如下:

 
p1.friends.push("c");
document.write(p1.friends+"<br/>"); //a,b,c
document.write(p2.friends+"<br/>"); //a,b,c
p1.friends=["x","y","z"];
document.write(p1.friends+"<br/>"); //x,y,z
document.write(p2.friends+"<br/>"); //a,b,c
document.write(p1.hasOwnProperty("friends")+"<br/>"); //true 属于对象
document.write(p2.hasOwnProperty("friends")+"<br/>"); //false 属于原型
document.write(Object.keys(p1)+"<br/>"); //name,friend
document.write(Object.keys(p2)+"<br/>"); //空
document.write(Object.getOwnPropertyNames(Person.prototype)+"<br/>"); //constructor,name,age,friends,getName
document.write(Person.prototype.friends+"<br/>"); //a,b,c

此次测试结果与第一次测试基本一致。当通过等号直接赋值修改friends时,会切断原有的引用关系,并为实例p1创建一个新的属性,该属性覆盖了原型中的同名属性。



基于以上两个测试结果可以发现,在实例中直接修改原型中的值类型属性(如字符串、数字)或引用类型属性(如数组对象)时,行为有所不同:直接赋值会创建实例属性并覆盖原型属性;而通过方法修改引用类型成员(如push)则会共享影响所有实例。当然,将值类型属性定义在原型中本身并不符合最佳实践,此处仅为演示知识点。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章