JavaScript构造函数的工作原理、与普通函数的区别及原型优化

作者:半夏时间:2026-10-25 13:53:02浏览:330

本文深入解析JavaScript构造函数的执行机制,详细阐述使用new关键字时对象创建、this绑定及原型继承的过程。对比构造函数与普通函数在调用方式、this指向、返回值处理及命名规范上的核心差异,并指出传统构造函数导致的方法重复定义与内存浪费问题。最后介绍通过全局函数和原型对象两种方案解决方法复用问题的思路,重点推荐利用prototype优化内存使用的最佳实践。

构造函数是指利用函数来初始化使用new运算符创建的新对象,这类函数被称为构造函数(constructor)。

function Person(){
    this.name = "zqq";
    this.age = 28;
}
var p = new Person();

当通过new调用构造函数(例如执行var p = new Person())时,函数内部会依次执行以下操作:

首先创建一个空对象。

var p = {};

接着将this变量指向该新对象p。

Person.call(p)

然后使p继承构造函数Person()的原型属性。

p.__proto__ = Person.prototype

最后执行构造函数Person()内部的代码逻辑。

构造函数与普通函数的主要区别体现在以下几个方面:

第一,构造函数必须使用new关键字进行调用,而普通函数则不需要。

var p = new Person();
var p = Person();

第二,构造函数内部可以使用this关键字;而在普通函数中不建议使用this,因为此时this通常指向window全局对象,这可能导致无意间为window添加全局变量或函数。

在构造函数内部,this指向的是正在构造的新对象实例。

在普通函数内部,this指向的是window全局对象。

第三,构造函数默认不使用return语句返回特定值;而普通函数通常会有明确的return返回值。

构造函数会默认返回this,即新创建的实例对象。

如果普通函数没有指定return值,则返回undefined。

若使用了return语句,返回值的类型取决于return后面跟随的值类型。

return的是五种简单数据类型:String,Number,Boolean,Null,Undefined的话,构造函数会忽略return的值,依然返回this对象;而普通函数会返回return后面的值
 
function Person(){
    var a;
    this.name = "zqq";
    this.age = 28;
    return a;
}
var p = new Person();//返回this对象
var p = Person();//因为a没初始化,所以a是undefined,而undefined属于简单数据类型,所以返回undefined,String,Number,Boolean,Null同理
 
 
如果return的是引用类型:Array,Date,Object,Function,RegExp,Error的话,构造函数和普通函数都会返回return后面的值
 
function Person(){
    var arr = [];
    this.name = "zqq";
    this.age = 28;
    return arr;
}
var p = new Person();//返回arr空数组,Date,Object,Function,RegExp,Error同理
var p1 = new Person();//返回arr空数组,Date,Object,Function,RegExp,Error同理

第四,构造函数名称建议首字母大写;普通函数名称建议首字母小写。

接下来分析构造函数的优点与缺点。

其优点在于可以通过instanceof操作符识别对象类型;缺点则是每次实例化对象时,都会将属性和方法复制一份。

function CreateObj(uName) {
              this.userName = uName;
              this.showUserName = function () {
              return this.userName;
            }
        }
 
var obj1 = new CreateObj('ghostwu');
var obj2 = new CreateObj('卫庄');
 
console.log( obj1.showUserName === obj2.showUserName ); //false

从执行结果可以看出,obj1.showUserName和obj.showUserName并非同一个函数引用。在JavaScript中,引用类型比较的是内存地址,函数属于引用类型,因此它们存在于两个不同的内存地址中。虽然每个对象的属性可能不同,但方法执行的代码逻辑完全一致,因此没有必要为每个对象复制一份方法,这会造成内存浪费,这也是构造函数的主要缺点。

如何避免构造函数中方法被多次复制的问题?

function CreateObj(uName) {
  this.userName = uName;
  this.showUserName = showUserName;
}
function showUserName() {
  return this.userName;
}
var obj1 = new CreateObj('ghostwu');
var obj2 = new CreateObj('卫庄');
console.log(obj1.showUserName === obj2.showUserName); //true

一种做法是将对象的方法指向同一个全局函数showUserName。虽然这解决了多次复制的问题,但全局函数极易被覆盖,即常说的全局变量污染问题。

是否存在更优的解决方案?

较好的解决方式是通过原型(prototype)对象,将方法定义在构造函数的原型上。

function CreateObj(uName) {
  this.userName = uName;
}
CreateObj.prototype.showUserName = function () {
  return this.userName;
}
var obj1 = new CreateObj('ghostwu');
var obj2 = new CreateObj('卫庄');
console.log(obj1.showUserName === obj2.showUserName); //true

以上为本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章