一、构造函数介绍:
在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
操作符来检测。
- 由于构造函数创建的实例与构造函数之间存在一种特殊的联系,因此我们可以使用