一、构造函数介绍:
在JavaScript中,构造函数是用于创建和初始化一个由new关键字生成的对象的特殊函数。构造函数的名字通常以大写字母开头,但这并不是JavaScript语法的一部分,而是一种约定俗成的命名规范,有助于区分构造函数和普通函数。
- 示例:
function Person(name, age) {  
    this.name = name;  
    this.age = age;  
  
    // 还可以添加其他方法和属性  
    this.say= function() {  
        console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);  
    };  
}  
  
// 使用new关键字和构造函数创建一个新的Person对象  
var obj = new Person('xiaoming', 30);  
  
// 访问对象的属性和方法  
console.log(obj.name); // 输出: xiaoming
console.log(obj.age);  // 输出: 30  
obj.say();            // 输出: Hello, my name is xiaoming and I'm 30 years old.
在上面的例子中,Person是一个构造函数,它接受两个参数name和age,并使用this关键字来设置新创建对象的属性。this在构造函数中引用的是新创建的对象。
构造函数的一个常见错误是忘记使用
new关键字来调用它们。如果忘记使用new,那么this将不会引用新创建的对象,而是引用全局对象(在浏览器中是window对象)。这通常会导致意外的全局变量和难以调试的错误。
二、构造函数特点
- 命名约定:
 构造函数的命名通常以大写字母开头,以区分它们与其他函数(尽管这不是强制性的,但遵循这个约定可以提高代码的可读性)。
- 使用new关键字:
 当你使用new关键字和一个构造函数时,JavaScript会创建一个新的空对象,将这个新对象的[[Prototype]](内部链接)链接到构造函数的prototype对象上,然后将this关键字绑定到这个新对象上,并执行构造函数中的代码。
- this关键字:
 在构造函数内部,- this关键字引用的是新创建的对象实例。你可以使用- this来设置新对象的属性或方法。
- prototype属性:
 每个构造函数都有一个- prototype属性,它是一个对象,用于存储所有实例共享的属性和方法。当你创建一个新对象时,这个新对象会继承构造函数的- prototype对象上的属性和方法。
- 返回值:
 通常,构造函数不返回任何值(或返回this,这是隐式的)。然而,如果构造函数显式地返回了一个非原始值(如对象或数组),那么这个值将替代新创建的对象作为new表达式的返回值。但是,如果返回的是原始值(如number、string、boolean、null或undefined),那么新创建的对象仍然会被返回。
- 继承:
 JavaScript中的继承通常通过修改原型链或使用ES6中的class语法(它是基于原型链的语法糖)来实现。构造函数可以通过其prototype属性参与原型链,从而允许子类继承父类的属性和方法。
三、简易实现
示例1:
// 假如一个普通函数Person
function Person(name, age) {  
    const obj = {};
    obj.name = name;  
    obj.age = age; 
    obj.__proto__ = Person.prototype
    return obj
}  
const a = Person('a', 20)

示例2:
// 定义构造函数Person
function Person(name, age) {  
    this.name = name;  
    this.age = age; 
}  
const a = new Person('a', 20)

四、与普通函数区别
构造函数(Constructor Functions)和普通函数(Regular Functions)主要差异:
- 使用 new关键字:- 构造函数通常与 new关键字一起使用来创建和初始化对象。当使用new关键字调用一个函数时,这个函数就被当作构造函数来使用。
- 普通函数则不需要使用 new关键字来调用,它们通常用于执行某些操作或返回某个值。
 
- 构造函数通常与 
- this的行为:- 在构造函数中,this关键字引用的是通过new创建的新对象。构造函数内部通常使用this来为新对象添加属性和方法。
- 在普通函数中,this的值取决于函数如何被调用。如果函数作为普通函数调用,this通常指向全局对象(在浏览器中是window)。但如果函数作为对象的方法被调用,this将指向调用该方法的对象。此外,还可以使用Function.prototype.call、Function.prototype.apply或箭头函数来显式设置this的值。
 
- 在构造函数中,
- 返回值: 
  - 如果构造函数没有显式地返回一个对象,那么 new表达式将返回新创建的对象。如果构造函数显式地返回了一个非原始值(如对象或数组),那么这个值将替代新创建的对象作为new表达式的返回值(但这种情况很少见,通常不建议这样做)。
- 普通函数可以返回任何类型的值,包括原始值和对象。返回值由函数体内的 return语句确定。
 
- 如果构造函数没有显式地返回一个对象,那么 
- 命名约定: 
  - 虽然JavaScript并没有强制要求构造函数和普通函数有不同的命名方式,但按照惯例,构造函数通常使用大驼峰命名法(PascalCase),即首字母大写的命名方式(例如Person、Car等)。
- 普通函数则可以使用任何有效的命名方式,但通常使用小驼峰命名法(camelCase),即首字母小写的命名方式(例如calculateSum、greetUser等)。
 
- 虽然
- 目的: 
  - 构造函数的主要目的是创建和初始化对象,为新对象设置属性和方法。
- 普通函数则用于执行各种任务,如计算、数据处理、逻辑判断等。
 
- 原型链: 
  - 构造函数与原型链密切相关。每个构造函数都有一个 prototype属性,这个属性是一个对象,包含可以由构造函数创建的所有实例共享的属性和方法。通过原型链,我们可以实现继承和其他面向对象的编程模式。
- 普通函数也可以有原型,但它们的原型通常不用于创建实例共享的属性和方法。
 
- 构造函数与原型链密切相关。每个构造函数都有一个 
- instanceof操作符:- 由于构造函数创建的实例与构造函数之间存在一种特殊的联系,因此我们可以使用 instanceof操作符来检测一个对象是否由某个构造函数创建。
- 普通函数与它们调用的结果之间不存在这种联系,因此不能使用 instanceof操作符来检测。
 
- 由于构造函数创建的实例与构造函数之间存在一种特殊的联系,因此我们可以使用 




















