js 解析表达式,js的算法案例

2023-12-05

大家好,给大家分享一下js 解析表达式,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!

01. 模拟实现 new

首先,这里呢,先简单说明一下 new 关键字的基本作用,有以下三点:

  • 创建一个新的对象
  • 把Person方法的原型 prototype 挂载到了obj的原型链 __proto__
  • 返回一个新的对象

所以呢,我们可以根据它的这三个特性,来自定义个一个方法 objectFactory ,如下所示:

function person(name, age) {
  this.name = name
  this.age = age

  return this
}

function objectFactory() {
	const obj = new Object(); // 1. 创建一个新的对象
	const Constructor = [].shift.call(arguments);  
	obj.__proto__ = Constructor.prototype; // 2. 把Person方法的原型挂载到了obj的原型链上
	const ret = Constructor.apply(obj, arguments); 
	return typeof ret === "object" ? ret : obj;  // 3. 返回一个新的对象
}

objectFactory(person, 'michel', '18')
02. 防抖函数实现

首先呢,这里简单介绍一下,什么是防抖函数,防抖函数呢,就是在一段时间内,多次执行,只算最后一次,所以呢,按照这个需求,我们如下实现:

var btn = document.getElementById('btn');
btn.addEventListener('click',fn(()=>{
    console.log('12321');
}));

function fn(callback){
    let timer = null;
    return function(){
        console.log('click')
        clearTimeout(timer);
        timer = setTimeout(()=>{
            callback()
        },3000);
    }
}

控制台打印:
在这里插入图片描述

03. 节流函数实现

这里我们来了解下节流函数,什么是节流函数呢,在某些时候,我们可能会很快的触发事件,但是我们的页面只需要响应一次,所以我们需要做一下节流,测试代码如下:

const throttle = (callback) => {
let flag = true
	return () => {
		console.log('click')
		if(!flag) return
		flag = false;
		setTimeout(() => {
			  flag = true;
			  callback()
		}, 3000)	
	}
}

let btn = document.querySelector('#btn');
btn.addEventListener('click', throttle(() => {
	console.log('输出执行结果')
})  );

最终执行结果:
在这里插入图片描述
从这个最终的效果,我们可以发现无论我们怎么点,或者快速点击多少次,这里只是在三秒后输出了对应的结果,这就是节流的一个概念,无论你怎么点,怎么触发,这段时间我就执行这一次,当然实现的核心就是这个 flag 这个开关进行控制,至于为什么会有美女,当然也是为了开发体验啦,作为程序猿们,你懂得 ~

04. 自定义事件 Emiter 实现

我们首先来了解一下,什么是自定义事件,如果大家使用过 addEventListener 这种类型的事件绑定,那大家对事件监听应该是非常熟悉的,那我们如何来手动实现一个我们自己的订阅-发布模式的自定义事件呢,好我们根据需求编辑如下:

class Eventer {
	constructor(){
		this.events = new Map();
	}
	
	// 在序列中找到并且执行方法
	emit(event_name){
		let handler = this.events.get(event_name);
		// 判断是否带参数
		if(arguments.length > 0){
			handler.apply(this, arguments)
		}else{
			handler.call(this)
		}
	}
	
	// 监听并塞入序列
	on(event_name, fn){
		if(!this.events.get(event_name)){
			this.events.set(event_name, fn);
		}
	}
	
	// 删除事件
	delete(event_name){
		if(this.events.get(event_name)){
			this.events.delete(event_name);
		}
	}
}

// 调用执行
let btn = document.getElementById('btn');
let emiter = new Eventer();
emiter.on('click-btn', function(){
	console.log('你点击按钮啦');
})
btn.onclick = function(){
	emiter.emit('click-btn');
}

浏览器控制台,测试案例打印效果:
在这里插入图片描述

05. 实现 instanceOf

首先我们需要分析一下indanceOf的功能和作用,它有什么功能和作用呢?它可以检测一个方法的原型 prototype 是否挂载到了另外一个对象的原型链上了,所以返回值就是 true 或者 false ;理解清楚它的作用之后呢,我们就来实现一下:

const instance_of = (obj, fn) => {
	let fn_prototype = fn.prototype; // 获取 fn 的原型 prototype
	let obj_proto = obj.__proto__; // 获取 obj 的第一级原型链 __proto__

	while(true){
		// 如果为null 说明找到顶 返回 fasle
		if(obj_proto == null) return false;
		// 如果相等 就说明查找到了 返回 true
		if(obj_proto === fn_prototype) return true;
		
		// 继续往上级原型链查找
		obj_proto = obj_proto.__proto__;
	}

}

// 测试代码片段
function Person(name, age){
	this.name = name,
	this.age = age;
}

let child = new Person('Lee', 18);
let obj = new Object();

console.log(instance_of(child, Person)) // true
console.log(instance_of(child, Object))  // true
console.log(instance_of(child, Array)) // false
console.log(instance_of(obj, Person)) // false
06. 实现一个 call

这里呢,首先我们需要弄明白,call的作用是什么?改变函数内部的this指向,并且执行这个方法;所以呢,我们分三步来模拟:

  1. 首先把这个方法变成这个对象的属性
  2. 然后执行它
  3. 最后再删除它
  4. 这当中呢,需要注意的点有,如果不传入对象, this 指向 window ;如果有参数,需要把参数也得给带进去;函数执行有返回值,需要把返回值给带出去;
Function.prototype._call = function(obj){
	obj = obj || window;
	obj.fn = this; // 1. 首先把这个方法变成这个对象的属性
	let arr = [];
	for(let i=1;i<arguments.length;i++){
		arr.push(arguments[i]);
	}
	let result = obj.fn(...arr);  // 2. 然后执行它
	delete obj.fn;  // 3. 最后再删除它
	return result;
}

// 测试代码片段
function Person(){
	return this.name + ',' +this.age;
}

function Child(){
	this.name = 'Lee';
	this.age = 8;
}

let child = new Child();
let people = Person._call(child)
console.log(people) // Lee, 8

浏览器控制台打印效果:
在这里插入图片描述

07. 实现一个 apply

实现 apply 和实现 call 基本类似,唯一有一点区别就是 call 传递的是参数类型,apply传递的是类数组类型,所以呢,我们需要做一点改变,编辑如下:

Function.prototype._apply = function(obj, arrs){
	obj = obj || window;
	obj.fn = this; // 1. 首先把这个方法变成这个对象的属性
	
	// 判断是否传递数组
	let arr = [];
	if(arrs){	
		for(let i=1;i<arrs.length;i++){
			arr.push(arrs[i]);
		}
	}
	
	let result = obj.fn(...arr);  // 2. 然后执行它
	delete obj.fn;  // 3. 最后再删除它
	return result;
}

function Person(){
	return this.name + ',' +this.age;
}

function Child(){
	this.name = 'Lee';
	this.age = 8;
}

let child = new Child();
let people = Person._apply(child)
console.log(people)  // Lee,8
09. 实现一个 Object.create

首先我们需要明确 Object.create 的作用,它是干什么的呢?它可以创建一个新对象,并且这个新对象有一个特性,什么特性呢?传进去的对象会挂载到新对象的原型链上面,所以我们根据这样一个特性,模拟实现编辑如下:

function create(obj){
    function fn(){ };
    fn.prototype = obj;

    return new fn();
}
10. 模拟实现一个 JSON.parse

玩过前端的都知道 JSON.parse JSON.stringify 的基本作用是什么,那我们怎么模拟实现一个 JSON.parse 的功能呢?我们可以使用 eval 解析字符串的功能来编译我们的字符串,最终解析成对象,编辑如下:

var json = '{"name":"lee", "age":25}';
var obj = eval("(" + json + ")");

这里呢,顺带着把 JSON.stringify 的原理实现给贴过来,方便查阅:

function json2str(o) {
    let arr = [];
    const fmt = function(s) {
        if(typeof s == 'object' && s !== null){
            return json2str(s);
        }
        // undefine symbol function的时候 设置为空, 注意区分 '' 与 `"${s}"`, 后者多了 "", 不是真正的空
        if(s === null) {
            return null
        } else if (s === false) {
            return false
        } else if(/^(undefined|symbol|function)$/.test(typeof s)) {
            return ''
        } else {
            return `"${s}"`
        }
    }
    for (var i in o) {
        // 如果是空 就代表是 undefine symbol function  就不用了,去掉
        if(fmt(o[i]) === null || fmt(o[i]) === false || fmt(o[i])){
            arr.push(`"${i}":${fmt(o[i])}`)
        }
    }
    return `{${arr.join(',')}}`
}
11. 类继承

类继承呢,一直都是比较火热的一个话题,也是前端开发者面试的时候遇到的很频繁的一个问题,但是呢,大多数互联网资料,都声明有好几种实现方法,但都有缺点,有缺点就说明没办法正常类继承嘛,所以,这里整理了下,比较规范完整的类继承,实现的主要方向:(1)完成父级方法内部的 this 拷贝 (2)完成父级方法原型 prototype 的引用,这里使用上面的 Object.create(parent_prototype) 进行原型拷贝 (3)最终我们需要重新设置子方法的 construtor 的指向

Parent.prototype.list = [123,2131,1231,41,90];
Parent.prototype.say = function () {
    console.log("Parent prototype")
};
function Parent () {
    this.name = 'parent';
    this.lists = [1, 2, 3];
}
function Child () {
    Parent.call(this);  // 子类里执行父类构造函数
    this.type = 'child';
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

//以下是测试代码
var c1 = new Child();
var c2 = new Child();

console.log(c1, c2);
console.log(c1 instanceof Child, c1 instanceof Parent);
console.log(c1.constructor);
12. 手写实现一个 Promise

1、首先,我们需要明确 Promise 的具体功能的使用,它是如何使用的?它有哪些特性?我们才好下手去写一个方法模拟它的功能,首先我们需要明白什么事函数式编程,把函数当成参数传递是目前很多第三方库源码比较流行的一种做法;这个 Promise 它可以传递两个方法参数进入函数,第一个是 resolve ,第二个呢 reject ,所以我们需要在函数内部构建两个方法 resolve reject (也可以取其他名字)。

2、当然我们需要定义三个状态 pending resolved rejectd 这是三个状态,为什么呢?因为在 Promise 当中运行机制是 pending => resolved 或者 pending => rejected ,不能是 rejected <=> resolved 这种类型的,所以呢我们需要在修改状态前,判断当前的状态是否是 pending 状态

3、 new Promise( ( resolve, reject) => { resolve() } ) 中调用 resolve 方法的时候,是如何在then方法中的第一个毁掉方法参数中获取呢?这里需要知道一点 then 方法接收两个参数,这两个参数呢都是函数,第一个方法会在 resolved 状态下触发,第二个方法会在 rejected 方法中触发;所以只需要我们初始化 Promise 的时候调用了 resolve() 方法,我们就需要把当前状态修改成 resolved 状态,然后通过 this 获取,在 then 方法中判断,这样呢,我们就可以在 then 中获取状态和值,并且传递给第一个回调方法

  1. 接下来,我们需要来解决这个 异步 的问题,如果我们在 new Promise( ( resolve, reject) => { /* 异步代码 */ } )
    使用了 setTimeout 等异步代码,那我们该如何处理呢?这里呢,我们可以使用这个数组塞入我们的这个方法,在Promise方法内部的 resolve 执行的时候,再来调用这个then的第一个回调方法
~function(){
    
    // 构建一个自己的 Promise 构造函数
    function Promises(exector){
        
        // 存储成功或者失败的值
        let self = this;
        this.value = undefined;
        this.reason = undefined;
        // 追加一个状态
        this.status = 'pending';
        // 存储then成功的回调方法
        this.onSuccessedArr = [];
        // 存储then失败的回调方法
        this.onFailedArr = [];

        
        // 成功执行
        function resolve(v){
            // 判断是否处于 pending 状态 ,不过不是禁止往下执行
            if(self.status === 'pending'){
                self.value = v;
                self.status = 'resolved';
                self.onSuccessedArr.forEach(v => v());
            }
        }

        // 失败执行
        function reject(v){
            // 判断是否处于 pending 状态
            if(self.status === 'pending'){
                self.reason = v;
                self.status = 'rejected';
                self.onFailedArr.forEach(v => v());
            }
        }
        
        // 对异常进行处理
        try{
            exector(resolve, reject);
        }catch(e){
            reject(e)
        }
    }

    // 我们将then方法添加到垢找方法的原型上 参数分别为成功和失败的回调
    Promises.prototype.then = function(onSuccessed, onFailed){
        
        // 获取 this
        let self = this;
        // 设置一个新的 promise 
        let promise_new = null;
        
        // 成功 resolve 
        if(self.status === 'resolved'){
            promise_new = new Promises((resolve, reject) => {
                onSuccessed(self.value);
            })
        }
        
        // 失败 reject 
        if(self.status === 'rejected'){
            promise_new = new Promises((resolve, reject) => {
                onFailed(self.reason);
            })
        }
        
        // 准备阶段 pending
        if(self.status === 'pending'){
            promise_new = new Promises((resolve, reject) => {
                self.onFailedArr.push(() => {
                onFailed(self.reason)
                });
                self.onSuccessedArr.push(() => {
                    onSuccessed(self.value)
                });
            })
        }
        
        return promise_new;
    }
    
    // 测试代码
    let promises = new Promises((resolve, reject) => {
        setTimeout(() => {
            resolve('2s之后我被执行了')
        },2000)

        setTimeout(() => {
            reject('5s之后我报了个错')
        },5000)
    });
   
     
    promises.then(res => {
        console.log(res)
    }, err => {
        console.log(err)
    }).then();
    
    
}();

目前只是实现了一个简版,完整版的,大家可以查阅如下地址:https://www.imooc.com/article/30135

未完待续~~~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js 解析表达式,js的算法案例 的相关文章

随机推荐

  • 论文查重越改越多怎么办【一文读懂】

    大家好 今天来聊聊论文查重越改越多怎么办 希望能给大家提供一点参考 以下是针对论文重复率高的情况 提供一些修改建议和技巧 论文查重越改越多怎么办 在论文写作过程中 我们经常遇到论文查重率过高的问题 小发猫写作 有时候 我们会发现 越是修改论
  • ySql.Data.Types.MySqlConversionException: Unable to convert MySQL date/time value to System.DateTime

    public DateTime Createtime MySql Data Types MySqlConversionException Unable to convert MySQL date time value to System D
  • 5.6K Star,多种开发环境的管理利器,从此告别混乱与冲突!

    今天要给大家推荐一个 GitHub 开源项目 jetpack io devbox 该项目在 GitHub 有超过 4 8k Star 用一句话介绍该项目就是 Instant easy and predictable development
  • C语言,求取数组的序亏:已知一个整数数组,求出个数组中每个元素在整个 数组的排序。

    要求获取整数数组中每个元素的排序 可以使用以下方法 1 定义一个结构体数组 其中每个结构体包含数组元素的值和索引 2 遍历整数数组 将每个元素与其索引一起存储到结构体数组中 3 对结构体数组进行排序 按照元素的值进行升序排序 4 遍历排序后
  • 知网间接引用标注算重复率吗【详细教程】

    大家好 今天来聊聊知网间接引用标注算重复率吗 希望能给大家提供一点参考 以下是针对论文重复率高的情况 提供一些修改建议和技巧 知网间接引用标注算重复率吗 在学术研究和论文写作中 我们经常需要引用他人的研究成果和观点 快码论文 然而 对于间接
  • javascript调用客户端程序,js的调用方式有哪三种

    本篇文章给大家谈谈javascript调用函数的方法有哪些 以及javascript调用客户端程序 希望对各位有所帮助 不要忘了收藏本站喔 web项目中要调第三方客户端 于是归纳整理了js调用客户端exe程序的几种方法 如下 方法一 使用A
  • javascript核心技术开发解密,javascript核心原理解析

    大家好 小编来为大家解答以下问题 javascript的核心组成部分有哪些 javascript的核心语言对象包括 今天让我们一起来看看吧 文章目录 前言 一 什么是 ECMAScript 1 1 ECMAScript 的三种具体表现 1
  • 如何有效进行主数据治理

    在企业信息化建设不断推进 逐渐进行数字化转型的今天 几乎所有的企业都卷入到数据及其处理 数据收集 存储 检索 传输 分析和表示 的浪潮中 数据已成为重要生产要素和无形资产 针对主数据的全生命周期管理迫在眉睫 对企业而言 分散管理的数据由于不
  • pngPackerGUI_V2.0是什么软件?png图片打包plist工具

    png图片打包plist工具 手把手教你使用pngPackerGUI V2 0 此软件是在 pngpacker V1 1 软件基础之后 开发的界面化操作软件 方便不太懂命令行的小白快捷上手使用 1 下载并解压缩软件 得到如下目录 双击打开
  • 【源码篇】基于SpringBoot+thymeleaf实现的蓝天幼儿园管理系统

    基于SpringBoot thymeleaf实现的蓝天幼儿园管理系统 文章目录 系统说明 技术选型 成果展示 账号地址及其他说明 系统说明 基于SpringBoot thymeleaf实现的蓝
  • GraphQL 实现原理,不要被表象骗了

    GraphQL 实现原理 及实例 GraphQL是一种用于API的查询语言和运行时环境 它提供了一种描述数据的方式 客户端可以根据需要进行精确地获取所需的数据 下面是GraphQL的实现原理 类型系统 Type System GraphQL
  • 检测下我的饺子皮擀的怎么样(圆度)

    各位老铁周末愉快 快乐的时间做充实的事 好久没有吃饺子了 俗话说好吃不过饺子 我个人觉得会包饺子不算本事 会擀饺子皮那才叫 今天我就来 手撕 一下饺子皮 和面 和面这一步 看似简单 实则不难 不过还是要掌握一些小技巧 小技巧一 和面的水里面
  • openCV在Visual Studio2019下的集成使用

    文章目录 下载OpenCV工具 选择合适库文件 使用visual studio创建空项目 测试运行 运行结果 下载OpenCV工具 官网下载实在太慢 还老实下不下来 下面从网上找到些别人分享的一些版本 从3 4到4 7 放到了网盘里 请按需
  • EasyV不止可视化|易知微带你打开可视化工具新大门!

    可视化工具的发展已经成为当今信息技术领域中的一股不可忽视的力量 如今 人们有了更多的数据和信息需要处理 因此需要一种更加高效 更加直观的手段来呈现这些信息 而可视化工具应运而生 这些工具包括多种类型的图表 地图 仪表板等 随着技术不断革新和
  • 博士论文答辩通过但需改论文【保姆教程】

    大家好 今天来聊聊博士论文答辩通过但需改论文 希望能给大家提供一点参考 以下是针对论文重复率高的情况 提供一些修改建议和技巧 博士论文答辩通过但需改论文 背景介绍 博士论文答辩是博士研究生学术生涯的重要环节 也是对其研究能力和学术水平的全面
  • zephir 实现PHP封装成C语言扩展文件so实现demo简单案例【菜鸟级教程】

    从github 安装 zephir phar 最新网址 https github com zephir lang zephir releases 将文件改名 zephir phar 改名为 zephir 放到 bin 目录下 查看是否安装
  • ERP软件定制开发对企业的优势|app小程序搭建

    ERP软件定制开发对企业的优势 app小程序搭建 随着科技的不断发展 企业管理也面临了更多的挑战 为了更好地适应市场需求和提高运营效率 越来越多的企业开始选择使用ERP软件进行管理 然而 市场上现成的ERP软件并不能完全满足企业的需求 因此
  • 2024年甘肃省职业院校技能大赛(中职教师组)网络安全竞赛样题卷③

    2024年甘肃省职业院校技能大赛 中职教师组 网络安全竞赛样题卷 2024年甘肃省职业院校技能大赛 中职教师组 网络安全竞赛样题卷 A模块基础设施设置 安全加固 200分 A 1任务一 登录安全加固 Windows Linux A 2任务二
  • 部门新来的00后太猛了,老油条表示真干不过...

    在程序员职场上 什么样的人最让人反感呢 是技术不好的人吗 并不是 技术不好的同事 我们可以帮他 是技术太强的人吗 也不是 技术很强的同事 可遇不可求 向他学习还来不及呢 真正让人反感的 是技术平平 却急于表现自己的人 每天加班到12点 在老
  • js 解析表达式,js的算法案例

    大家好 给大家分享一下js 解析表达式 很多人还不知道这一点 下面详细解释一下 现在让我们来看看 01 模拟实现 new 首先 这里呢 先简单说明一下 new 关键字的基本作用 有以下三点 创建一个新的对象 把Person方法的原型 pro