JavaScript中new运算符的运行机制与存在意义解析
本文深入解析JavaScript中new运算符的内部执行流程,包括空对象创建、原型链绑定及构造函数调用。通过Animal与cat示例,阐明new如何实现属性继承与实例化,并解释instanceof判断规则,揭示new在JS对象模型中实现继承的核心意义。
JavaScript中new运算符的运行机制与存在意义解析
与其他高级编程语言类似,JavaScript也提供了new运算符。通常认为,该运算符用于实例化类,进而在内存中分配一个具体的实例对象。然而,在JavaScript中“万物皆对象”,为何还需要借助new来生成对象?本文将带你深入探索JavaScript中new运算符的运作原理。
认识new运算符
一、认识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、代码解读
第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方法。
new执行流程详解
2、重点解析
第8行代码是整个流程的关键:
var cat = new Animal("cat");
JS引擎执行这句代码时,在内部做了很多工作,用伪代码模拟其工作流程如下:
new Animal("cat") = {
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的原型链为:cat->Animal.prototype->Object.prototype->null
cat对象上新增了一个属性:name
分析完cat的产生过程,我们来看看最终的输出结果:
cat.name -> 在过程(3)中,obj对象已经产生了name属性。因此,cat.name即对应这里的obj.name。
cat.color -> cat会先查找自身是否拥有color属性,若未找到则沿原型链向上查找。在上述例子中,我们仅在Animal对象上定义了color,并未在其原型链上定义,因此无法找到。
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,而是函数对象内置的属性。
一般情况下,函数对象在创建时会内置name属性,并将函数名作为其值(仅针对函数对象)。
Animal.say -> Animal在自身未找到say方法,也会沿其原型链查找。那么,Animal的原型链是什么呢?

从测试结果来看:Animal的原型链结构如下:
Animal->Function.prototype->Object.prototype->null
因此,Animal的原型链上并未定义say方法!
new存在的意义
二、new存在的意义
认识了new运算符之后,我们再回到开篇提到的问题:JavaScript中万物皆对象,为何还要通过new来产生对象?要弄明白这个问题,我们首先要搞清楚cat和Animal的关系。
通过上面的分析,我们发现cat继承了Animal中的部分属性,因此我们可以简单地理解:Animal和cat之间存在继承关系。
另一方面,cat是通过new产生的对象,那么cat到底是不是Animal的实例对象?我们先来了解一下JavaScript是如何定义“实例对象”的?
A instanceof B
如果上述表达式为true,JavaScript认为A是B的实例对象。我们用这个方法来判断一下cat和Animal。
cat instanceof Animal; //true
从执行结果看:cat确实是Animal的实例。要想证实这个结果,我们再来了解一下JavaScript中instanceof的判断规则:
var L = A.__proto__;
var R = B.prototype;
if(L === R)
return true;
如果A的__proto__等价于B的prototype,就返回true
在new的执行过程(2)中,cat的__proto__指向了Animal的prototype,因此cat和Animal符合instanceof的判断结果。所以,我们认为:cat是Animal的实例对象。
在JavaScript中,通过new可以产生原对象的一个实例对象,而这个实例对象继承了原对象的属性和方法。因此,new存在的意义在于它实现了JavaScript中的继承,而不仅仅是实例化了一个对象!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
