【重学JS之路】new关键词

400 阅读2分钟

大部分面试的时候,面试官先已原型链铺路,随后就会问你 new 关键词都做了些什么?也是为了下一个继承问题再次铺路! 那这篇文章我们就来讲讲这个 new! 我们通常在什么地方能看到它,在创建实例的时候,new 后面加上一个构造函数,就是创建这个构造函数的实例。

首先我们创建一个构造函数,看看new都做了哪些事情:

function Person() {
  this.name = 'Jack';
  this.age = '29';
}
Person.prototype.eat = function() {
  console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭

我们从上述可以看出,new关键词主要做了以下几个事情:

  1. 创建了一个新的对象,
  2. 将新对象的__proto__函数指向构造函数的prototype,这个新对象就可以访问构造函数原型上的属性
  3. 将this指向改变,指向新的对象,这样就可以访问构造函数内部的属性
  4. 返回新的对象

接下来来模拟一下new函数:

function MyNew() {
  let obj = new Object();
  Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  Constructor.apply(obj, arguments);
  return obj;
}

我们来验证一下写的这个方法是否正确:

function Person() {
  this.name = 'Jack';
  this.age = '29';
}
Person.prototype.eat = function() {
  console.log('烤鸭');
}
var person = MyNew(Person);
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭

输出结果一样,那忽然有个想法,构造函数毕竟是个函数,如果构造函数有返回值,那new后结果是怎样呢:

// 返回基本数据类型
function Person() {
  this.name = 'Jack';
  this.age = '29';
  return 1;
}
Person.prototype.eat = function() {
  console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //Jack
console.log(person.age); // 29
person.eat(); // 烤鸭
// 返回对象
function Person() {
  this.name = 'Jack';
  this.age = '29';
  return {
    sex: 'nan',
    like: 'nv'
  };
}
Person.prototype.eat = function() {
  console.log('烤鸭');
}
var person = new Person();
console.log(person.name); //undefined
console.log(person.age); // undefined
console.log(person.sex); //Jack
console.log(person.like); // 29
person.eat(); // Uncaught TypeError: person.eat is not a function

当构造函数返回的是一个基本数据类型时,跟没有返回值是一样的结果,但是当返回值是一个对象时,就会真的返回这个对象,return之前定义的属性都会失效,并且定义在原型上的属性也会失效。根据这个特性,对之前写的MyNew函数进行升级。

function MyNew() {
  let obj = new Object();
  Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  let res = Constructor.apply(obj, arguments);
  return typeof res === 'object' ? res : obj;
}