JavaScript专题之模拟实现new

栏目: JavaScript · 发布时间: 6年前

内容简介:本文共 1230 字,读完只需 5 分钟写在前面最近工作太忙,快接近两周没更新博客,总感觉有一些事情等着自己去做,虽然工作内容对自己提升挺大,但我总觉得,一直埋着头走路,偶尔也需要抬起头来,看看现在和自己的期望向是否脱轨,所以周末还是选择来星巴克写些文字。

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

写在前面

最近工作太忙,快接近两周没更新博客,总感觉有一些事情等着自己去做,虽然工作内容对自己提升挺大,但我总觉得,一直埋着头走路,偶尔也需要抬起头来,看看现在和自己的期望向是否脱轨,所以周末还是选择来星巴克写些文字。

今天记录 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
复制代码

以上,可以看出:

__proto__

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

由于 new 是 JS 的一个关键字,我们无法实现关键字,但我们可以通过函数的形式来模拟 new 关键字的行为。

一、基本思路

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

/**
 * 模拟实现 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 关键字的初步模拟。伙伴们可以自己动手敲一下,每句代码自己是否都能理解。

二、处理返回值

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

/**
 * 模拟实现 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专题之模拟实现new

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Programming Ruby中文版

Programming Ruby中文版

托马斯 / 孙勇、姚延栋、张海峰 / 电子工业出版社 / 2007-3 / 99.00元

《Programming Rudy》(中文版)(第2版)是它的第2版,其中包括超过200页的新内容,以及对原有内容的修订,涵盖了Ruby 1.8中新的和改进的特性以及标准库模块。它不仅是您学习Ruby语言及其丰富特性的一本优秀教程,也可以作为日常编程时类和模块的参考手册。Ruby是一种跨平台、面向对象的动态类型编程语言。Ruby体现了表达的一致性和简单性,它不仅是一门编程语言,更是表达想法的一种简......一起来看看 《Programming Ruby中文版》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具