JavaScript 自定义对象 及 new原理与实现 如何完整地手写实现new

简介: JavaScript 自定义对象 及 new 原理与实现 如何完整地手写实现new

JavaScript 自定义对象 及 new 原理与实现


李俊才(jcLee95)的个人博客

已入驻阿里云社区

邮箱 :291148484@163.com
本文地址

目 录


1. 引入:JavaScript中自定义对象的方法

2. new 运算符在创建自定义对象的过程

3. 自己实现一个拥有new功能的函数

4. 使用 new 创建 类(class) 实例


object 表示类型,是 JavaScript 的六种 主要类型 之一(ES6后新增了Symbol为7种) ,也就是我们所说的 “对象” ,用于存储各种键值集合和更复杂的实体。Object()(首字母大写)是JavaScript语言中提供的用于创建 object 的构造器,相当于一些语言中的 Object 类,也就是说在 JavaScript 中所有的对象都是 Object "类"的实例。

使用new是运算符用于创建对象的方式之一。

1. JavaScript中自定义对象的方法

1.1 直接创建

在一对花括号中填写若干个属性名和属性值的方法可以用于直接创建对象,这是最简单也最直观的方法,其格式为:

varobjName= {
attribName1: attribvalue1, 
attribName2: attribvalue2, 
...  }

例如:

varstudent= {
name: '李华',
age: 12,
sex: 'male'}

1.2 通过 Object 对象创建

Object是JavaScript内置对象构造器,

obj=newObject([value])

例如:

varstudent=newObject();
student.name='李华';
student.age=12;
student.sex='male';

这与 1.1 节例子中创建的对象是一样的。

1.3 通过自定义构造函数创建

以下这种方式只能在非严格模式下成立:

// 1. 定义作为`构造函数`的函数functionTeacher(name, sex, height){
this.name=name;
this.sex=sex;
this.height=height;
}
// 创建对象实例varteacher1=newTeacher("ZhangSan", "male", 190);

1.4 关于 this 的指向的说明

1. 在全局执行环境中(在任何函数体外部)this 都指向全局对象。在浏览器中, window 对象同时也是全局对象。

【注意】在严格模式下将有所不同,函数内部的this会若无赋值,将一直保持为undefined

2. 在函数内部,this的值取决于函数被调用的方式

1.3 节中,如果直接调用Teacher函数即执行("ZhangSan", "male", 190)this将指向window对象(非严格模式)。然而将其作为构造器使用时,即执行new Teacher("ZhangSan", "male", 190)时,new运算符改变了this的指向,使其不再指向window,而是指向新创建的对象。这在之后的自己实现 new章节的代码中将会看到具体的过程。

2. new 运算符在创建自定义对象的过程

new运算符创建一个用户定义的对象类型的实例具有构造函数的内置对象的实例。具体来说,它做了以下工作:

  • (1)创建一个空的简单JavaScript对象(即{});
  • (2)为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象
  • (3)将(1)中新创建的对象作为this的上下文 ;
  • (4)如果该函数没有返回对象,则返回this

Object.prototype.__proto__已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。通过现代浏览器的操作属性的便利性,可以改变一个对象的 [[Prototype]] 属性, 这种行为在每一个JavaScript引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.proto = … 语句上, 它还会影响到所有继承来自该 [[Prototype]] 的对象,如果你关心性能,你就不应该在一个对象中修改它的 [[Prototype]]。

3. 自己实现一个拥有new功能的函数

3.1 完整手写实现

为了完整体现new的过程,这里禁止调用Object.create()Function.prototype.apply()这两个方法,完整地按照2 小节中的步骤进行实现。

functionmyNew(cstrct,...params){
// 1.创建一个空的JavaScript对象 objconstobj= {};
// 2.为新创建的对象(obj)添加属性`__proto__`,// 并将该属性 链接至 构造函数的 原型对象  ;obj.__proto__=cstrct.prototype; 
// 3. 将该新对象(obj)作为this的上下文 ;// 3.1 在 obj.__proto__ 上临时挂上构造函数obj.__proto__._func=cstrct;
// 3.2 执行该构造函数得到 "this"let_=obj._func(...params);
// 3.3 删除该临时挂载的属性 _func(否则实例上会多出这个属性)deleteobj.__proto__._func// 4. 如果该函数没有返回对象,即null或undefined,// 则返回this,否则返回该对象return_instanceofObject?_ : obj;
}

3.2 调用现成方法实现

了解了完整地实现过程之后,再介绍两个方法:

方法 语法 描述
Object.create() Object.create(proto,[propertiesObject]) 使用指定的原型对象和属性创建一个新对象。
Function.prototype.apply() func.apply(thisArg, [argsArray]) 用于调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
返回 调用有指定this值和参数的函数的结果。

因此3.1 节中的

functionmyNew(cstrct,...params){
constobj=Object.create(cstrct.prototype)
obj.__proto__._func=cstrct;
// 3.2 执行该构造函数得到let_=obj._func(...params);
// 删除该临时挂载的属性 _func(否则实例上会多出这个属性)deleteobj.__proto__._funcreturn_instanceofObject?_ : obj;
}

4. 使用 new 创建 类(class) 实例

首先很遗憾地说,JavaScript 并不是基于 的面向对象编程语言,即使在有了class关键字后,本质上还是基于原型链的,而class只是为了模仿其它语言中的类而新增的语法糖。ES6引入了也就是class,其本质上是一个JavaScript 函数

例如:

classCar{
publiccolor;
publicheight;
constructor(color,height){
this.color=color;
this.height=height;
  }
run(){
console.log('I am running at high speed...');
  }
serfIntroduce(){
console.log(`I am a ${this.color}car with a height of ${this.height.toString()}meters.`)
  }
}
constlamborghini=newCar('green',1.05)

实际上上面的代码只是以下代码使用class语法糖的结果:

varCar= (function () {
functionCar(color, height) {
this.color=color;
this.height=height;
    }
Car.prototype.run=function () {
console.log('I am running at high speed...');
    };
Car.prototype.serfIntroduce=function () {
console.log("I am a ".concat(this.color, " car with a height of ").concat(this.height.toString(), " meters."));
    };
returnCar;
}());
varlamborghini=newCar('green', 1.05);
lamborghini.serfIntroduce();
lamborghini.run();

从以上代码可以看出虽然自从ES6标准发布后在形式上看JavaScript中的"类"看起来就像 Java 等语言中的类用法一样,但本质上JavaScript中的new只是模拟了Java等语言中new的行为。

目录
相关文章
|
20小时前
|
Web App开发 JavaScript 前端开发
JavaScript 中的 Range 和 Selection 对象
JavaScript 中的 `Range` 和 `Selection` 对象用于处理文本选择。`Range` 表示文档中选定的区域,而 `Selection` 表示用户选择的文本或光标位置。`Range` 可以创建并设置于任何元素或文本,具有多个属性(如 `startContainer`, `endContainer`, `collapsed`)和方法(如 `cloneContents`, `deleteContents`)。`Selection` 提供了获取和操作用户选择的方法,如 `anchorNode`, `focusNode` 和 `addRange`。两者在所有现代浏览器中基本兼容。
5 1
JavaScript 中的 Range 和 Selection 对象
|
2天前
|
JSON JavaScript 安全
向js发送含有NSDictionary对象或NSArray对象的消息
向js发送含有NSDictionary对象或NSArray对象的消息
9 0
|
3天前
|
前端开发 JavaScript
前端 JS 经典:判断对象属性是否存在
前端 JS 经典:判断对象属性是否存在
7 0
|
6天前
|
JSON 前端开发 JavaScript
前端 JS 经典:JSON 对象
前端 JS 经典:JSON 对象
10 0
|
6天前
|
前端开发 JavaScript
前端 js 经典:原型对象和原型链
前端 js 经典:原型对象和原型链
16 1
|
6天前
|
JavaScript 前端开发 流计算
使用JavaScript 中的Math对象和勾股定理公式,计算鼠标的位置与页面图片中心点的距离,根据距离对页面上的图片进行放大或缩小处理
使用JavaScript 中的Math对象和勾股定理公式,计算鼠标的位置与页面图片中心点的距离,根据距离对页面上的图片进行放大或缩小处理
|
7天前
|
JSON JavaScript 前端开发
js将json字符串还原为json对象
【5月更文挑战第14天】js将json字符串还原为json对象
30 1
|
8月前
|
JSON JavaScript 前端开发
JavaScript的自定义对象
JavaScript的自定义对象
|
9天前
|
存储 JavaScript 前端开发
JavaScript 自定义对象 及 new()原理与实现 如何完整地手写实现new
JavaScript 自定义对象 及 new()原理与实现 如何完整地手写实现new
82 0
|
JavaScript 前端开发
JavaScript基础——自定义对象
JavaScript基础——自定义对象
121 0