JavaScript 由手撕new关键字想到的

Crushdada
  • 115

问题出现的环境背景及自己尝试过哪些方法

最近在学习JS面向对象和原型相关知识,而new关键字是一种使用广泛的继承方式,于是研究一下内部机制
百度到这样一段代码--

function create(Con, ...args){   //Con即要new的构造函数  
  // 创建一个空的对象
  let  obj = Object.create(null);
  // 将空对象指向构造函数的原型链
  Object.setPrototypeOf(obj, Con.prototype);
  // obj绑定到构造函数上,便可以访问构造函数中的属性,即obj.Con(args)
  let result = Con.apply(obj, args);
  // 如果返回的result是一个对象则返回
  // 否则new方法失效,返回obj空对象
  return result instanceof Object ? result : obj;
}

// 测试
function company(name, address) {
    this.name = name;
    this.address = address;
  }

var company1 = create(company, 'yideng', 'beijing');
console.log('company1: ', company1);

在以上代码中,函数create就相当于“new”关键字

问题描述

我不理解最后一句return语句,有什么意义?

作者给的注释是 “如果返回的result是一个对象则返回,否则new方法失效,返回obj空对象” --这是什么意思?

期待富有逻辑性的结果

回复
阅读 579
3 个回答
✓ 已被采纳

观察一下这段代码的结果,或许有你想要的答案

function Con() {
    return {
        hello: "world"
    };
}

const inst = new Con();
console.log(inst);
console.log(inst instanceof Con);

或者把两种情况都考虑到,

function Con(switcher) {
    if (switcher) {
        return {
            hello: "world"
        };
    }
}

const inst = new Con();
console.log(inst instanceof Con, inst);

const inst2 = new Con(true);
console.log(inst2 instanceof Con, inst2);

再改一下 Con

function Con(switcher) {
    if (switcher) {
        return "hello";
    }
}

会看到完全不同的结果,这次返回的都是 Con 对象。

参考:MDN 上关于 new 的描述,其中有一段:

new 关键字会进行如下的操作:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(设置该对象的constructor)到另一个对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this。

第 4 句回答了这个问题

为了覆盖这种分支:如果构造函数有 return 语句,真实的 new 操作其实是返回这个 return 的东西,而不是 new 出来的 this.

apply 的返回值如果是一个对象,说明这个构造器里面写了 return 语句,那么为了和 new 有相同的效果,应该把这个 result 返回,而不是临时对象 obj.

这个规则是 js 的糟粕,构造函数还能 return. 你上 lint 都会给你报错。明白这么回事儿就行。

大意是构造函数不能返回对象Object类型,不然会覆盖掉,返回原始值不会生效,返回对象会导致 new 操作符没有作用

function Foo(name) {
  this.name = name
  console.log(this) // Foo { name: 'test' }

  return 11
  
}
const t = new Foo('test')
console.log(t) // { name: 'test' }
function Foo(name) {
  this.name = name
  console.log(this) // Foo { name: 'test' }
  return { age: 18 }
}
const t = new Foo('test')
console.log(t) // { age: 18 } //此时不是你要的对象实例
function Foo(name) {
  this.name = name
  console.log(this) // Foo { name: 'test' }
  
}
const t = new Foo('test')
console.log(t) // { name: 'test' }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏