我们通过new运算符的使用,来探寻new操作符在执行的过程中究竟做了哪些操作,并且根据操作实现自己的new运算符。
定义
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
使用
先看正常使用new运算符调用构造函数
function Test(testText) {
this.testText = testText;
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = new Test('文本文本');
console.log(t1.testText); // 文本文本
t1.console(); // 文本文本
上述代码使用new运算符调用构造函数,会返回t1这个值,然后t1可以访问构造函数内部this上的值(也就是说他们两个绑定在了一起),t1还可以访问构造函数原型链上的值。下面不使用new操作符调用构造函数来进行对比:
1、对比构造函数返回的值
使用new运算符返回的t1值为对象
function Test(testText) {
this.testText = testText;
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = new Test('文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Object]
console.log(t1.testText); // 文本文本
t1.console(); // 文本文本
不使用new运算符返回值为undefined,并且函数内部的值不可访问。
function Test(testText) {
this.testText = testText;
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = Test('文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Undefined]
console.log(t1.testText); // 报错
t1.console(); // 报错
由上述对比可知构造函数内部不返回值,new操作符会创建一个对象,并将函数内部的this绑定在这个对象上并将它返回。
2、构造函数内部有返回值时的对比
构造函数返回普通类型值时的结果对new运算符返回结果没有任何影响。如:
function Test(testText) {
this.testText = testText;
// return 1;
return '2222';
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = new Test('文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Object]
console.log(t1.testText); // 文本文本
t1.console(); // 文本文本
构造函数返回引用类型值时,会覆盖new运算符调用时返回的结果。如:
function Test(testText) {
this.testText = testText;
return {};
// return function() {};
// return [];
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = new Test('文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Object]
// console.log(Object.prototype.toString.call(t1)); // [object Function]
// console.log(Object.prototype.toString.call(t1)); // [object Array]
console.log(t1.testText); // undefined
t1.console(); // 报错
当构造函数返回值为null时,对new运算符调用返回结果无影响。如:
function Test(testText) {
this.testText = testText;
return null;
}
Test.prototype.console = function() {
console.log(this.testText);
}
let t1 = new Test('文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Object]
console.log(t1.testText); // 文本文本
t1.console(); // 文本文本
通过构造函数内部有返回值时的对比,会发现当构造函数返回结果为普通类型和null时对new运算符调用返回的结果没影响,而当构造函数内部返回的是引用类型时,则会覆盖new运算符调用返回的结果。
总结
综上所述可以发现new运算符一共做了以下几件事:
1、 创建一个对象
2、 new创建的对象指向了构造函数的原型对象
3、 构造函数内部的this指向了new创建的对象
4、 调用了构造函数
5、 如果构造函数内部的返回值为普通类型和null则将new创建的对象返回出去,而如果构造函数返回的对象为引用类型对象则采用构造函数返回的对象。
实现自己的new运算符
function myNew(Fn, ...paramet) {
// 创建一个对象并可以访问构造函数Fn的原型
let obj = Object.create(Fn.prototype);
// 将构造函数内部this绑定到创建的对象上,并调用构造函数
let fnReasult = Fn.apply(obj, paramet);
// 判断需要返回的结果
return fnReasult instanceof Object? fnReasult: obj;
}
测试
function Test(testText) {
this.testText = testText;
return null;
}
Test.prototype.console = function() {
console.log(this.testText);
}
// let t1 = new Test('文本文本');
let t1 = myNew(Test, '文本文本');
console.log(Object.prototype.toString.call(t1)); // [object Object]
console.log(t1.testText); // 文本文本
t1.console(); // 文本文本
网友评论