大家好,相信大家都用到过new操作符,那么今天和大家聊一聊new操作符到底做了什么事情?
一、首先让我们通过几个例子来看看new的作用
function TestNew(name){
this.name = name;
this.sayname = function(){
console.log(this.name);
}
}
TestNew.prototype.sayhello = function(name){
console.log(`hello ${name}`);
}
const test = new TestNew('test');
console.log(test.name); // test
test.sayname(); // test
test.sayhello('test'); //hello test
通过上面的例子我们可以看出来
- new 操作符创建出来的 test 实例可以访问到TestNew里面的属性。
- new 操作符创建出来的 test 实例可以访问到TestNew原型链上的属性。
我们上面的 TestNew没有 return 值,那么当构造函数有返回值的情况下会怎么样呢?
function TestNew(name){
this.name = name;
return 'test return'
}
const test = new TestNew('test');
console.log(test.name); // test
我们发现结果还是返回了 test 并没有输出 test return,也就是说 返回值是字符串的时候 返回值并没有实际意义。
注意:我特意提到的当返回值是字符串的时候 返回值没有意义,那么如果是其他类型的返回值的情况呢?
function TestNew (name,age){
this.name = name;
return {
age
}
}
const test = new TestNew('test',26);
console.log(test.name); // undefined
console.log(test.age); // 26
可以发现 返回值 生效了,这里只展示了返回值是对象和字符串的情况,有兴趣的同学可以自己去试试其他基本数据类型的返回值(结果和字符串是一样的),所以构造函数是不需要返回值的,如果是基本数据类型,则返回值失效,如果是对象,则会使new失去意义。
小结:
- new 操作符创建出来的 test 实例可以访问到TestNew里面的的属性
- new 操作符创建出来的 test 实例可以访问到TestNew原型链上的属性
- 尽量避免在构造函数中使用 return 返回值
理解了new的作用,那么我们接下来就可以尝试自己手写一个new了
二:手写 new
function myNew (Base,name){
const obj= new Object(); // 创建空对象
obj.__proto__ = Base.prototype; // 将obj通过__proto__指向Base的原型
const rel = Base.call(obj,name); // 将新对象作为上下文(this),调用call来执行类的构造函数
//如果fn返回的是null或undefined(也就是不返回内容)或者其他基础类型,我们返回的是obj,否则返回rel
return rel instanceof Object ? rel : obj;
}
function TestNew(name){
this.name = name;
this.sayname = function(){
console.log(this.name);
}
}
TestNew.prototype.sayhello = function(name){
console.log(`hello ${name}`);
}
const myTestNew = myNew(TestNew,'Constructor function');
console.log(myTestNew.name); // Constructor function
console.log(myTestNew.sayname()); // Constructor function
console.log(myTestNew.sayhello('prototype function')); // hello prototype function
至此我们也实现了自己的 new 操作符。