JavaScript专题之模拟实现new

本文共 1230 字,读完只需 5 分钟javascript

写在前面java

最近工做太忙,快接近两周没更新博客,总感受有一些事情等着本身去作,虽然工做内容对本身提高挺大,但我总以为,一直埋着头走路,偶尔也须要抬起头来,看看如今和本身的指望向是否脱轨,因此周末仍是选择来星巴克写些文字。面试

今天记录 JavaScript 中 new 关键字的模拟实现,当咱们在模拟实现某个语言行为以前,应该想一想这个行为都作了哪些事情,经过实践,最后也能更加掌握知识点,这就是不少面试题都会问到模拟实现的缘由,目的是为了考察候选人知识的深度。闭包

function Person(name) {
    this.name = name;
}

var person = new Person('jayChou');

typeof(person)  // "object"
person instanceof Person  // true
person.__proto__ === Person.prototype  // true
person.constructor === Person  // true
person.constructor === Person.prototype.constructor  // true
复制代码

以上,能够看出:app

  1. new 建立并返回了一个新对象,是构造函数的实例
  2. 对象的实例的构造函数属性实际上是构造函数的原型对象的 constructor 属性
  3. 对象实例的 __proto__ 关联到构造函数的原型对象

上面的内容有关于 JavaScript 中原型对象和原型链的知识,不够清楚的同窗能够查看我以前的博客。函数

因为 new 是 JS 的一个关键字,咱们没法实现关键字,但咱们能够经过函数的形式来模拟 new 关键字的行为。post

1、基本思路

知道 new 关键字作了哪些工做,那咱们就有了模拟实现的基本思路。ui

/** * 模拟实现 JavaScript new 操做符 * @param {Function} constructor [构造函数] * @return {Object|Function|Regex|Date|Error} [返回结果] */
function mockNew() {
    // 建立一个空对象
    let resultObj = new Object();

    // 取传入的第一个参数,即构造函数,并删除第一个参数。
    // 关于为何要用 Array.prototype.shift.call 的形式,见以前的博客文章 《JavaScript之arguments》
    let constructor =  Array.prototype.shift.call(arguments);
    
    // 类型判断,错误处理
    if(typeof constructor !== "function") {
        throw("构造函数第一个参数应为函数");
    }
    
    // 绑定 constructor 属性
    resultObj.constructor = constructor;
    
    // 关联 __proto__ 到 constructor.prototype
    resultObj.__proto__ = constructor.prototype;
    
    // 将构造函数的 this 指向返回的对象
    constructor.apply(resultObj, arguments);
    
    // 返回对象
    return resultObj;
}

function Person(name) {
    this.name = name;
}


var person = mockNew(Person, "jayChou");

console.log(person);

// constructor: ƒ Person(name)
// name: "jayChou"
// __proto__: Object
复制代码

基本思路正确! 因此咱们完成了 new 关键字的初步模拟。伙伴们能够本身动手敲一下,每句代码本身是否都能理解。this

2、处理返回值

构造函数也是函数,有不一样类型返回值。有时候构造函数会返回指定的对象内容,因此要对这部分进行处理。spa

/** * 模拟实现 JavaScript new 操做符 * @param {Function} constructor [构造函数] * @return {Object|Function|Regex|Date|Error} [返回结果] */
function mockNew() {
    // 建立一个空对象
    let emptyObj = new Object();

    // 取传入的第一个参数,即构造函数,并删除第一个参数。
    // 关于为何要用 Array.prototype.shift.call 的形式,见以前的博客文章 《JavaScript之arguments》
    let constructor =  Array.prototype.shift.call(arguments);
    
    // 类型判断,错误处理
    if(typeof constructor !== "function") {
        throw("构造函数第一个参数应为函数");
    }
    
    // 绑定 constructor 属性
    emptyObj.constructor = constructor;
    
    // 关联 __proto__ 到 constructor.prototype
    emptyObj.__proto__ = constructor.prototype;
    
    // 将构造函数的 this 指向返回的对象
    let resultObj = constructor.apply(emptyObj, arguments);
    
    // 返回类型判断, 若是是对象,则返回构造函数返回的对象
    if (typeof resultObj === "object") {
        return resultObj
    }
    
    // 返回对象
    return emptyObj;
}

function Person(name) {
    this.name = name;
    return {
        name: this.name,
        age: 40
    }
}


var person = mockNew(Person, "jayChou");

console.log(person);

// {name: "jayChou", age: 40}
// age: 40
// name: "jayChou"
// __proto__: Object
复制代码

当返回值返回了一个自定义对象后,模拟 new 函数就返回该自定义对象。

总结

JavaScript new 关键字的意义在于让普通函数生成一个新对象,并将对象实例的 __proto__ 关联到函数的 prototype 对象。

本文中有些地方须要一些前置知识,可是整体上理解是比较容易的。若是有迷惑的地方,能够翻看我以前的博客文章

掘金专栏 JavaScript 系列文章

  1. JavaScript之变量及做用域
  2. JavaScript之声明提高
  3. JavaScript之执行上下文
  4. JavaScript之变量对象
  5. JavaScript之原型与原型链
  6. JavaScript之做用域链
  7. JavaScript之闭包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值传递
  11. JavaScript之例题中完全理解this
  12. JavaScript专题之模拟实现call和apply
  13. JavaScript专题之模拟实现bind

欢迎关注个人我的公众号“谢南波”,专一分享原创文章。

相关文章
相关标签/搜索