先搞清楚new

首先,我们要知道,创建一个用户自定义对象需要两步:

  1. 通过编写函数来定义对象类型。
  2. 通过new来创建对象实例。

通过此处引出了new的描述,new是干嘛的呢?引用MDN的一句话:

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

初看时可能会有点懵,我们可以对这段话修枝剪叶留下枝干: new运算符可以创建 对象实例 。(之后再通过new的运用,补全其枝叶。)

这句话就符合最开头说的创建一个用户自定义对象的第二步了。实际应用也是,new运算符经常是与一个函数结合使用。

来看个例子:

// example
function Foo(name, age) {this.name = name;this.age = age;this.sex = 'male';
}
Foo.prototype.brother = "宇智波鼬";Foo.prototype.chat = function () {console.log('how are you? 鸣人');
}var person = new Foo('佐助', 21);console.log(person.name);
console.log(person.sex);
console.log(person.brother);
person.chat();
// 佐助
// male
// 宇智波鼬
// how are you? 鸣人
复制代码

从这个例子中我们可以看出,:

  1. 生成了新对象(实例)person。
  2. Foo函数里的this指向该实例对象person。
  3. 这个对象实例可以访问Foo.prototype上的属性。

MDN上帮我们总结的更清楚,当代码 new Foo(...) 执行时,会发生以下事情:

  1. 一个继承自 Foo.prototype 的新对象被创建。("继承"用得不是很准确,应该叫委托才好,具体参见you-dont-konw-js)
  2. 使用指定的参数调用构造函数 Foo ,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
  3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)

注: 由同一个构造函数创建的实例各个独立且其原型相同,原型对象都等于 构造函数.prototype === 实例.__proto__

第一步

有了对new的认识后,咱们开始仿写。因为 new 是个关键字,没法像之前的call、bind那样子写方法覆盖。我们可以写个方法 copyNew()。

以上面例子为例,我们让 new Foo(xxx) 的效果等于 copyNew(Foo, xxx)就行。

来第一步代码:

// codes
function copyNew() {var obj = new Object();var constructor = [].shift.call(arguments); // 取出第一个构造函数参数。注意shift可以改变原数组。obj.__proto__ = constructor.prototype; // 这样obj就可以访问在构造函数的prototype上的属性// 根据apply经典继承来让函数的this指向实例constructor.apply(obj, arguments);return obj
}
复制代码

have a test:

// example
function Foo(name, age) {this.name = name;this.age = age;this.sex = 'male';
}
Foo.prototype.brother = "宇智波鼬";Foo.prototype.chat = function () {console.log('how are you? 鸣人');
}var person = copyNew(Foo, '佐助', 21);console.log(person.name);
console.log(person.sex);
console.log(person.brother);
person.chat();
// 佐助
// male
// 宇智波鼬
// how are you? 鸣人
复制代码

第一步成功。

第二步

我们现在考虑下构造函数有返回值的情况。

1、假设构造函数的返回值是对象。

举个例子:

// 假设构造函数的返回值是对象
function Foo(name, age) {this.brother = '宇智波鼬';this.age = agereturn {habit: 'coding',name: name}
}const person = new Foo('佐助', 21);console.log(person.age);
console.log(person.brother);
console.log('**********华丽的分割线**********');
console.log(person.habit);
console.log(person.name);
// undefined
// undefined
//**********华丽的分割线**********
// coding
// 佐助
复制代码

我们可以发现,构造函数Foo的person实例完全只能访问Foo返回的对象中的属性。

那构造函数的返回值不是对象呢? 我们试一个基本类型的值。

2、假设构造函数的返回值是基本类型的值

// 假设构造函数的返回值是一个基本类型的值
function Foo(name, age) {this.brother = '宇智波鼬';this.age = agereturn 'sadhu'
}const person = new Foo('佐助', 21);console.log(person.age);
console.log(person.brother);
console.log('**********华丽的分割线**********');
console.log(person.habit);
console.log(person.name);
// 21
// 宇智波鼬
//**********华丽的分割线**********
// undefined
// undefined
复制代码

结果刚刚相反,相当于无返回值时的处理。

所以我们可以根据这两个例子的结果去完善最后的代码,根据这个思路:

若当构造函数返回值是对象时,则new调用后也返回该对象实例。若当构造函数的返回值是基本类型或者无返回值时,都当作无返回值情况处理,该返回什么就返回什么。

最终代码:

function copyNew() {var obj = new Object();var constructor = [].shift.call(arguments);obj.__proto__ = constructor.prototype;var result = constructor.apply(obj, arguments);return typeof result === 'object' ? result : obj;
}
复制代码

参考:

  1. MDN
  2. JavaScript深入之new的模拟实现

转载于:https://juejin.im/post/5caaec416fb9a05e49446108

JS复习笔记之造new轮子相关推荐

  1. 【JS复习笔记】00 序

    作为一个前端苦手,说是复习,你就当我是重学好了. 好吧,我当然不可能抱着一个砖头去复习,所以捡了本薄的来读--<JavaScript语言精粹>. 当初带我的人说这本书挺好,就看这本书好了. ...

  2. JavaScript复习笔记

    js复习笔记 js复习笔记,内容来源自廖雪峰JavaScript教程,w3school,菜鸟教程 一.快速入门 1.基本语法 1)js是一种直译式脚本语言 2)js结束语句后的;可以省略不写,原因是执 ...

  3. 前端JS基础知识复习笔记(1)

    珠峰前端JS基础复习笔记(1) 在财务工作中自学了HTML和CSS之后,硬啃了JS高级编程三,实在觉得想要学的透是需要找一位好老师的,于是最近在学习周啸天老师的JS高级编程课,课外需要再补补基础,就回 ...

  4. 结合自己造的轮子实践按需加载

    本文提供了按需加载了几种思路,并给出了相应实践.原文地址 为了探究按需加载的本质,选择了对先前造的轮子 diana 进行实验. 实验一:全量引用 import * as _ from 'diana' ...

  5. c++语言自定义操作符,C++语言复习笔记二

    C++语言复习笔记二 零.OOP 特征:抽象-封装-继承-多态 一.自定义数据类型 1.类 class 类名 { private: 私有成员(本类) public: 公共成员(所有) protecte ...

  6. 造个轮子,动手实现一个复杂场景的表格组件(UniApp)

    造个轮子,动手实现一个复杂场景的表格组件(UniApp) 是一个成熟的程序猿了,要懂得自己造轮子(uniApp的插件市场找了一遍都没发现符合需求的插件,没有办法了,只能自己动手造个轮子).本文旨在复盘 ...

  7. 【人工智能】人工智能发展简史 | 复习笔记

    人工智能发展简史 人工智能基本概念 "人工智能" 是相对于"人类智能" 而言的,"人类智能"是"人工智能"的原型:&qu ...

  8. 【Web】javaEE课程复习笔记

    JavaEE复习笔记 根据上课的笔记整理与补充.涵盖web应用开发基础,jsp,标签,注解,struts,spring, mvc, 数据访问等内容 (因为转于个人blog,csdn图片无法显示,可至下 ...

  9. Spring复习笔记:4

    在复习笔记三中我们进行的案例的编写,我们可以发现,就算使用了注解的方式,xml配置文件文件还是不能够删除,现在我们来将一些新的注解可以让我们去掉xml配置文件. @Configuration 作用:指 ...

  10. matlab arr3(5 end),matlab复习笔记.doc

    matlab复习笔记.doc 如果一个语句在一行内书写太长了,可能要另起一行接着写,在这种情况下我们需要在第一行末打上半个省略号(),再开始第二行的书写.历史命令窗口(THEHISTORYCOMMAN ...

最新文章

  1. 炼个BERT别人花几分钟你花了快1天?谷歌:我这是4810亿参数的巨型BERT
  2. 2018新秀杯a城轨司机调度_城市轨道交通行车调度问题与优化方式研究
  3. 我的世界java手机版下载1.15_我的世界java版20w16a
  4. 渗透测试靶机搭建_对vulnhub中Android4靶机渗透测试全过程!
  5. PAM+4+matlab,基于PAM4调制的400G光模块
  6. ASCII编码:LinuxWindows
  7. Java——用户激活邮件工具类
  8. 耳机四根线的图解_耳机五根线如何连接
  9. win10从网络访问计算机没有guest,简单几步解决win10没有权限访问网络资源的问题...
  10. 打印机打印中文,截取字符时出现乱码问题
  11. 【C++】虚函数与虚函数表
  12. seo需要精通php吗?,SEO专职,我们不需要什么都精通吗?
  13. 为什么尽量不要使用全局变量?
  14. MySQL数据库,数据的约束
  15. VC++检测当前网络状态
  16. WF(Windows Workflow Foundation)
  17. python历史时间轴可视化_如何使用Python创建历史时间轴
  18. RK3399平台开发系列讲解(内核入门篇)1.42、Linux 文件系统是怎么工作的?
  19. macbook Python Turtle Graphics黑屏
  20. 慕课网:Web前端面试题目及答案汇总

热门文章

  1. 扣哒世界发布面向中小学阶段C++信奥课程体系
  2. Hibernate 的 could not initialize proxy - the owning Session was closed问题
  3. rough set_Rough.js使用Canvas和SVG制作手绘图形
  4. 计算机丢失msvc80.dll,msvcr80.dll丢失如何解决-msvcr80.dll丢失的解决方法
  5. 【06月24日】预分红股息率最高排名
  6. 电信路由器用linux开发板,WRTnode: WRTnode是基于家用无线路由器芯片的开源Linux开发板,想法源于我之前的项目和产业经验...
  7. win7安装ubuntu18.04双系统
  8. 用telnet登录163服务器发邮件
  9. jquery 立体走马灯_jquery实现跑马灯效果(一)
  10. android记账本折线图_小熊记账本