在 javaScript创建对象的方法-构造函数模式 中创建了构造函数Person。
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
}
var person1 = new Person('Tom', 18);
var person2 = new Person('Harry', 28);
复制代码
并提到,要创建一个构造函数的实例需要使用 new 操作符,这种方式调用构造函数其实经历了如下几个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给这个新对象,同时 this 指向这个新创建的对象
- 执行构造函数,为新对象添加属性
- 返回新对象
那么new 操作符的具体原理是怎样的呢,在使用 new操作符的时候究竟做了什么?先修改上面的构造函数分别返回undefined、NaN、一个字符串、null。
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
return;
}
console.log(Person('Tom', 18)); // undefined
console.log(new Person('Harry', 28)); // Person {name: "Harry", age: 28, say: ƒ}
复制代码
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
return NaN;
}
console.log(Person('Tom', 18)); // NaN
console.log(new Person('Harry', 28)); // Person {name: "Harry", age: 28, say: ƒ}
复制代码
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
return `My name is ${this.name}. I'm ${this.age} years old.`;
}
console.log(Person('Tom', 18)); // My name is Tom. I'm 18 years old.
console.log(new Person('Harry', 28)); // Person {name: "Harry", age: 28, say: ƒ}
复制代码
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
return null;
}
console.log(Person('Tom', 18)); // null
console.log(new Person('Harry', 28)); // Person {name: "Harry", age: 28, say: ƒ}
复制代码
作为普通函数调用时,返回该函数的返回值(undefined/NaN/字符串/null…)。作为构造函数调用时,此时的返回值为(undefined/NaN/字符串/null)时会被忽略了,返回了这个新创建的对象。
修改上面的构造函数为返回一个对象。
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name + ' ' + this.age);
}
return { name, age };
}
console.log(Person('Tom', 18)); // {name: "Tom", age: 18}
console.log(new Person('Harry', 28)); // {name: "Harry", age: 28}
复制代码
作为普通函数调用时,返回该函数的返回值,作为构造函数调用时,也返回了该函数的返回值。
综上所述,加上查阅文档得到:
在使用new操作符的时候,会对构造函数的返回值做一些判断:
- 如果返回值是基础数据类型,则忽略返回值;
- 如果返回值是引用数据类型,则使用构造函数return 的返回值,也就是new操作符无效。
根据上述,模拟new的内部处理细节。
// NewFn函数要接受的参数个数不定,
// 第一个参数是构造函数(既是new操作符的目标函数),
// 其余参数为构造函数的参数。
function NewFn(ConstructFn, ...args) {
// 创建一个新对象
let obj = Object.create({}); // let obj = {}
// 将空对象的原型prototype指向构造函数的原型(将构造函数的作用域赋给这个新对象)
Object.setPrototypeOf(obj, ConstructFn.prototype); // obj.__proto__ = ConstructFn.prototype
// 在obj的作用域内执行ConstructFn,并传入args参数,为新对象添加属性
let res = ConstructFn.apply(obj, args);
// 判断原构造函数的返回值,返回最终结果
return res instanceof Object ? res : obj;
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END