JavaScript 构造函数与普通函数的核心区别及 new 关键字原理

作者:半夏时间:2026-10-29 08:17:58浏览:286

本文深入解析 JavaScript 中构造函数与普通函数的区别,重点阐述 new 关键字执行时的四个步骤(创建对象、绑定 this、关联原型、执行代码)。同时详细说明 call/apply 的作用以及构造函数中 return 语句对返回值的不同影响,帮助开发者准确理解对象创建机制。

问题概述

问题

什么是构造函数? 构造函数与普通函数区别是什么? 用new关键字的时候到底做了什么? 构造函数有返回值怎么办? 构造函数能当普通函数调用吗?

以下是我的一些理解,理解错误的地方恳请大家帮忙指正,谢谢!

this 指向机制

关于 this 关键字 this 始终指向当前正在执行函数或方法的拥有者(owner)。例如:


function test(){
  console.log(this);
}
test();
//Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

在上述代码中,我们在页面中定义了一个 test() 函数并直接调用。当函数定义在全局作用域时,其拥有者即为当前页面,也就是 window 对象。

this 指向的几种常见情况

1. 全局作用域中调用

this.name // this 指向 window 对象 2. 普通函数调用

test();// test() 函数内部的 this 同样指向 window 对象 3. 对象方法调用

obj1.fn();// obj1 对象的 fn() 方法中,this 指向 obj1 4. 调用构造函数 var dog=new Dog();// 构造函数内部的 this 指向新创建的实例对象,即这里的 dog

call 和 apply 的作用相同,仅参数传递方式不同:call 接受多个独立参数,apply 接受参数数组。 简单来说,call 和 apply 用于当一个对象缺少某个函数或方法时,调用另一个对象的现成函数/方法。其核心机制是通过替换 this 为当前对象实例,从而改变函数运行时的上下文环境。 例如:


function Dog(){
  this.sound="汪汪汪";
}
Dog.prototype.bark=function(){
  alert(this.sound);
}

现在我有另一个 cat 对象:

var cat={sound:'喵喵喵'}

我希望让 cat 对象也能调用 bark 方法,此时无需重新定义,可直接通过 call/apply 调用 Dog 类的 bark 方法:

Dog.prototype.bark.call(cat);

或者:

dog.bark.call(cat);

增加参数传递的示例:


function Dog(){
  this.sound="汪汪汪";
}
Dog.prototype.bark=function(words){
  alert(this.sound+" "+words);
}
var dog=new Dog();
dog.bark("有小偷");//alert:汪汪汪  有小偷
Dog.prototype.bark.call(cat,"饿了");//alert:喵喵喵  饿了

普通函数与构造函数的区别

普通函数 这是一个简单的普通函数:


function fn(){
  alert("hello sheila");
}
fn();//alert:hello sheila

与普通函数相比,构造函数具有以下四个显著特点:

1. 无需使用 new 关键字调用

fn();2. 可以使用 return 语句返回值


 function fn(a,b){
    return a+b;
  }
  alert(fn(2,3));//alert:5

3. 函数内部不建议使用 this 关键字 我们之所以说不建议使用,是因为若强行使用需注意其后果。如果在普通函数内部使用 this 定义变量或函数,由于此时 this 指向全局 window 对象,这将无意中为 window 添加全局变量或函数。


function greeting(){
    this.name="sheila";
    alert("hello "+this.name);
  }
  greeting();//alert:hello sheila
  alert(window.name);//alert:sheila

4. 函数命名采用驼峰式,且首字母小写

构造函数 在 JavaScript 中,使用 new 关键字来调用定义的构造函数。默认情况下,它返回一个新对象,该对象拥有构造函数中定义的变量和函数/方法。

举个栗子:


function Prince(name,age){
  this.gender="male";
  this.kind=true;
  this.rich=true;
  this.name=name;
  this.age=age;
}
Prince.prototype.toFrog=function(){
  console.log("Prince "+this.name+" turned into a frog.");
}
var prince=new Prince("charming",25);
prince.toFrog();//Prince charming turned into a frog.
prince.kind;//true

与普通函数相比,构造函数具有以下显著特点:

1. 必须使用 new 关键字调用

var prince=new Prince("charming",25);

2. 函数内部可以使用 this 关键字 在构造函数内部,this 指向正在构建的新对象。使用 this 定义的变量或函数/方法即为实例变量或实例函数/方法。这些成员必须通过实例才能访问,无法通过类型名直接访问。

prince.age;//25 Prince.age;//undefined

3. 默认不使用 return 返回值 构造函数无需显式使用 return 返回特定值,默认会返回 this,即新创建的实例对象。当然,也可以使用 return 语句,但返回值的具体表现取决于 return 值的类型,细节将在下文介绍。

4. 函数命名建议首字母大写,以便与普通函数区分。 这并非严格的命名规范,但作为一种良好的编码习惯建议如此书写。

new 关键字执行原理与返回值处理

使用 new 关键字实例化时发生了什么? 以上文中的 Prince() 函数为例:

1. 第一步,创建一个空对象。

var prince={}

2. 第二步,将构造函数 Prince() 中的 this 指向新创建的对象 prince。 3. 第三步,将 prince 的 __proto__ 属性指向 Prince 函数的 prototype,从而建立对象与原型之间的关系。 4. 第四步,执行构造函数 Prince() 内部的代码。

构造函数有 return 值怎么办? 当构造函数内部没有显式调用 return 时,默认返回 this 对象,即新创建的实例对象。 当构造函数内部调用 return 时,分为两种情况:

1. return 的是五种简单数据类型:String,Number,Boolean,Null,Undefined。 在这种情况下,忽略 return 的值,依然返回 this 对象。

2. return 的是 Object 在这种情况下,不再返回 this 对象,而是返回 return 语句指定的返回值。


function Person(name){
    this.name=name;
    return {name:"cherry"}
  }
  var person=new Person("sheila");
  person.name;//cherry
  p;//Object {name: "cherry"}
作者最新文章