使用构造函数
// 这是一个构造函数 (产品蓝图)
function Person(name, age) {
this.name = name;
this.age = age;
// 假设构造函数有一个返回值
// return { custom: 'object' }; // 情况 A
// return 'a string'; // 情况 B
}
// 为所有“人类”产品添加一个共享的技能
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
// 下达生产指令
const alice = new Person('Alice', 30);
js中new一个对象的过程
在内存中创建一个空对象,
将这个空对象的内部原型 [[Prototype]] (也就是非标准的 __proto__ 属性) 指向构造函数的 prototype 对象。
空对象 现在继承了
构造函数的prototype上的所有属性和方法。
将构造函数的 this 关键字绑定到空对象上,然后调用这个构造函数,并传入参数。
在构造函数执行完毕后,隐式地 return 这个空对象(此时可能已经被赋值) 。
-
如果构造函数自己
显式地return 了一个值:-
如果返回的是一个对象 (Object) 或函数 (Function) (情况 A):那么 new 操作符会放弃我们自己创建的那个 newObj,而是直接返回构造函数返回的这个对象。
function SpecialPerson() { this.name = 'default'; return { custom: 'object' }; // 返回了一个对象 } const sp = new SpecialPerson(); console.log(sp); // 输出: { custom: 'object' } (我们自己的 newObj 被丢弃了) -
如果返回的是一个基本数据类型 (String, Number, Boolean, null, undefined) (情况 B):那么 new 操作符会忽略这个返回值,仍然坚持返回我们自己创建的那个 newObj。
function NormalPerson() { this.name = 'default'; return 'a string'; // 返回了一个基本类型 } const np = new NormalPerson(); console.log(np); // 输出: { name: 'default' } (返回值 'a string' 被忽略了)
-
-
最佳实践:在构造函数中,通常不应该使用 return 语句,除非你知道你在做什么。让 new 自动地、隐式地返回 this 是最清晰、最符合预期的行为。
手写实现 new
function myNew(Constructor, ...args) {
// 步骤 1: 创建一个全新的空对象
const newObj = {};
// 步骤 2: 链接到原型
Object.setPrototypeOf(newObj, Constructor.prototype);
// 步骤 3: 绑定 this 并执行构造函数
const result = Constructor.apply(newObj, args);
// 步骤 4: 返回新对象 (并处理构造函数的返回值)
// 判断构造函数的返回值是不是一个对象或函数
const isObject = typeof result === 'object' && result !== null;
const isFunction = typeof result === 'function';
return isObject || isFunction ? result : newObj;
}
// --- 使用我们自己的 myNew ---
const bob = myNew(Person, 'Bob', 40);
bob.sayHello(); // 输出: Hello, my name is Bob
console.log(bob instanceof Person); // true