js原型和原型链 - 草履虫都看得懂

本文详细探讨了JavaScript中的原型、new操作符的工作原理,通过手动实现new和继承来理解其内部机制。还讨论了Object.create(null)创建纯净对象的用法,以及如何优化属性访问以提高性能。此外,解释了instanceof运算符的工作方式,并给出了手动实现的示例。最后,总结了这些基础知识在实际开发中的重要性。
摘要由CSDN通过智能技术生成

 关注公众号,每天都能领外卖红包

1、概念

搬自MDN - 实例对象的原型链指向它构造方法的原型。原型使用prototype访问,原型链用__proto__访问,虽然__proto__更大主流浏览器都支持,但MDN更推荐使用以下方法进行原型链读写,为了方便讲解文章使用__proto__来举例。

// get __proto__Object.getPrototypeOf();// set __proto__Object.setPrototypeOf();

关于原型和原型链,举个简单的例子

const object = new Object();

上述代码可知object是被Object构造出来的实例对象,Object是构造出object的构造方法,所以根据概念可以得出实例对象object的原型链指向构造方法Object的原型

object.__proto__ === Object.prototype; // true// orObject.getPrototypeOf(object) === Object.prototype; // true

2、new

new做了什么,再从MDN中搬下概念:

  1. 创建一个空的简单JavaScript对象(即{});

  2. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;

  3. 将步骤1新创建的对象作为this的上下文 ;

  4. 如果该函数没有返回对象,则返回this

手动实现一个:

const myNew = (constructor, ...params) => {  const obj = Object.create(null);  obj.__proto__ = constructor.prototype;  const result = constructor.call(obj, ...params);  return typeof result === 'object' ? result : obj;};

测试一下

function Person(type) { this.type = type || 'person'; }const student = myNew(Person, 'student');console.log(student);

打印

再测试一下js自带的new

function Person(type) { this.type = type || 'person'; }const student = new Person('student');console.log(student);

结果相同

3、Object.create(null)

const obj1 = Object.create(null);const obj2 = new Object();const obj3 = {};

比较常见创建对象方法有以上三种,Object.create(null)创建的是一个不包含原型链的纯净空对象,而第二种和第三种都会创建原型链,第三种可以理解成第二种的语法糖,也更为常见,分别打印他们结果

第一种:

第二种:

第三种,结果和第二种相同:

对象中属性的规则为当前对象如果找不到该属性则会顺着原型链,去一层层向上寻找,直到null,下面代码为例

Object.prototype.a = 1;const obj = {};console.log(obj.a); // 1

所以如果你的项目对性能有很大的要求,建议不要使用类似下面的代码来获取属性值,因为当对象属性a不存在的时候会试图遍历更高层的原型属性,直到null,像下面这样写性能会差些

const a = obj.a || 2;

你可以使用Object.create(null)创建一个没有原型链的纯净对象,或者使用Object.hasOwnProperty,他只会去访问当前对象属性不会去遍历原型链

const a = obj.hasOwnProperty('a') ? obj.a : 2;

4、继承

先说说ES6中的class关键字,如下

class Person {  construstor() { this.type = 'person'; }  getType() { return this.type; }}

形如java中的class语法,但他只是个语法糖,原理仍然是个对象,相当于

function Person() {  this.type = 'perosn';}Person.prototype.getType= function() { return this.type; } 

class继承也很简单,和java一样使用extendssuper

class Student extends Person {  construstor() {    super();    this.type = 'student';  }}const student = new Student();// studentconsole.log(student.type);// studentconsole.log(student.getType());

extendssuperclass一样也是语法糖,其核心操作为 - extends使实例对象可以访问到继承的对象属性和原型属性,super就是调用一下要继承的构造方法,并且将this指向他,实现一个简易版的单继承extends和super

// extends,也可以使用Object.create形式实现function myExtends(a, b) {  a.prototype.__proto__ = b.prototype;}// superfunction mySuper(a, b, ...params) {  a.call(b, ...params);}function Student() {  // 调用父类构造方法  mySuper(Person, this);  this.type = 'student';}// Student继承PersonmyExtends(Student, Person);const student = new Student();// studentconsole.log(student.type);// studentconsole.log(student.getType());

测试打印结果相同

顺便提一句,js中所谓在子类中对父类方法的重写,只是因为新重写的方法在原型链中离实例对象更近,所以调用优先级更高

5、instanceof

执行a instanceof b后,会判断a的原型链是否指向b的原型,如果不是会一直顺着原型链往上进行比较,一直到null

student instanceof Student // truestudent instanceof Person // truestudent instanceof Object // true

我们可以手动实现一个

function myInstanceof(a, b) {  let result = a;  while(result.__proto__) {    result = result.__proto__;    if (result === b.prototype) return true;  }  return null;}

测试打印,结果相同

student instanceof Student // truestudent instanceof Person // truestudent instanceof Object // true

6、结语

周末抽空巩固记录一下基础知识以上的内容如有错误请及时指出

 

可以关注我的公众号,都是原创技术文章,一起进步吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hhzzcc_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值