javaScript手写专题——实现instanceof/call/apply/bind/new的过程/继承方式

目录

原型链相关

手写instanceof

实现一个_instance方法,判断对象obj是否是target的实例

 测试

 手写new的过程

实现一个myNew方法,接收一个构造函数以及构造函数的参数,返回构造函数创建的实例对象

测试myNew方法

手写类的继承

ES6:class+extends实现继承

组合继承:调用两次父类构造函数

Object.create原型式继承

寄生组合式继承:调用一次父类构造函数+通过object()复制原型

手写call/apply/bind方法

手写call方法

普通版call方法

 使用Symbol标识属性

处理非object类型绑定

测试call方法

手写apply方法

手写bind方法

 bind使用场景

普通版bind方法

用作构造函数boundFn处理

考虑构造函数继承

 测试bind方法


原型链相关

原型链(prototype chain)是 JavaScript 中面向对象编程的一个重要概念,用于实现对象的继承和共享属性。每个函数(构造函数)都有一个 prototype 属性,指向一个对象,这个对象称为原型对象。这个原型对象包含了所有实例共享的属性和方法。

当我们使用构造函数创建一个新对象时,新对象一个隐式的原型属性(__proto__,指向构造函数的原型对象。这样,新对象就可以通过原型链访问到构造函数原型对象上的属性和方法。

如果我们继续查找 __proto__ 属性,可以找到一个叫做 Object.prototype 的对象,它是所有对象的原型。如果继续查找 __proto__ 属性,会找到 null,表示原型链的结束。

这就形成了一个原型链的连接,从新对象的 __proto__ 属性可以一直向上查找到 Object.prototype,然后再查找到 null。这种连接方式让所有对象都可以继承 Object.prototype 的属性和方法,并且可以通过原型链实现对象的继承和共享属性。

手写instanceof

实现一个_instance方法,判断对象obj是否是target的实例

思路:instanceof的原理是基于原型链的概念,通过遍历对象的原型链,检查原型链中的某个原型是否等于目标构造函数的 prototype 属性。如果找到匹配,则返回 true,否则返回 false

instanceof使用场景:我们通常用typeof判断基本类型、symbol、function。对于对象的具体类型,通常用instanceof来判断,比如判断Map、Set、Array、Date类型。 

function _instanceof(obj, target) {
  //instanceof只检测对象
  if (typeof obj != "object" || obj == null) {
    return false;
  }
  let proto = Object.getPrototypeOf(obj); //拿到对象的原型
  //   let proto = obj.__proto__;
  while (proto) {
    if (proto == target.prototype) {
      //原型上找到了target
      return true;
    }
    proto = Object.getPrototypeOf(proto);
    // proto = proto.__proto__;
  }
  return false;
}

 可以通Object.getPrototypeOf()方法拿到对象/构造函数原型的原型

也可以使用__proto__两个下划线proto拿到原型

 测试

对Array、Set、Map类型进行测试

console.log(_instanceof(null, Array));
console.log(_instanceof([], Array)); //判断数组
console.log(_instanceof({}, Array));
console.log(_instanceof({}, Object)); //普通对象
const set = new Set();
console.log(_instanceof(set, Set)); //判断Set
const map = new Map();
console.log(_instanceof(map, Map)); //判断Map
const date = new Date();
console.log(_instanceof(date, Date)); //判断Date

 手写new的过程

实现一个myNew方法,接收一个构造函数以及构造函数的参数,返回构造函数创建的实例对象

思路:

  1. 创建一个对象obj,使用 constructor.prototype 作为其原型。
  2. 使用 apply 方法改变构造函数 constructorthis 指向为新对象 obj,并将 args 传递给 constructor
  3. 如果 constructor 返回一个对象,则返回 constructor 返回的对象;否则返回 newObj
//第一个参数构造函数,第二个通过...拿到的args参数
function myNew(constructor, ...args) {
  const obj = Object.create(constructor.prototype);
  let res = constructor.apply(obj, args); //使用apply绑定this,传args类数组对象,执行constructor构造函数方法
  //   let res = constructor.call(obj, ...args);
  return typeof res === "object" ? res : obj; //构造函数如果没有返回值,返回obj;如果有返回值,返回res
}

在myNew方法中调用constructor方法,需要显示通过call或apply改变this。让方法找调用的对象obj。

测试myNew方法

测试myNew方法,打印person实例,调用person方法

// 测试
function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.say = function () {
  console.log(this.age);
};
let person = myNew(Person, "三月的一天", 18);
console.log(person);
person.say();

手写类的继承

在过去,JavaScript 中实现类的继承有多种方式,包括原型链继承、构造函数继承、组合继承、原型式继承等。这些方式各有优缺点,需要开发人员根据具体情况进行选择和使用。

但是,随着 ES6 的普及和使用,开发人员可以更多地关注使用 classextends 实现继

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

像素棱镜

你的鼓励将是我前进的动力。

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

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

打赏作者

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

抵扣说明:

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

余额充值