Iwen's blog Iwen's blog
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于

Iwen

不摸鱼的哥哥
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于
  • Vue

  • Vue进阶

  • CSS

  • ES6

  • Base

  • Core

  • Array

  • Object

  • String

  • Async

  • Browser

  • Http

  • 性能优化

  • 正则

  • 经典总结

  • 设计模式

  • 数据结构

  • 算法

  • 手写

    • call、apply
    • 实现bind函数
    • instanceOf
    • new 原理及模拟实现
      • 定义
      • 模拟实现第一步
      • 模拟实现第二步
      • 参考
    • 防抖、节流
    • 发布订阅模式
    • 深拷贝
    • Promise A+
    • Promise 进阶
    • Array-prototype-map
    • Array-prototype-filter
    • Array-prototype-reduce
    • 并发请求
    • 继承
    • JSON 字符串
  • TypeScript

  • 复盘
  • 手写
Mr.w
2020-11-29

new 原理及模拟实现

# new 原理及模拟实现

# 定义

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

举个栗子

function Car(color) {
    this.color = color;
}
Car.prototype.start = function() {
    console.log(this.color + " car start");
}

var car = new Car("black");
car.color; // 访问构造函数里的属性
// black

car.start(); // 访问原型里的属性
// black car start
1
2
3
4
5
6
7
8
9
10
11
12
13

可以看出 new 创建的实例有以下 2 个特性

  1. 能访问到构造函数里的属性
  2. 能访问到原型里的属性

这就有要说另一个面试经典问题:new 的过程了,(ಥ_ಥ)

# 模拟实现第一步

new 是关键词,不可以直接覆盖。这里使用 create 来模拟实现 new 的效果。

new 返回一个新对象,通过 obj.__proto__ = Con.prototype 继承构造函数的原型,同时通过 Con.apply(obj, arguments)调用父构造函数实现继承,获取构造函数上的属性;

实现代码如下

// 第一版
function create() {
	// 创建一个空的对象
    var obj = new Object(),
	// 获得构造函数,arguments中去除第一个参数
    Con = [].shift.call(arguments);
	// 链接到原型,obj 可以访问到构造函数原型中的属性
    obj.__proto__ = Con.prototype;
	// 绑定 this 实现继承,obj 可以访问到构造函数中的属性
    Con.apply(obj, arguments);
	// 返回对象
    return obj;
};
1
2
3
4
5
6
7
8
9
10
11
12
13

测试一下

// 测试用例
function Car(color) {
    this.color = color;
}
Car.prototype.start = function() {
    console.log(this.color + " car start");
}

var car = create(Car, "black");

car.color;      // black
car.start();    // black car start
1
2
3
4
5
6
7
8
9
10
11
12

完美!

# 模拟实现第二步

上面的代码已经实现了 80%,现在继续优化。

构造函数返回值有如下三种情况:

  1. 返回一个对象
  2. 没有 return,即返回 undefined
  3. 返回undefined以外的基本类型

情况1:返回一个对象

function Car(color, name) {
    this.color = color;
    return {
        name: name
    }
}
var car = new Car("black", "BMW");
car.color;  // undefined
car.name;   // "BMW"
1
2
3
4
5
6
7
8
9

实例car中只能访问到返回对象中的属性。

情况2:没有 return,即返回 undefined

function Car(color, name) {
    this.color = color;
}
var car = new Car("black", "BMW");
car.color;  // black
car.name;   // undefined
1
2
3
4
5
6

实例 car 中只能访问到构造函数中的属性,和情况1完全相反。

情况3:返回undefined以外的基本类型

function Car(color, name) {
    this.color = color;
    return "new car";
}
var car = new Car("black", "BMW");
car.color;  // black
car.name;   // undefined
1
2
3
4
5
6
7

实例 car 中只能访问到构造函数中的属性,和情况1完全相反,结果相当于没有返回值。

所以需要判断下返回的值是不是一个对象,如果是对象则返回这个对象,不然返回新创建的obj对象。

// 第二版
function create() {
	// 1、获得构造函数,同时删除 arguments 中第一个参数
    Con = [].shift.call(arguments);
	// 2、创建一个空的对象并链接到原型,obj 可以访问构造函数原型中的属性
    var obj = Object.create(Con.prototype);
	// 3、绑定 this 实现继承,obj 可以访问到构造函数中的属性
    var ret = Con.apply(obj, arguments);
	// 4、优先返回构造函数返回的对象
	return ret instanceof Object ? ret : obj;
};

// 第二版的代码
function objectFactory() {
    var obj = new Object(),
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    var ret = Constructor.apply(obj, arguments);
    return typeof ret === 'object' ? ret : obj;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 参考

  • JavaScript 深入之 new 的模拟实现 (opens new window)
  • MDN 之 Symbol (opens new window)
  • MDN 之 new 运算符 (opens new window)
  • javascript 函数 add(1)(2)(3)(4) 实现无限极累加 (opens new window)
instanceOf
防抖、节流

← instanceOf 防抖、节流→

最近更新
01
flex布局页面自适应滚动条问题
12-28
02
前后端分离开发请求接口跨域如何携带cookie的问题
12-28
03
怎么实现div长宽比固定width-height4比3
12-28
更多文章>
Theme by Vdoing | Copyright © 2017-2022 Iwen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式