九个超级好用的 Javascript 技巧

 前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

前言

在实际的开发工作过程中,积累了一些常见又超级好用的 Javascript 技巧和代码片段,包括整理的其他大神的 JS 使用技巧,今天筛选了 9 个,以供大家参考。

1、动态加载 JS 文件

在一些特殊的场景下,特别是一些库和框架的开发中,我们有时会去动态的加载 JS 文件并执行,下面是利用 Promise 进行了简单的封装。

function loadJS(files, done) {// 获取head标签const head = document.getElementsByTagName('head')[0];Promise.all(files.map(file => {return new Promise(resolve => {// 创建script标签并添加到headconst s = document.createElement('script');s.type = "text/javascript";s.async = true;s.src = file;// 监听load事件,如果加载完成则resolves.addEventListener('load', (e) => resolve(), false);head.appendChild(s);});})).then(done);  // 所有均完成,执行用户的回调事件
}loadJS(["test1.js", "test2.js"], () => {// 用户的回调逻辑
});

上面代码核心有两点,一是利用 Promise 处理异步的逻辑,而是利用 script 标签进行 js 的加载并执行。

2、实现模板引擎

下面示例用了极少的代码实现了动态的模板渲染引擎,不仅支持普通的动态变量的替换,还支持包含 for 循环,if 判断等的动态的 JS 语法逻辑,具体实现逻辑在笔者另外一篇文章《面试官问:你能手写一个模版引擎吗?》做了非常详详尽的说明,感兴趣的小伙伴可自行阅读。

// 这是包含了js代码的动态模板
var template =
'My avorite sports:' +
'<%if(this.showSports) {%>' +'<% for(var index in this.sports) {   %>' +'<a><%this.sports[index]%></a>' +'<%}%>' +
'<%} else {%>' +'<p>none</p>' +
'<%}%>';
// 这是我们要拼接的函数字符串
const code = `with(obj) {var r=[];r.push("My avorite sports:");if(this.showSports) {for(var index in this.sports) {r.push("<a>");r.push(this.sports[index]);r.push("</a>");}} else {r.push("<span>none</span>");}return r.join("");
}`
// 动态渲染的数据
const options = {sports: ["swimming", "basketball", "football"],showSports: true
}
// 构建可行的函数并传入参数,改变函数执行时this的指向
result = new Function("obj", code).apply(options, [options]);
console.log(result);

3、利用 reduce 进行数据结构的转换

有时候前端需要对后端传来的数据进行转换,以适配前端的业务逻辑,或者对组件的数据格式进行转换再传给后端进行处理,而 reduce 是一个非常强大的工具。

const arr = [{ classId: "1", name: "张三", age: 16 },{ classId: "1", name: "李四", age: 15 },{ classId: "2", name: "王五", age: 16 },{ classId: "3", name: "赵六", age: 15 },{ classId: "2", name: "孔七", age: 16 }
];groupArrayByKey(arr, "classId");function groupArrayByKey(arr = [], key) {return arr.reduce((t, v) => (!t[v[key]] && (t[v[key]] = []), t[v[key]].push(v), t), {})
}

很多很复杂的逻辑如果用 reduce 去处理,都非常的简洁。

4、添加默认值

有时候一个方法需要用户传入一个参数,通常情况下我们有两种处理方式,如果用户不传,我们通常会给一个默认值,亦或是用户必须要传一个参数,不传直接抛错。

function double() {return value *2
}// 不传的话给一个默认值0
function double(value = 0) {return value * 2
}// 用户必须要传一个参数,不传参数就抛出一个错误const required = () => {throw new Error("This function requires one parameter.")
}
function double(value = required()) {return value * 2
}double(3) // 6
double() // throw Error

5、函数只执行一次

有些情况下我们有一些特殊的场景,某一个函数只允许执行一次,或者绑定的某一个方法只允许执行一次。

export function once (fn) {// 利用闭包判断函数是否执行过let called = falsereturn function () {if (!called) {called = truefn.apply(this, arguments)}}
}

6、实现 Curring

JavaScript 的柯里化是指将接受多个参数的函数转换为一系列只接受一个参数的函数的过程。这样可以更加灵活地使用函数,减少重复代码,并增加代码的可读性。

function curry(fn) {return function curried(...args) {if (args.length >= fn.length) {return fn.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2));};}};
}function add(x, y) {return x + y;
}const curriedAdd = curry(add);console.log(curriedAdd(1)(2)); // 输出 3
console.log(curriedAdd(1, 2)); // 输出 3

通过柯里化,我们可以将一些常见的功能模块化,例如验证、缓存等等。这样可以提高代码的可维护性和可读性,减少出错的机会。

7、实现单例模式

JavaScript 的单例模式是一种常用的设计模式,它可以确保一个类只有一个实例,并提供对该实例的全局访问点,在 JS 中有广泛的应用场景,如购物车,缓存对象,全局的状态管理等等。

let cache;
class A {// ...
}function getInstance() {if (cache) return cache;return cache = new A();
}const x = getInstance();
const y = getInstance();console.log(x === y); // true

8、实现 CommonJs 规范

CommonJS 规范的核心思想是将每个文件都看作一个模块,每个模块都有自己的作用域,其中的变量、函数和对象都是私有的,不能被外部访问。要访问模块中的数据,必须通过导出(exports)和导入(require)的方式。

// id:完整的文件名
const path = require('path');
const fs = require('fs');
function Module(id){// 用来唯一标识模块this.id = id;// 用来导出模块的属性和方法this.exports = {};
}function myRequire(filePath) {// 直接调用Module的静态方法进行文件的加载return Module._load(filePath);
}Module._cache = {};
Module._load = function(filePath) {// 首先通过用户传入的filePath寻址文件的绝对路径// 因为再CommnJS中,模块的唯一标识是文件的绝对路径const realPath = Module._resoleveFilename(filePath);// 缓存优先,如果缓存中存在即直接返回模块的exports属性let cacheModule = Module._cache[realPath];if(cacheModule) return cacheModule.exports;// 如果第一次加载,需要new一个模块,参数是文件的绝对路径let module = new Module(realPath);// 调用模块的load方法去编译模块module.load(realPath);return module.exports;
}// node文件暂不讨论
Module._extensions = {// 对js文件处理".js": handleJS,// 对json文件处理".json": handleJSON
}function handleJSON(module) {// 如果是json文件,直接用fs.readFileSync进行读取,// 然后用JSON.parse进行转化,直接返回即可const json = fs.readFileSync(module.id, 'utf-8')module.exports = JSON.parse(json)
}function handleJS(module) {const js = fs.readFileSync(module.id, 'utf-8')let fn = new Function('exports', 'myRequire', 'module', '__filename', '__dirname', js)let exports = module.exports;// 组装后的函数直接执行即可fn.call(exports, exports, myRequire, module,module.id,path.dirname(module.id))
}Module._resolveFilename = function (filePath) {// 拼接绝对路径,然后去查找,存在即返回let absPath = path.resolve(__dirname, filePath);let exists = fs.existsSync(absPath);if (exists) return absPath;// 如果不存在,依次拼接.js,.json,.node进行尝试let keys = Object.keys(Module._extensions);for (let i = 0; i < keys.length; i++) {let currentPath = absPath + keys[i];if (fs.existsSync(currentPath)) return currentPath;}
};Module.prototype.load = function(realPath) {// 获取文件扩展名,交由相对应的方法进行处理let extname = path.extname(realPath)Module._extensions[extname](this)
}

上面对 CommonJs 规范进行了简单的实现,核心解决了作用域的隔离,并提供了 Myrequire 方法进行方法和属性的加载,对于上面的实现,笔者专门有一篇文章《38 行代码带你实现 规范》进行了详细的说明,感兴趣的小伙伴可自行阅读。

9、递归获取对象属性

如果让我挑选一个用的最广泛的设计模式,我会选观察者模式,如果让我挑一个我所遇到的最多的算法思维,那肯定是递归,递归通过将原始问题分割为结构相同的子问题,然后依次解决这些子问题,组合子问题的结果最终获得原问题的答案。

const user = {info: {name: "张三",address: { home: "Shaanxi", company: "Xian" },},
};// obj是获取属性的对象,path是路径,fallback是默认值
function get(obj, path, fallback) {const parts = path.split(".");const key = parts.shift();if (typeof obj[key] !== "undefined") {return parts.length > 0 ?get(obj[key], parts.join("."), fallback) :obj[key];}// 如果没有找到key返回fallbackreturn fallback;
}console.log(get(user, "info.name")); // 张三
console.log(get(user, "info.address.home")); // Shaanxi
console.log(get(user, "info.address.company")); // Xian
console.log(get(user, "info.address.abc", "fallback")); // fallback

上面挑选了 9 个笔者认为比较有用的 JS 技巧,希望对大家有所帮助。

 前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/611008.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战Transformer的新架构Mamba解析以及Pytorch复现

今天我们来详细研究这篇论文“Mamba:具有选择性状态空间的线性时间序列建模” Mamba一直在人工智能界掀起波澜&#xff0c;被吹捧为Transformer的潜在竞争对手。到底是什么让Mamba在拥挤的序列建中脱颖而出? 在介绍之前先简要回顾一下现有的模型 Transformer:以其注意力机制而…

PM3-PM002-学习笔记

----------本学习笔记说明&#xff0c;在看本文章前请认真看完学习视频相关内容-------------- 说明—>PM002—>表示题号 —>选择后表示—>答案 PM002-01. 选择&#xff1a;质量保证过程PM002-02. 选择&#xff1a;项目经理和项目管理团队PM002-03. 选择&#xff…

一文读懂数字工厂管理系统解决方案

随着科技的飞速发展&#xff0c;数字化转型已成为企业提升竞争力、优化运营管理的必由之路。数字工厂管理系统作为这一转型的核心组成部分&#xff0c;正逐渐受到业界的广泛关注。本文将深入探讨数字工厂管理系统解决方案的核心理念、功能模块、实施步骤及其对企业发展的影响。…

前端基础 keep-alive的使用(Vue)

用法 keep-alive是Vue内置的一个组件&#xff0c;可以使被包含的组件保留状态&#xff0c;避免重新渲染 <keep-alive><component><!-- 该组件将被缓存&#xff01; --></component> </keep-alive> props include - 字符串或正则表达&#xff0…

2024 1.9 Spark_SQL , 数据清洗API , 写出操作

目录 一. DataFrame 详解 1. 数据清洗API 1.去重 : 2. 去除空: 3. 填充替换 : 2. SparkSQL的shuffle分区设置 3 . SparkSQL 数据写出操作 3.1 写出到文件系统 3.2 写出到数据库 一. DataFrame 详解 1. 数据清洗API 1.1 去重 : DropDupilcates : init_df.dropDuplicates().…

Kubernetes 核心实战之三(精华篇 3/3)

文章目录 6、Ingress ★6.1 安装 Ingress6.2 访问6.3 安装不成功的bug解决6.4 测试使用6.4.1 搭建测试环境6.4.2 配置 Ingress的规则6.4.3 测试I6.4.4 测试II6.4.5 路径重写6.4.6 限流 7. Kubernetes 存储抽象7.1 NFS 搭建7.2 原生方式 数据挂载7.3 PV 和 PVC ★7.3.1 创建 PV …

语义解析:连接自然语言与机器智能的桥梁

文章目录 01 语义解析的应用场景场景一&#xff1a;场景二&#xff1a; 02 语义解析和大模型的关系 语义解析技术可以提高人机交互的效率和准确性&#xff0c;在自然语言处理、数据分析、智能客服、智能家居等领域都有广泛的应用前景。特别是在大数据时代&#xff0c;语义解析能…

m401a电视盒子

1.1 刷机教程 魔百盒M401A成功刷入armbian_m401a刷armbian-CSDN博客 https://blog.csdn.net/xiaokai1999/article/details/129623435 江苏版M401A原版 刷机ARMBIAN注意要点 http://www.taodudu.cc/news/show-5341375.html?actiononClick 1.2 查看系统内核 cat /etc/ophub-…

2024年甘肃省职业院校技能大赛 “信息安全管理与评估”赛项样题卷①

2024年甘肃省职业院校技能大赛 高职学生组电子与信息大类信息安全管理与评估赛项样题 第一阶段&#xff1a;第二阶段&#xff1a;模块二 网络安全事件响应、数字取证调查、应用程序安全第二阶段 网络安全事件响应第一部分 网络安全事件响应第二部分 数字取证调查第三部分 应用程…

[Linux进程(一)] 什么是进程?PCB的底层是什么?以及进程标识符pid与ppid

文章目录 1、前言2、描述进程 — PCB(os怎么管理进程呢)3、查看进程3.1 方法一3.2 方法二 4、系统调用获取进程标示符(PID)4.1 获取进程的ID4.2 获取进程的父进程ID 5、系统调用创建子进程-fork 1、前言 大家经常都在讲进程&#xff0c;而它到底是什么呢&#xff1f; 这里给大…

Android逆向学习(六)绕过app签名校验,通过frida,io重定向(上)

Android逆向学习&#xff08;六&#xff09;绕过app签名校验&#xff0c;通过frida&#xff0c;io重定向&#xff08;上&#xff09; 一、写在前面 这是吾爱破解正己大大教程的第五个作业&#xff0c;然后我的系统还是ubuntu&#xff0c;建议先看一下上一个博客&#xff0c;关…

linux: netstat 与 ss 用法详解

文章目录 netstat描述语法参数例子 ss描述语法参数例子 总结 netstat 描述 内核中访问网络连接状态及其相关信息的程序&#xff0c;它能提供 TCP 连接&#xff0c;TCP 和 UDP 监听&#xff0c;进程内存管理的相关报告 语法 netstat [选项] usage: netstat [-vWeenNcCF] [&l…

聊聊 Java 集合框架中的Arrays

Arrays 和 Collections是分别操作数组和集合的两个工具类。今天就来对 Arrays 中的内容作个总结。 一、Arrays 类概述 Arrays 类位于 java.util包中。Arrays 继承 Object java.lang.Object↳ java.util.ArraysArrays 类中的静态方法可以对数组进行排序、查询、搜索等等操作。…

Zookeeper设计理念与源码剖析

Zookeeper 架构理解 整体架构 Follower server 可以直接处理读请求&#xff0c;但不能直接处理写请求。写请求只能转发给 leader server 进行处理。最终所有的写请求在 leader server 端串行执行。&#xff08;因为分布式环境下永远无法精确地确认不同服务器不同事件发生的先后…

easyExcel 获取多个sheet中复杂表头的数据

easyExcel 获取多个sheet中复杂表头的数据 easyExcel 解释 EasyExcel是一个强大且易于使用的Java库&#xff0c;用于简化Excel文件的读写操作。它是阿里巴巴开源的一个基于POI实现的Excel处理工具&#xff0c;并提供了一组简单的API来处理Excel文件&#xff0c;包括读取、写入…

逐步分解,一文教会你如何用 jenkins+docker 实现主从模式

jenkins 主从模式想必大家都不陌生&#xff0c;大家在学习过程中为了学习方便都在自己本地搭建了 jenkins 环境&#xff0c;然后通过 javaweb 方式实现&#xff0c;对于 docker 下实现主从模式大家好像兴趣挺大。 今天就通过这篇文章给大家讲讲怎么玩&#xff0c;希望对大家有帮…

Vivado开发FPGA使用流程、教程 verilog(建立工程、编译文件到最终烧录的全流程)

目录 一、概述 二、工程创建 三、添加设计文件并编译 四、线上仿真 五、布局布线 六、生成比特流文件 七、烧录 一、概述 vivado开发FPGA流程分为创建工程、添加设计文件、编译、线上仿真、布局布线&#xff08;添加约束文件&#xff09;、生成比特流文件、烧录等步骤&a…

交叉编译ARM64架构electron详解

基本介绍 本文主要参考Electron官方文档中 构建说明 和 构建步骤(Linux) 在amd64环境内构建arm64的electron包。 如果是arm64环境请查看文章arm64架构编译electron长征路 一、环境说明 操作系统版本:统信1060 操作系统架构:amd64 内存:32G 如下图: electron版本:v25…

企业微信forMAC,如何左右翻动预览图片

1、control commandshifd 进入企业微信的debug调试模式 2、按照如下步骤选择 3、重启企业微信

全球再生环保趋势的热门项目GRS认证

GRS&#xff0c;最初由世优认证&#xff08;CU&#xff09;于2008年制定&#xff0c;并于2011年1月1日将所有权转让给了纺织品交易所TE。 自2017年7月1日GRS4.0版本开始生效。是为在纺织工业的需求所制定&#xff0c;核查回收产品或某些特定产品。更重要的是让零售商和消费者了…