JavaScript中new关键字详解:原型继承与执行机制

作者:小括号时间:2026-10-29 18:48:56浏览:625

本文深入解析JavaScript中new关键字的实际作用与执行机制。通过具体代码示例,详细拆解new操作在创建对象、绑定原型链、执行构造函数及处理返回值时的完整流程,阐明其核心功能在于实现原型继承而非简单的实例创建。

JavaScript中new关键字详解:原型继承与执行机制

与其他高级编程语言类似,JavaScript也提供了new关键字。传统观念中,new通常用于创建类的实例,但在JavaScript这种万物皆对象的体系中,使用new的意义何在?实际上,JavaScript中的new并非单纯为了创建类的实例,其核心作用在于实现继承机制。下文将详细剖析JavaScript中new关键字的具体运作原理。


function Animal(name){
  this.name = name;
}
Animal.color = "black";
Animal.prototype.say = function(){
  console.log("I'm " + this.name);
};
var cat = new Animal("cat");

console.log(
  cat.name, //cat
  cat.height //undefined
);
cat.say(); //I'm cat

console.log(
  Animal.name, //Animal
  Animal.color //back
);
Animal.say(); //Animal.say is not a function

若能理解前文输出的结果,表明你对JavaScript中new关键字及this关键字的运行机制已有深入掌握,可直接跳过本文。

我们将通过解析具体代码示例,进一步加深你对JavaScript中new关键字及继承机制的理解。若对JavaScript中的this关键字尚不熟悉,建议先阅读相关教程:JS作用域和this关键字。

代码解读

一、代码解读

第1至3行代码定义了一个名为Animal的函数,并在该函数的this上下文中定义了属性name,其值取决于函数执行时传入的形参。

第4行代码在Animal函数对象本身(注意:函数也是对象)上定义了一个静态属性color,并将其赋值为字符串“black”。

第5至7行代码在Animal函数的原型对象prototype上定义了一个名为say()的方法,该方法用于输出this所指向的name属性值。

第8行代码使用new关键字创建了一个名为cat的新对象。

第10至14行代码中,cat对象尝试访问name和color属性,并调用say方法。

第16至20行代码中,Animal对象尝试访问name和color属性,并调用say方法。

重点解析

二、重点解析

第8行代码是整个示例的关键所在:


var cat = new Animal("cat");

JavaScript引擎在执行该语句时执行了多项内部操作,以下伪代码模拟了其工作流程:


 var obj = {};
 obj.__proto__ = Animal.prototype;
 var result = Animal.call(obj,"cat");
 return typeof result === 'obj'? result : obj;

(1)创建一个空对象obj;

(2)将obj的__proto__属性指向Animal的原型对象prototype,从而建立obj对象的原型链:obj->Animal.prototype->Object.prototype->null。

若对JavaScript原型链概念尚不熟悉,建议先阅读相关教程:JS原型和原型链。

(3)在obj对象的执行上下文中调用Animal函数,并传递参数“cat”。这相当于执行var result = obj.Animal("cat")。

执行完上述语句后,obj对象便产生了属性name,并赋值为“cat”。关于JavaScript中call方法的用法,建议阅读相关教程:JS的call和apply。

(4)检查第3步中函数的返回值。若无返回值或返回值不是对象类型,则返回obj作为新对象;否则,将返回值作为新对象返回。

了解new的运行机制后,我们知道cat实际上是过程(4)的返回值,因此我们对cat对象的认知可进一步补充:

cat的原型链结构为:obj->Animal.prototype->Object.prototype->null。

cat对象上新增了一个属性:name。

分析完cat对象的生成过程,我们再来查看输出结果:

cat.name -> 在过程(3)中,obj对象已生成name属性。因此,cat.name即对应这里的obj.name。

cat.color -> cat会先查找自身是否包含color属性,若未找到则沿原型链向上查找。在上述示例中,color仅在Animal对象上定义为静态属性,并未定义在其原型链上,因此无法找到。

cat.say -> cat会先查找自身是否包含say方法,若未找到则沿原型链向上查找。在上述示例中,我们在Animal的prototype上定义了say方法,因此能在原型链中找到该方法。

此外,在say方法中还访问了this.name,此时的this指向其调用者obj,因此输出的是obj.name的值。

对于Animal对象而言,它本身也是一个对象,因此在访问属性和方法时同样遵循上述查找规则,故:

Animal.color -> 返回“black”。

Animal.name -> 返回“Animal”。Animal先查找自身的name属性并找到,但需注意:此处的name并非我们自定义的name,而是函数对象内置的属性。

通常情况下,函数对象在创建时会内置name属性,并将函数名作为其值(仅适用于函数对象)。

Animal.say -> Animal在自身未找到say方法,会沿其原型链继续查找。那么,Animal的原型链结构是什么呢?

JavaScript中new关键字详解:原型继承与执行机制

从调试结果可以看出:

Animal的原型链结构为:

因此,Animal的原型链上并未定义say方法。

综上所述,JavaScript的new关键字主要作用是实现继承。在上述示例中,cat对象在生成时便继承了Animal中定义的方法和属性,因此,从某种不严谨的角度看,cat不是Animal的实例,而是其子类。可能有人会想:既然cat是通过new生成的,那cat和Animal应该是同类型的。我认为,既然是父类与子类的关系,它们就不可能是同类型。不信,请看:

JavaScript中new关键字详解:原型继承与执行机制

javascript 使用new关键字的区别

javascript 使用new关键字的区别

第一种方式使用new关键字以原型的方式将user对象暴露到window对象中


//one
var user = function(){
  this.name="";
  this.id="";
};
user.add = function(){
  console.log("add");
};
user.delete = function(){
  console.log("delete");
};
user.prototype = user;
window.user = new user();

第二种方式不使用new关键字直接将user对象暴露到window对象中


//two
var user = {
  name:"",
  id:""
};
user.add = function(){
  console.log("add");
};
user.delete = function(){
  console.log("delete");
};
window.user = user;

使用


<button onclick="user.add()">增加</button>
<button onclick="user.delete()">删除</button>

作者最新文章