学习Javascript之模拟实现new

前言

本文1021字,阅读大约需要5分钟。

总括: 本文对new进行了一个简单介绍,然后使用一个函数模拟实现了new操作符做的事情。

  • 参考文档:new 运算符
  • 公众号:「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

人生是没有毕业的学校。

正文

new是JS中的一个关键字,用来将构造函数实例化的一个运算符。例子:

function Animal(name) {
	this.name = name;
}
Animal.prototype.sayName = function() {
	console.log("I'm " + this.name);
}
var cat = new Animal('Tom');
console.log(cat.name); // Tom
console.log(cat.__proto__ === Animal.prototype); // true
cat.sayName(); // I'm Tom

从上面的例子可以得出两点结论:

  1. new操作符实例化了一个对象;
  2. 这个对象可以访问构造函数的属性;
  3. 这个对象可以访问构造函数原型上的属性;
  4. 对象的**_proto_**属性指向了构造函数的原型;

由于new是关键字,我们只能去声明一个函数去实现new的功能,首先实现上面的三个特性,第一版代码如下:

附:对原型原型链不熟悉的可以先看理解Javascript的原型和原型链

// construct: 构造函数
function newFunction() {
  var res = {};
  // 排除第一个构造函数参数
  var construct = Array.prototype.shift.call(arguments);
  res.__proto__ = construct.prototype;
  // 使用apply执行构造函数,将构造函数的属性挂载在res上面
  construct.apply(res, arguments);
  return res;
}

我们测试下:

function newFunction() {
  var res = {};
  var construct = Array.prototype.shift.call(arguments);
  res.__proto__ = construct.prototype;
  construct.apply(res, arguments);
  return res;
}
function Animal(name) {
	this.name = name;
}
Animal.prototype.sayName = function() {
	console.log("I'm " + this.name);
}
var cat = newFunction(Animal, 'Tom');
console.log(cat.name); // Tom
console.log(cat.__proto__ === Animal.prototype); // true
cat.sayName(); // I'm Tom

一切正常。new的特性实现已经80%,但new还有一个特性:

function Animal(name) {
    this.name = name;
    return {
        prop: 'test'
    };
}
var cat = new Animal('Tom');
console.log(cat.prop); // test
console.log(cat.name); // undefined
console.log(cat.__proto__ === Object.prototype); // true
console.log(cat.__proto__ === Animal.prototype); // false

如上,如果构造函数return了一个对象,那么new操作后返回的是构造函数return的对象。让我们来实现下这个特性,最终版代码如下:

// construct: 构造函数
function newFunction() {
  var res = {};
  // 排除第一个构造函数参数
  var construct = Array.prototype.shift.call(arguments);
  res.__proto__ = construct.prototype;
  // 使用apply执行构造函数,将构造函数的属性挂载在res上面
  var conRes = construct.apply(res, arguments);
  // 判断返回类型
  return conRes instanceof Object ? conRes : res;
}

测试下:

function Animal(name) {
	this.name = name;
  return {
    prop: 'test'
	};
}
var cat = newFunction(Animal, 'Tom');
console.log(cat.prop); // test
console.log(cat.name); // undefined
console.log(cat.__proto__ === Object.prototype); // true
console.log(cat.__proto__ === Animal.prototype); // false

以上代码就是我们最终对new操作符的模拟实现。我们再来看下官方对new的解释

引用MDN对new运算符的定义:

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

new操作符会干下面这些事:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

4条都已经实现。还有一个更好的实现,就是通过Object.create去创建一个空的对象:

// construct: 构造函数
function newFunction() {
  // 通过Object.create创建一个空对象;
  var res = Object.create(null);
  // 排除第一个构造函数参数
  var construct = Array.prototype.shift.call(arguments);
  res.__proto__ = construct.prototype;
  // 使用apply执行构造函数,将构造函数的属性挂载在res上面
  var conRes = construct.apply(res, arguments);
  // 判断返回类型
  return conRes instanceof Object ? conRes : res;
}

以上。


能力有限,水平一般,欢迎勘误,不胜感激。

订阅更多文章可关注公众号「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

前端进阶学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以回答这个问题。以下是一个简单JavaScript 代码模拟电梯的实现: ``` class Elevator { constructor(numFloors) { this.floor = 0; this.numFloors = numFloors; this.direction = 'up'; this.stops = []; this.currentStop = null; this.running = false; } request(floor) { if (floor > this.numFloors) { console.log('Error: Requested floor is above the top floor of the building.'); return; } else if (floor < 1) { console.log('Error: Requested floor is below the bottom floor of the building.'); return; } this.stops.push(floor); if (!this.running) { this.run(); } } run() { this.running = true; while (this.stops.length > 0) { this.currentStop = this.nextStop(); if (this.currentStop > this.floor) { this.direction = 'up'; } else if (this.currentStop < this.floor) { this.direction = 'down'; } console.log(`Floor ${this.floor}`); while (this.floor !== this.currentStop) { this.floor = this.direction === 'up' ? this.floor + 1 : this.floor - 1; console.log(`Floor ${this.floor}`); } console.log(`Stopping at floor ${this.floor}`); this.stops.splice(this.stops.indexOf(this.currentStop), 1); } this.running = false; } nextStop() { let nextFloor = this.floor; if (this.direction === 'up') { for (let i = 0; i < this.stops.length; i++) { if (this.stops[i] >= this.floor && this.stops[i] < nextFloor) { nextFloor = this.stops[i]; } } } else if (this.direction === 'down') { for (let i = 0; i < this.stops.length; i++) { if (this.stops[i] <= this.floor && this.stops[i] > nextFloor) { nextFloor = this.stops[i]; } } } return nextFloor; } } const elevator = new Elevator(10); elevator.request(3); elevator.request(7); elevator.request(2); ``` 这个代码实现了一个 Elevator 类,该类具有请求电梯并移动到所需楼层的能力。该代码以 1 作为底层楼层。要测试代码,您可以将代码粘贴到浏览器的控制台中,然后调用 `elevator.request()` 方法以请求所需的楼层。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值