在JS中通过构造函数或类创建一个对象时,new操作符做了那些事情?看完你也来自己动手实现一个new操作符吧!
什么是new操作符
在JavaScript中,
new是一个用于创建对象实例的关键字。它用于调用构造函数,并返回一个新的对象。
mdn中是这么定义new操作符的:new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
//例1
let Animal1=function(){this.name=1};
let animal=new Animal1; //这里不带()相当于不传参数
//=>Animal1 {name: 1}
//例2
let TestObj={}
let t1=new TestObj;
//=>Uncaught TypeError: TestObj is not a constructor
例子:
function Test(name) {
this.name = name
}
Test.prototype.sayName = function () {
console.log(this.name)
}
const t = new Test('yck')
console.log(t.name) // 'yck'
t.sayName() // 'yck'
function Test(name) {
this.name = name
return 1
}
const t = new Test('yck')
console.log(t.name) // 'yck'
function Test(name) {
this.name = name
console.log(this) // Test { name: 'yck' }
return { age: 26 }
}
const t = new Test('yck')
console.log(t) // { age: 26 }
console.log(t.name) // 'undefined'
new通过构造函数 Test 创建出来的实例可以访问到构造函数中的属性new通过构造函数 Test 创建出来的实例可以访问到构造函数原型链中的属性,也就是说通过 new 操作符,实例与构造函数通过原型链连接了起来- 构造函数如果返回原始值( 虽然例子中只有返回了 1,但是你可以试试其他的原始值,结果还是一样的 ),那么这个返回值毫无意义
- 构造函数如果返回值为 对象 ,那么这个 返回值会被正常使用
new操作符的作用
new操作符会返回一个对象,所以我们需要在内部创建一个对象- 这个对象,也就是构造函数中的
this,可以访问到挂载在this上的任意属性 - 这个对象可以访问到构造函数原型上的属性,所以需要将对象与构造函数链接起来
- 返回原始值需要忽略,返回对象需要正常处理
手写/实现new操作符
new关键字的实现原理可以分为以下几个步骤:
- 创建一个新的空对象。
- 将新创建的对象的
__proto__属性指向构造函数的prototype属性。 - 将构造函数的
this关键字指向新创建的对象。 - 执行构造函数中的代码,给这个空对象添加属性和方法。
- 如果构造函数没有显式返回一个对象,则返回新创建的对象。
function myNew(constructor, ...args) {
// 创建一个空对象
const obj = {};
// 设置原型链
Object.setPrototypeOf(obj, constructor.prototype);
// 将构建函数的this指向新对象,并执行构造函数的代码
const result = constructor.apply(obj, args);
// 如果构造函数返回的是对象,则返回该对象;否则返回新创建的对象
return Object.prototype.toString.call(result) === '[object Object]' ? result : obj;
}
function Person (name, age){
this.name = name
this.age = age
}
Person.prototype.intro = function(){
console.log(`我叫${this.name},今年${this.age}岁`);
}
const person1 = myNew(Person, '张三', 18)
console.log(person1.name);
console.log(person1.age);
person1.intro() // 输出:我叫张三,今年18岁
const person2 = new Person('张三', 18)
console.log(person2.name);
console.log(person2.age);
person2.intro() // 输出:我叫张三,今年18岁
function Person (name, age){
this.name = name
this.age = age
return {
name: this.name,
age: this.age,
sex: 'unknown'
}
}
Person.prototype.intro = function(){
console.log(`我叫${this.name},今年${this.age}岁`);
}
const person3 = myNew(Person, '李四', 20)
console.log(person3);
// { name: '李四', age: 20, sex: 'unknown' }
const person4 = new Person('李四', 20)
console.log(person4);
// { name: '李四', age: 20, sex: 'unknown' }