hzzzzzzzq / Blog

这是我记录博客的地方,希望能多写一些技术博客,JS、ES、React、Vue等
14 stars 0 forks source link

深入理解JavaScript系列(10):new 操作 #51

Open hzzzzzzzq opened 2 years ago

hzzzzzzzq commented 2 years ago

new 关键字

new 操作,我们在类对象,函数中都会使用到,那么它到底是用来干什么的呢?又是怎么实现的呢?

第一版 - 基础完成

我们先看看 MDN 的定义:

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

我们先来举个例子吧

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.weight = 70;
Person.prototype.getInfo = function () {
  console.log(this.name, this.age, this.weight);
};
const person = new Person('hzzzzzzzq', 18);
console.log(person.name); // hzzzzzzzq
console.log(person.age); // 18
console.log(person.weight); // 70
person.getInfo(); // hzzzzzzzq 18 70

我们从例子中来看,我们创建的实例 person 可以做到

所以由此我们来推断 new 操作做了什么。

但是由于 new 操作是关键字,所以就是用一个创建方法 objectFactory 来替代了。

let pserson = new Person(...arguments);

// 等价我们创建的方法

let person = objectFactory(Person, ...arguments);

由此,我们来看第一版代码吧。

function objectFactory() {
  const obj = {}; // 创建一个新对象,也可以使用 new Object()
  const Constructor = [].shift.call(arguments); // 获取构造函数,传入参数的第一个值
  obj.__proto__ = Constructor.prototype; // 将对象的原型指向构造函数的原型
  Constructor.apply(obj, arguments); // 绑定对象,为对象添加属性
  return obj; // 返回对象
}

接下来,我们来测试一下

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.weight = 70;
Person.prototype.getInfo = function () {
  console.log(this.name, this.age, this.weight);
};

function objectFactory() {
  const obj = {}; // 创建一个新对象,也可以使用 new Object()
  const Constructor = [].shift.call(arguments); // 获取构造函数,传入参数的第一个值
  obj.__proto__ = Constructor.prototype; // 将对象的原型指向构造函数的原型
  Constructor.apply(obj, arguments); // 绑定对象,为对象添加属性
  return obj; // 返回对象
}
// const person = new Person('hzzzzzzzq', 18);
const person = objectFactory(Person, 'hzzzzzzzq', 18);
console.log(person.name); // hzzzzzzzq
console.log(person.age); // 18
console.log(person.weight); // 70
person.getInfo(); // hzzzzzzzq 18 70

发现,结果是一样的,这样就实现了吗? 当然不是,我们的构造函数如果有返回值呢?那会怎么样呢?

第二版 - 返回值

我们来看看例子,由此,我们可以看见,如果构造函数带有返回值,则会导致返回值以外定义的值无效。

function Person(name, age) {
  this.weight = 70;

  return {
    name: name,
    age: age,
  };
}
Person.prototype.getInfo = function () {
  console.log(this.name, this.age, this.weight);
};
const person = new Person('hzzzzzzzq', 18);
console.log(person.name); // hzzzzzzzq
console.log(person.age); // 18
console.log(person.weight); // undefined
person.getInfo(); // TypeError: person.getInfo is not a function

但是返回值就一定是对象吗?结果显然是不一定。

所有,我们来看看不是对象时是什么情况:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.weight = 70;

  return 'hello';
}
const person = new Person('hzzzzzzzq', 18);
console.log(person.name); // hzzzzzzzq
console.log(person.age); // 18
console.log(person.weight); // 70

我们发现,都正确返回了,所以我们需要进行判断

接下来我们来更改我们的代码.

function objectFactory() {
  const obj = {};
  const Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  const result = Constructor.apply(obj, arguments); // 获取 返回值

  return typeof result === 'object' ? result : obj; // typeof 进行判读
}

小结

我们来小结一下 new 做的事情。

到此,我们就完美复刻出了 new 操作喽。