JavaScript 构造函数与原型
构造函数与原型是 JavaScript 创建对象和实现共享方法的基础机制,理解它们是掌握原型链的关键。
构造函数
JavaScript
// 构造函数:用于创建同类对象
function Person(name, age) {
// this 指向新创建的实例
this.name = name;
this.age = age;
}
// 使用 new 调用
const p1 = new Person('Tom', 25);
const p2 = new Person('Jerry', 30);
console.log(p1.name); // 'Tom'
console.log(p2.name); // 'Jerry'
console.log(p1.constructor === Person); // true
new 操作符执行流程
JavaScript
// new 做了四件事:
function Person(name) {
this.name = name;
}
const p = new Person('Tom');
// 等价于:
const p = Object.create(Person.prototype); // 1. 创建空对象,继承原型
Person.call(p, 'Tom'); // 2. 执行构造函数,绑定 this
return p; // 3. 返回新对象(除非构造函数返回对象)
原型对象 prototype
JavaScript
// prototype:存储实例共享的方法和属性
function Person(name) {
this.name = name; // 实例属性(每个实例独立)
}
// 原型方法(所有实例共享)
Person.prototype.sayHello = function() {
console.log('Hello, ' + this.name);
};
Person.prototype.species = 'human'; // 共享属性
const p1 = new Person('Tom');
const p2 = new Person('Jerry');
p1.sayHello(); // 'Hello, Tom'
p2.sayHello(); // 'Hello, Jerry'
// 方法共享,内存高效
console.log(p1.sayHello === p2.sayHello); // true
console.log(p1.species === p2.species); // true
实例属性 vs 原型属性
JavaScript
function Person(name, age) {
// 实例属性:每个实例独立存储
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(this.name);
};
Person.prototype.species = 'human';
const p1 = new Person('Tom', 25);
// 查看属性来源
console.log(p1.hasOwnProperty('name')); // true(实例属性)
console.log(p1.hasOwnProperty('age')); // true
console.log(p1.hasOwnProperty('sayHello')); // false(原型属性)
console.log(p1.hasOwnProperty('species')); // false
// 实例属性可覆盖原型属性
Person.prototype.age = 0;
const p2 = new Person('Jerry', 30);
console.log(p2.hasOwnProperty('age')); // true(实例属性覆盖)
console.log(p2.age); // 30(实例优先)
constructor 属性
JavaScript
// prototype.constructor 指回构造函数
function Person(name) {
this.name = name;
}
console.log(Person.prototype.constructor === Person); // true
// 实例通过 constructor 找到构造函数
const p = new Person('Tom');
console.log(p.constructor === Person); // true
console.log(p.__proto__.constructor === Person); // true
// 重写 prototype 会丢失 constructor
Person.prototype = {
sayHello: function() {
console.log(this.name);
}
};
console.log(Person.prototype.constructor === Person); // false
console.log(Person.prototype.constructor === Object); // true
// 手动修复 constructor
Person.prototype.constructor = Person;
console.log(Person.prototype.constructor === Person); // true
原型重写
JavaScript
// 方式一:逐个添加(推荐,保留 constructor)
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {};
Person.prototype.sayBye = function() {};
// 方式二:整体重写(需修复 constructor)
function Animal(type) {
this.type = type;
}
Animal.prototype = {
constructor: Animal, // 必须手动修复
speak: function() {
console.log(this.type + ' speaks');
},
move: function() {
console.log(this.type + ' moves');
}
};
const dog = new Animal('dog');
dog.speak(); // 'dog speaks'
console.log(dog.constructor === Animal); // true
最佳实践
JavaScript
// 推荐:实例属性放构造函数,方法放原型
function User(name, email) {
// 实例属性
this.name = name;
this.email = email;
this.friends = []; // 可变数据放实例
}
// 共享方法放原型
User.prototype.getInfo = function() {
return `${this.name}: ${this.email}`;
};
User.prototype.addFriend = function(friend) {
this.friends.push(friend);
};
// 静态方法:直接定义在构造函数上(不参与原型链)
User.createGuest = function() {
return new User('Guest', 'guest@example.com');
};
const guest = User.createGuest();
console.log(guest.getInfo()); // 'Guest: guest@example.com'
注意事项
- 构造函数首字母大写(约定),用
new调用- 原型方法中的
this指向调用实例- 重写
prototype后需修复constructor- 可变数据(数组、对象)不要放在原型上
JavaScript
// 错误:忘记 new
const p = Person('Tom'); // this 指向全局对象或 undefined
console.log(p); // undefined
console.log(window.name); // 'Tom'(严格模式下报错)
// 保护措施
function Person(name) {
if (!(this instanceof Person)) {
return new Person(name);
}
this.name = name;
}
// 或使用 new.target(ES6)
function Person(name) {
if (!new.target) {
return new Person(name);
}
this.name = name;
}
要点总结
- 构造函数用
new调用,this指向新实例 prototype存储共享方法,所有实例共用,节省内存- 实例属性放构造函数,共享方法放原型
prototype.constructor默认指向构造函数,重写后需手动修复- 可变数据放实例,不可变数据和方法可放原型
- 避免忘记
new,可添加保护检查
📝 发现内容有误?点击此处直接编辑