JavaScript 手写代码 第二期

您所在的位置:网站首页 js手写eventbus JavaScript 手写代码 第二期

JavaScript 手写代码 第二期

2023-06-25 01:51| 来源: 网络整理| 查看: 265

文章目录 1.为什么要手写代码?2. 手写代码2.1 手写实现判断类型函数2.1.1 前置知识2.1.1 手写实现 2.2 手写实现aplly,call,bind方法2.2.1 基本使用2.2.2 实现思路2.2.3 手写实现

1.为什么要手写代码?

我们在日常开发过程中,往往都是取出来直接用,从来不思考代码的底层实现逻辑,但当我开始研究一些底层的东西的时候,才开始理解了JavaScript每个方法和函数的底层实现思路,我认为这可以很好的提高我们的代码水平和逻辑思维。

2. 手写代码 2.1 手写实现判断类型函数 2.1.1 前置知识 let arr = [1, 2, 3]; let obj = { name: 'zs', age: 19, }; console.log(typeof null); // object console.log(typeof arr); // object console.log(typeof obj); // object

因此我们可以知道,当使用 typeof 判断数据类型的时候,无论是判断 null,Array,Object都会输出对象object 类型,所以就无法利用 typeof 方法判断他们的数据类型,所以我们就必须使用其他的方法解决这一个问题,Object.prototype.toString() 方法

Object.prototype.toString()方法介绍

每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中 type 是对象的类型。

Object.prototype.toString()方法的简单使用

console.log(Object.prototype.toString.call(obj)); // [object Object] console.log(Object.prototype.toString.call(arr)); // [object Array] console.log(Object.prototype.toString.call(null)); // [object Null]

可以看出来数组里面的后面就是 我们想要的数据类型,可以利用正则或者splice方法进行截取

2.1.1 手写实现 function getType(obj) { let type = typeof obj; if (type !== 'object') { // 先进行typeof判断,如果是基础数据类型,直接返回 return type; } // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果 return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); } 2.2 手写实现aplly,call,bind方法 2.2.1 基本使用

1.apply 方法 apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次 1.call 方法 call方法的第一个参数也是this的指向,后面传入的是一个参数列表,跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次 1.bind 方法 bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

2.2.2 实现思路 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用call方法等方式调用的情况判断传入上下文对象是否存在,如果不存在,则设置为window将函数作为上下文对象的一个属性判断参数值是否传入使用上下文对象来调用这个方法,并保存返回结果删除刚才新增的属性返回结果 2.2.3 手写实现

手写实现call方法

let name = 'zs'; let obj = { name: 'lisi', }; function getName(a, b, c) { console.log(this.name); console.log(a, b, c); } Function.prototype.myCall = function (context) { // 这里的this就是调用的方法 if (typeof this !== 'function') { throw new Error('type error'); } context = context || window; // 截取参数 let args = [...arguments].slice(1); // 在obj对象里面新增调用方法 context.fn = this; // 调用obj里面的方法fn let result = context.fn(...args); // 删除obj里面新增的方法 delete context.fn; return result; }; getName.myCall(obj, 1, 2, 3);

在这里插入图片描述 正常来说应该输出 ‘zs’ 说明我们通过我们手写的apply方法改变了getName的this指向 手写实现apply方法 只是传递参数的是必须是数组

Function.prototype.myApply = function (context) { // 这里的this就是调用的方法 if (typeof this !== 'function') { throw new Error('type error'); } context = context || window; // 截取参数 let args = [...arguments].slice(1); // 在obj对象里面新增调用方法 context.fn = this; // 调用obj里面的方法fn let result = context.fn(args); // 删除obj里面新增的方法 delete context.fn; return result; }; getName.myApply(obj, 1, 2, 3);

手写实现bind方法 bind方法实现思路稍有不同

判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用call等方式调用的情况,保存当前函数的引用,获取其余传入参数值创建一个函数返回函数内部使用 apply 来绑定函数调用,需要判断作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象

实现代码

Function.prototype.myBind = function (context) { // 判断调用对象是否为函数 if (typeof this !== 'function') { throw new TypeError('Error'); } // 获取参数 const args = [...arguments].slice(1), fn = this; return function Fn() { // 根据调用方式,传入不同绑定值 return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments)); }; };


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3