十个超级好用的Javascript技巧

news2024/11/18 9:47:34

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

动态加载JS文件

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

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

loadJS(["test1.js", "test2.js"], () => {
  // 用户的回调逻辑
});
复制代码

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

实现模板引擎

下面示例用了极少的代码实现了动态的模板渲染引擎,不仅支持普通的动态变量的替换,还支持包含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);

复制代码

利用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去处理,都非常的简洁。

添加默认值

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

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
复制代码

函数只执行一次

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

export function once (fn) {
  // 利用闭包判断函数是否执行过
  let called = false
  return function () {
    if (!called) {
      called = true
      fn.apply(this, arguments)
    }
  }
}
复制代码

实现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

复制代码

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

实现单例模式

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
复制代码

实现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行代码带你实现CommonJS规范

递归获取对象属性

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

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返回fallback
  return 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
复制代码

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

 

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

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

相关文章

自己动手做chatgpt:解析gpt底层模型transformer的输入处理

前面我们完成了一些基本概念&#xff0c;如果你对深度学习的基本原理还不了解&#xff0c;你可以通过这里获得更多信息&#xff0c;由于深度学习的教程汗牛充栋&#xff0c;因此我在这里不会重复&#xff0c;而是集中精力到chatgpt模型原理的分析&#xff0c;实现和实践上。Cha…

初识C语言————3

博主这篇文章浅谈一下自己对函数和数组的理解。之后会详细说明。 文章目录 一、函数 二、数组 1、数组定义 2、数组的下标 3、数组的使用 一、函数 函数可以理解为一个模块的代码&#xff0c;完成一个独立的功能。 #include <stdio.h> int main() {int num1 0;int num…

ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7

编辑&#xff1a;ll ASEMI代理ADM3051CRZ-REEL7原装ADI车规级ADM3051CRZ-REEL7 型号&#xff1a;ADM3051CRZ-REEL7 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;SOIC-8 批号&#xff1a;2023 引脚数量&#xff1a;8 安装类型&#xff1a;表面贴装型 ADM3051CRZ-REEL7汽…

【Python】读取rdata类型数据转为csv excel格式文件, 无需安装r语言基于pyreadr+pandas实现数据分析(保姆级注释)

目录 环境配置取得数据名 datas.keys()取得pandas的DataFrame类型数据一些数据分析例程供入门同学学习转化为csv excel格式所有数据 转化为csv取前面100行数据 快速测试能否转化csv取前面100行数据 快速测试能否转化xlsx 完整例程总结 欢迎关注 『Python』 系列&#xff0c;持续…

简述AutoGPT原理(提示词)

启动时需要设置三个项目&#xff1a;机器人名字、设定给机器人的角色、要完成的目标。 根据你的设定利用ChatGPT进行下一步的抉择&#xff0c;具体的&#xff0c;实际上归功于提示词&#xff1a; 下面这段提示词在干什么呢&#xff1f; 将设定的名字、角色、目标告诉ChatGPT&…

【U8+】用友U8+对账不平案例及方法总结

【问题需求】 在使用用友U8软件过程中&#xff0c;由于软件涉及到多方面的对账。 所以经常会遇到期初或结账时对账不平。 【经验分享】 在众多对账中&#xff0c; 只有当【总账上下级】&#xff08;即&#xff1a;总账与明细账对账&#xff09;不平的时候&#xff0c; 软件才…

春秋云境:CVE-2022-26965(后台RCE)

目录 一、题目 二、 利用cms主题构造木马 一、题目 介绍&#xff1a; Pluck-CMS-Pluck-4.7.16 后台RCE 进入题目&#xff1a; cms页面 点击admin进行登录&#xff1a; 弱口令admin登录&#xff1a; 成功登录进去&#xff1a; 国产化一下&#xff1a; 选项---选择主题 点击…

漏洞分析丨cve20144113

一、漏洞简述 Microsoft Windows下的 win32k.sys是Windows子系统的内核部分&#xff0c;是一个内核模式设备驱动程序&#xff0c;它包含有窗口管理器、后者控制窗口显示和管理屏幕输出等。如果Windows内核模式驱动程序不正确地处理内存中的对象&#xff0c;则存在一个特权提升…

js对象案例练习

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大一在校生&#xff0c;web前端开发专业 &#x1f921; 个人主页&#xff1a;python学不会123 &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习…

SQL Server的日志传送

日志传送和复制 一、前言二、相关术语和定义三、日志传送和复制3.1、在主数据库丢失时从辅助数据库进行复制的要求和过程3.2、使用事务复制进行日志传送3.3、使用合并复制进行日志传送 一、前言 日志传送允许您自动将事务日志备份从主服务器实例上的主数据库发送到单独辅助服务…

思维导图手撕MyBatis源码

文章目录 前置准备通过类加载器读取配置文件流创建sqlSessionFactory建造者模式的使用 打开SqlSession获取Mapper接口对象执行Mapper接口方法 前置准备 既然要读MyBatis的源码&#xff0c;那么我们就要先弄清楚MyBatis的入口在哪。这里我们直接写一个标准的MyBatis使用程序&am…

Node 【Buffer 与 Stream】

文章目录 &#x1f31f;前言&#x1f31f;Buffer&#x1f31f; Buffer结构&#x1f31f; 什么时候用Buffer&#x1f31f; Buffer的转换&#x1f31f; Buffer使用&#x1f31f; 创建Buffer&#x1f31f; 字符串转Buffer&#x1f31f; Buffer转字符串&#x1f31f; 拼接Buffer&am…

微信小程序登录注册页面

// login.js // 获取应用实例 var app getApp() var api require("../../utils/api.js")Page({data: {motto: zhenbei V1.0.0,userInfo: {},hasUserInfo: false,disabled: true,btnstate: default,username: ,password: ,canIUse: wx.canIUse(button.open-type.get…

UE4/5 C++网络服务器编程纪录【零】--准备篇

前言 之前利用业余时间重新复习UE4/5的C开发&#xff0c;闲来无事做了个基于独立服务器的多人在线&#xff08;目前限定客户数量是20人以内&#xff09;DEMO&#xff0c;核心功能在我之前发的B站视频里面有&#xff0c;战斗、动作、交互以及场景演示都有了&#xff0c;有朋友看…

Linux使用:环境变量指南和CPU和GPU利用情况查看

Linux使用&#xff1a;环境变量指南和CPU和GPU利用情况查看 Linux环境变量初始化与对应文件的生效顺序Linux的变量种类设置环境变量直接运行export命令定义变量修改系统环境变量修改用户环境变量修改环境变量配置文件 环境配置文件的区别profile、 bashrc、.bash_profile、 .ba…

函数(有点难,要注重实战)

目录 1. 函数是什么2. C语言中函数的分类2.1 库函数2.1.1 如何学会使用库函数&#xff1f; 2.2 自定义函数 3. 函数的参数3.1 实际参数&#xff08;实参&#xff09;&#xff1a;3.2 形式参数&#xff08;形参&#xff09;&#xff1a; 4. 函数的调用&#xff1a;4.1 传值调用4…

Spark SQL实战(08)-整合Hive

1 整合原理及使用 Apache Spark 是一个快速、可扩展的分布式计算引擎&#xff0c;而 Hive 则是一个数据仓库工具&#xff0c;它提供了数据存储和查询功能。在 Spark 中使用 Hive 可以提高数据处理和查询的效率。 场景 历史原因积累下来的&#xff0c;很多数据原先是采用Hive…

Node内置模块 【url模块与queryString】

文章目录 &#x1f31f;前言&#x1f31f;url 模块&#x1f31f; URL各部分说明&#x1f31f; 将URL字符串转换为对象&#x1f31f; 将对象格式化为URL字符串&#xff1a;url.format(urlObj)&#x1f31f; URL路径处理&#xff1a;url.resolve(from, to) &#x1f31f; querySt…

MySQL-四大类日志

目录 &#x1f341;MySQL日志分为4大类 &#x1f341;错误日志 &#x1f343;修改系统配置 &#x1f341;二进制日志 &#x1f343;查看二进制日志 &#x1f343;删除二进制日志 &#x1f343;暂时停止二进制日志的功能 &#x1f341;事务日志(或称redo日志) &#x1f341;慢查…

SSM整合、环境配置以及详细综合测试(单表查询、多表查询和数据分页、前后端分离、Vue3)

SSM整合、环境配置以及基础综合测试 准备&#xff1a;创建maven项目以及项目框架准备 SSM整合简介 介绍: SSM(SpringSpringMVCMyBatis) 整合&#xff0c;就是三个框架协同开发。Spring整合Mybatis就是将Mybatis核心配置文件当中数据源的配置、事务处理、以及工厂的配置&…