JavaScript原型与原型链机制解析

作者:纸飞机时间:2026-10-30 04:38:32浏览:472

本文深入解析JavaScript中普通对象与函数对象的创建机制,阐明prototype与__proto__在原型链中的不同角色。通过代码示例说明对象属性查找规则,指出原型链的形成依赖于__proto__而非prototype,并总结两者在继承与类型判断中的核心作用。

JavaScript对象分类:普通对象与函数对象

在JavaScript语言中,所有事物均可视为对象,但根据定义方式的不同,主要可划分为普通对象(Object)与函数对象(Function)两类。

通常情况下,通过new Function构造函数生成的实例属于函数对象,而其余由其他方式构建的对象均归类为普通对象。

以下通过具体代码示例进行说明:


function f1(){
  //todo
}
var f2 = function(){
  //todo
};
var f3 = new Function('x','console.log(x)');
 
var o1 = {};
var o2 = new Object();
var o3 = new f1();
 
console.log(
  typeof f1,//function
  typeof f2,//function
  typeof f3,//function
  typeof o1,//object
  typeof o2,//object
  typeof o3 //object
);
>> function function function object object object

f1采用常规函数声明方式定义,这是最常见的函数创建手段;f2则是将匿名函数赋值给变量,属于函数表达式形式;f3虽较少见,但也构成了合法的函数对象。

Function是JavaScript内置的全局对象。在f1和f2定义时,JavaScript引擎会自动通过new Function()的机制来构建这些对象实例,因此这三个变量指向的对象均是通过该内置构造函数生成的。

JavaScript中创建对象主要有两种途径:对象字面量语法和使用new表达式。o1和o2的创建分别对应了这两种方式。此处重点分析o3,若参照Java或C#等语言的思维模式,可能会误认为o3是f1的实例,且两者类型相同,但这一理解在JavaScript中并不准确。

判断的关键在于o3是否由new Function生成。显然,o3并非通过new Function创建,因此它不属于函数对象,而是普通对象。

原型与原型链机制解析

在明确函数对象与普通对象的区别后,接下来深入探讨JavaScript中的原型及原型链机制:

在JavaScript中,每当定义一个函数对象f1时,该函数内部会自动包含一些内置属性,其中包含prototype和__proto__。prototype即原型对象,它存储了f1实例共有的属性和方法。

需要特别注意,prototype属性对于函数f1本身是不可见的,这意味着在查找f1自身的属性或方法时,不会去访问prototype中的内容。


function f(){}
f.prototype.foo = "abc";
console.log(f.foo); //undefined

那么,prototype的核心用途是什么?其主要功能在于支持继承。通俗而言,prototype中定义的属性和方法是供其“后代”(即通过该函数创建的实例)使用的,因此子类实例可以访问prototype中定义的属性和方法。

要了解f1如何将prototype传递给“后代”,需理解JavaScript的原型链机制。此时,__proto__属性发挥作用。该属性较为隐蔽,但在普通对象和函数对象中均存在。它的作用是保存父类的prototype对象。当使用new表达式创建新对象时,JavaScript通常会将父类的prototype赋值给新对象的__proto__属性,从而形成链式传承。


function f(){}
f.prototype.foo = "abc";
var obj = new f();
console.log(obj.foo); //abc

已知obj对象的__proto__指向f的prototype,那么f的prototype中的__proto__又指向哪里?请参考下图:

JavaScript对象分类:普通对象与函数对象

如图所示,f.prototype的__proto__指向Object.prototype。而Object.prototype对象自身也有__proto__属性,从输出结果可见,Object.prototype.__proto__的值为null,这标志着obj对象原型链的终点。具体结构如下图所示:

JavaScript对象分类:普通对象与函数对象

当obj对象拥有上述原型链后,执行obj.foo时,JavaScript引擎会先查找obj自身是否包含该属性,但不会直接查找其自身的prototype。如果在obj自身未找到foo,引擎会沿着原型链依次向上查找。

在上述示例中,我们在f的prototype上定义了foo属性。此时,obj在原型链查找过程中即可找到该属性并执行。

核心要点总结

最后,对本文涉及的核心要点进行简要总结:

  • 原型链的形成真正依赖于__proto__而非prototype。当JavaScript引擎执行对象方法时,首先检查对象自身是否存在该方法;若不存在,则沿原型链向上查找,但不会直接查找对象自身的prototype属性。
  • 一个对象的__proto__属性记录了其原型链,决定了该对象的数据类型。修改__proto__的值即等同于改变对象的数据类型。
  • 函数的prototype属性不属于其自身的原型链,它是子类创建的核心机制,决定了子类的数据类型,并作为连接子类原型链的桥梁。
  • 在原型对象上定义方法和属性的根本目的,是为了让子类能够继承并使用这些资源。

以上就是本文的全部内容,希望对大家的学习有所帮助。

作者最新文章