要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4个步骤:

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象;

1. new 操作符

在有上面的基础概念的介绍之后,在加上 new 操作符,我们就能完成传统面向对象的class + new的方式创建对象,在JavaScript中,我们将这类方式成为 Pseudoclassical。

基于上面的例子,我们执行如下代码

var obj = new Base();

这样代码的结果是什么,我们在Javascript引擎中看到的对象模型是:

new操作符具体干了什么呢? 其实很简单,就干了三件事情。

var obj  = {};
obj.proto = Base.prototype;
Base.call(obj);第一行,我们创建了一个空对象obj;
第二行,我们将这个空对象的 __proto__ 成员指向了 Base 函数对象 prototype 成员对象;
第三行,我们将 Base 函数对象的 this 指针替换成obj,然后再调用 Base 函数,于是我们就给 obj 对象赋值了一个 id 成员变量,
这个成员变量的值是 ”base” ,关于 call 函数的用法。

如果我们给 Base.prototype 的对象添加一些函数会有什么效果呢?

Base.prototype.toString = function() {return this.id;
}

那么当我们使用 new 创建一个新对象的时候,根据 proto 的特性,toString 这个方法也可以做新对象的方法被访问到。
于是我们看到了:
构造子对象中,我们来设置‘类’的成员变量(例如:例子中的id),构造子对象 prototype 中我们来设置 ‘类’ 的公共方法。于是通过函数对象和Javascript特有的 __ proto __ 与 prototype 成员及 new 操作符,模拟出类和类实例化的效果。

2. new操作中发生了什么

对于大部分前端开发者而言,new 一个构造函数或类得到对应实例,是非常普遍的操作了。
下面的例子中分别通过 构造函数 与 class类 实现了一个简单的创建实例的过程。

// ES5构造函数
let Dog = function (name, age) {this.name = name;this.age = age;
};
Dog.prototype.sayName = function () {console.log(this.name);
};
const myDog = new Dog('汪汪', 2);
myDog.sayName() // '汪汪'// ES6 class类
class Cat {constructor(name, age) {this.name = name;this.age = age;}sayName() {console.log(this.name);}
};
const myCat = new Cat('QIU', 3);
myCat.sayName(); // QIU

但 new 不应该像一个黑盒,我们除了知道结果,更应该明白过程究竟如何。

比较直观的感觉,当我们 new 一个构造函数,得到的实例继承了构造器的构造属性( this.name 这些) 以及原型上的属性
在《JavaScript模式》这本书中,new 的过程说的比较直白。当我们 new 一个构造器,主要有三步:

  1. 创建一个空对象,将它的引用赋给 this,继承函数的原型;
  2. 通过 this 将属性和方法添加至这个对象;
  3. 最后返回 this 指向的新对象,也就是实例(如果没有手动返回其他的对象);

改写上面的例子,大概就是这样:

// ES5构造函数
let Dog = function (name, age) {// 1.创建一个新对象,赋予this,这一步是隐性的,//   let this = {};// 2.给this指向的对象赋予构造属性this.name = name;this.age = age;// 3.如果没有手动返回对象,则默认返回this指向的这个对象,也是隐性的// return this;
};
const myDog = new Dog();

这应该不难理解,你应该在工作中看过类似下述代码中的操作,将this赋予一个新的变量(例如 that ),最后返回这个变量

// ES5构造函数
let Dog = function (name, age) {let that = this;that.name = name;that.age = age;return that;
};
const myDog = new Dog('汪汪', 2);

为什么要这么写呢?
我在前面说 this 的创建与返回是隐性的,但在工作中为了让构造过程更易可见与更易维护,所以才有了上述使用 that 代替 this,同时手动返回 that 的做法;
这也验证了隐性的这两步确实是存在的。

但上述这个解释我觉得不够完美,它只描述了构造器属性是如何塞给实例,没说原型上的属性是如何给实例继承的。

我在winter大神的重学前端专栏中,看到了比较符合我心意的,同时也是符合原理的描述:

  • 以构造器的 prototype 属性为原型,创建新对象;
  • 将 this (也就是上一句中的新对象)和调用参数传给构造器,执行;
  • 如果构造器没有手动返回对象,则返回第一步创建的对象;

到这里不管怎么说,你都应该大概知道了new过程中:会新建对象,此对象会继承构造器的原型与原型上的属性,最后它会被作为实例返回这样一个过程。知道了原理,我们来手动实现一个简单的new方法。

3. 实现一个简单的 new 方法

// 构造器函数
let Dog = function (name, age) {this.name = name;this.age = age;
};
Dog.prototype.sayName = function () {console.log(this.name);
};// 定义的new方法
let newMethod = function (Dog, ...rest) {// 1. 以构造器的 prototype 属性为原型,创建新对象;let myDog = Object.create(Dog.prototype);// 2. 将this和调用参数传给构造器执行Dog.apply(myDog, rest);// 3. 返回第一步的对象return myDog;
};// 创建实例,将构造函数 Dog 与形参作为参数传入
const myDog = newMethod(Dog, '汪汪', 2);
myDog.sayName() // '汪汪';// 最后检验,与使用new的效果相同
console.log( myDog instanceof Dog ) // true
console.log( myDog.hasOwnProperty('name') ); // true
console.log( myDog.hasOwnProperty('age') ); // true
console.log( myDog.hasOwnProperty('sayName') );// false

JavaScript中 new 一个对象过程详解相关推荐

  1. JavaScript中DOM对象的详解

    *** JavaScript中DOM对象的详解*** DOM对象:Document Object Model,文档对象模型.也称为document(文档对象),是HTML页面当前窗体的内容,是连接JS ...

  2. php 实现setinterval,JavaScript中setInterval的使用详解

    相信很多大伙都知道JavaScript中setInterval的作用是在播放动画的时,每隔一定时间就调用函数,方法或对象,也有很多小伙伴对此也只是知道setInterval的定义.也是一知半解,今天我 ...

  3. Javascript中的Document对象详解

    Document对象详解 document 文挡对象 - JavaScript脚本语言描述           -------------------------------------------- ...

  4. 数据包在网络中的传输过程详解

    我们当今使用电子设备都离不开网络,通过网络我们可以聊天.玩游戏.看电影都操作. 网络的本质就是交换数据. 本文我们就来看下数据是如何在网络中传输的. 计算机网络模型 现在有两种计算机网络模型,分别为O ...

  5. javascript中的闭包closure详解

    文章目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一 ...

  6. JavaScript 中常见排序算法详解

    十大经典算法 一张图概括: 名词解释: n:数据规模 k:"桶"的个数 In-place:占用常数内存,不占用额外内存 Out-place:占用额外内存 稳定性:排序后2个相等键值 ...

  7. javascript 中match函数使用详解

    javascript中的match函数是使用正则表达式对字符串进行查找,并将查找的结果作为数组返回,在实际开发中非常的有用,使用方法如下: stringObj.match(rgExp) 其中strin ...

  8. JavaScript中的valueOf方法详解

    Object.prototype.valueOf() valueOf() 方法返回指定对象的原始值. 语法 object.valueOf() 返回值 返回值为该对象的原始值. 描述 JavaScrip ...

  9. JavaScript中的window对象详解

    1.window对象简介 (1)在JavaScript中,一个浏览器窗口就是一个window对象. (2)一个窗口就是一个window对象,这个窗口里面的HTML文档就是一个document对象,do ...

  10. 理解JavaScript中this的指向详解

    this的定义和理解: this是JavaScript语言的一个关键字,它是函数运行时,在函数体内部自动生成的一个对象,只能在函数体内使用. 1.this和执行环境对象有关,和函数的声明无关. var ...

最新文章

  1. 【Spring】bean的作用域(@Scope) - singleton、prototype
  2. 水稻微生物组时间序列分析4-随机森林回归
  3. 以Dubbo为例,聊聊如何为开源项目做贡献
  4. Hystrix 熔断器02 —— hystrix 案例之高并发测试
  5. iview的select联动_iview2 之select二级联动细谈
  6. html按钮按下效果_CSS+HTMLlt;水滴按钮效果gt;
  7. 32位JDK和64位JDK
  8. NodeJs取参的四种方法
  9. 概率霍夫变换(Progressive Probabilistic Hough Transform)原理详解
  10. JavaScript获取坐标
  11. HarmonyOS IoT首著,走进万物互联的世界!
  12. php 非常简单的导入sql文件
  13. ps aux 输出格式
  14. Linux系统分区管理与swap分区
  15. 电脑账户服务器未能登录拒绝访问,win7系统开机提示服务未能登入拒绝访问的解决方法...
  16. centos6使用devtoolset快速升级GCC版本4.8/5.2/8.3
  17. 微信公众号学习--点亮图片
  18. 如何使投资收益最大化?
  19. Pytorch实现基于深度学习的面部表情识别(最新,非常详细)
  20. 计算机网络安全运维管理工作总结,计算机设备日常运维工作总结

热门文章

  1. 数据结构 将两个有序的链表合并为一个新链表
  2. Cocos2d-x制作《单机斗地主》源码解剖5:玩家的出牌
  3. Linux驱动开发(九)---树莓派I2C设备驱动开发(BME280)
  4. 在linux系统中查看mysql版本_Linux系统下查看mysql版本的四种方法_MySQL
  5. JavaScript获取完整当前域名
  6. 深入探究Retinex
  7. SysTrace常识
  8. Linux加入Windows域
  9. 虚拟机安装程序没有找到安装在此计算机上的硬盘驱动器,安装VMware提示无效驱动器:E:\ 解决方法...
  10. 触摸屏调出虚拟键盘_win7系统中打开虚拟键盘的两种方法(屏幕键盘)