导出TXT文件

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>exportTxt</title></head><body><button onclick="exportTxt('文件','内容')">click</button><script>function exportTxt(name, data) {// MouseEvent对象记录着鼠标触发事件时的所有属性let ev = new MouseEvent("click");// Blob为js的一个不可变的、原始数据的类似文件对象let export_blob = new Blob([data]);// 创建带有指定命名空间的元素节点let save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a")let urlObject = window.URL || window.webkitURL || window;// 根据传入的参数创建一个指向该参数对象的URLsave_link.href = urlObject.createObjectURL(export_blob);save_link.download = name;save_link.dispatchEvent(ev);}</script></body>
</html>

call

// 核心思路:在不改变原有对象的前提下
// 利用this动态地增删window对象下的属性/方法
Function.prototype.myCall = function(obj, ...arg) {// 1. 判断有无传入参数// 没有则默认指向window对象obj = obj ? Object(obj) : window;// 2. 给形参对象obj新增属性指向window对象obj.unique = this;// 3. 接收剩余参数const res = obj.unique(...arg);// 4. 删除这个新增的属性delete obj.unique;return res;
}let a = 1;
const obj = {a: 2
}function fn1(b, c) {console.log(this.a, b, c)
}fn1.call(obj, 3, 4); // 2, 3, 4
fn1.myCall(obj, 3, 4); // 2, 3, 4

apply

// 核心思路:利用this动态地增删window对象下的属性/方法
Function.prototype.myApply = function(obj, arg = []) {// 1. 判断有无传入参数// 没有则默认指向window对象obj = obj ? Object(obj) : window;// 2. 给形参对象obj新增属性指向window对象obj.unique = this;// 3. 接收剩余参数const res = obj.unique(...arg);// 4. 删除这个新增的属性delete obj.unique;return res;
}let a = 1;
const obj = {a: 2
}function fn1(b, c) {console.log(this.a, b, c)
}fn1.apply(obj, [3, 4]); // 2, 3, 4
fn1.myApply(obj, [3, 4]); // 2, 3, 4

bind

// 核心思路:通过改变this指向多次传递单一参数
Function.prototype.myBind = function(obj, ...arg1) {const fn = this;return function(...arg2) {return fn.call(obj, ...arg1.concat(arg2));}
}let a = 1;
const obj = {a: 2,
}function fn1(...arg) {console.log(this.a, ...arg)
}
fn1.bind(obj, 3, 4)(5, 6); // 2, 3, 4, 5, 6
fn1.myBind(obj, 3, 4)(5, 6); // 2, 3, 4, 5, 6

生成指定范围的随机数

  1. 借助Math.random()返回0-1范围的随机数
  2. 乘以倍数(需要加一)
  3. 补充最低值
function randomNum(min, max) {return Math.floor(Math.random() * (max - min + 1)) + min;
}

数组扁平化

手写JS之数组扁平化
也叫数组展开,是将多维数组转化成一维数组

数组扁平化的基本思路:逐个判断子项是否为数组

有3种方法

第一种方法:使用数组和字符串的转换

  1. 数组转换成字符串
  2. 借助map方法将字符串拼接成数组

第二种方法:使用递归

  1. 借助map方法
  2. 进行递归
  3. 拼接子项

第三种方法:使用while和some

  1. 使用while循环
  2. 借助some方法
  3. 拼接子项
// 数组扁平化,也叫数组展开,将多维数组转化成一维数组
// 基本思路:逐个判断子项是否为数组// 有3种方法// 第一种方法:使用数组和字符串的转换
Array.prototype.flat = function(arr) {// 1. 数组转换成字符串return arr.join(',').split(',').map(item => {// 2. 借助map方法将字符串拼接成数组return parseInt(item);})
}// 第二种方法:使用递归
Array.prototype.flat = function() {// 1. 借助map方法const res = this.map(item => {if (Array.isArray(item)) {// 2. 进行递归return item.flat();}return [item];})// 3. 拼接子项return [].concat(...res);
}// 第三种方法:使用while和some
Array.prototype.flat = function() {let res = this;// 1. 使用while循环// 2. 借助some方法while (res.some(item => Array.isArray(item))) {// 3. 拼接子项res = [].concat(...res);}return res;
}

new的过程

  1. 内存中创建新对象

  2. 让新对象的隐式原型指向构造函数的显式原型

  3. this指针指向新对象
    执行构造函数的方法,给新对象添加属性、方法

  4. 返回新对象

function newProcess(fn, ...args) {// 1. 内存中创建新对象const newObj = {};// 2. 让新对象的隐式原型指向构造函数的显式原型    newObj.__proto__ = fn.prototype;// 3. this指针指向新对象// 执行构造函数的方法,给新对象添加属性、方法fn.apply(newObj, ...args);// 4. 返回新对象return newObj;
}

深拷贝

关键在于遍历+递归

  1. 判断是否为对象

  2. 判断是否为数组

  3. 遍历对象

  4. 避免拷贝原型的属性、方法

  5. 进行递归,直至拷贝到最深层的属性、方法

  6. 返回深拷贝的结果

// 深拷贝的关键:遍历+递归
function deepClone(obj = {}) {// 1. 判断是否为对象if (typeof obj !== 'object' || obj == null) return obj;// 2. 判断是否为数组let newObj;if (obj instanceof Array) {newObj = [];} else {newObj = {};}// 3. 遍历对象for (let key in obj) {// 4. 避免拷贝原型的属性、方法if (obj.hasOwnProperty(key)) {// 5. 进行递归,直至拷贝到最深层的属性、方法newObj[key] = deepClone(obj[key]);}}// 6. 返回深拷贝的结果return newObj;
}

JSON.parse

// 第一种方法:直接调用eval()
function jsonParse(data) {return eval('(' + data + ')')
}// 第二种方法:使用Function
const newData = (new Function('return ' + data))()

节流

节流的关键点有两个,一个是节流开关阀,另一个是延时时间

基本思路是:
一,每次执行函数前都需要判断节流阀的开关状态

二,如果节流阀关闭,则直接退出

三,如果节流阀打开,则把节流阀关闭

四,在延时时间过后执行对应的回调函数,再把节流阀打开

// 节流的关键:1. 节流开关阀 2. 延时时间function throttle(callback, delayTime) {let state = true; // 节流阀打开// 每次执行该函数都需要判断开关阀状态return function() {// 如果节流阀关闭,则直接退出该函数// (永远不会执行callback)if (!state) {return;}// 如果节流阀打开,则先把节流阀关闭// 然后在设置的时间间隔(delayTime)后自动打开state = false;setTimeout(() => {callback && callback();state = true;}, delayTime)}}

防抖

防抖的关键在于对定时器的开始和清零

  1. 定义一个定时器

  2. 每次调用都需要判断定时器是否为空

  3. 定时器不为空,则需要重新计时

  4. 定时器为空,则开始倒计时

// 防抖的关键:对定时器的开始和清零
function debounce(callback, delayTime) {// 定义一个定时器let timer = null;return function() {// 如果定时器不是空,则需要重新计时if (timer != null) {clearTimeout(timer);}// 如果定时器还是空,则开始倒计时timer = setTimeout(() => {callback && callback();}, delayTime)}
}

柯里化

思路是:使用数组存储每次接收的参数,并且返回新函数处理剩下的参数,直到最后才调用

  1. 定义函数的参数列表

  2. 判断是否为最后一个参数组

  3. 如果不是,则递归调用function

  4. 如果是,则把接收的参数拼接成数组

// 关键:使用数组存储每次接收的参数,并且返回新函数处理剩下的参数,直到最后才调用
function currying(fn, ...args) {// 定义函数的参数列表let len = fn.length;// 判断是否为最后一个参数组// 如果不是,则递归调用fn()if (args.length >= len) {return fn(...args)}// 如果是,则把接收的参数拼接成数组return function() {let _args = args.concat([...arguments])return currying.call(this, fn, ..._args)}
}

正则表达式

// 匹配手机号:// 1. 所有号码都是以1开头
/^1/// 2. 第2位数都是3、4、5、7、8之一
/^1[34578]/// 3. 剩下的9位数可以取任意数字
/^1[34578]\d{9}$/// 4. 使用全局搜索
/^1[34578]\d{9}$/g// 匹配16进制颜色:// 1. 以#号开头(考虑用户体验也可以省略)
/#?/g// 2. 第一种情况:两两缩写,如#000,#fff
/#?[0-9a-fA-f]{3}/g// 3. 第二种情况:如:#010203
/#?[0-9a-fA-f]{3}|[0-9a-fA-F]{6}/g// 匹配身份证// 1. 首数字不能为0
/^[1-9]/g// 2. 第2-6位为任意数字
/^[1-9][0-9]{5}/g// 3. 第7-10位为出生年份,如19xx,20xx
/^[1-9][0-9]{5}(19|20)[0-9]{2}/g// 4. 第11-12位为出生月份
/^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])/g// 5. 第13-14位为出生天
/^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])/g// 6. 最后4位为随机数
/^[1-9][0-9]{5}(19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$/g

手写Promise

function Promise(executor) {// 初始化state为等待态 this.state = 'pending';// 成功的值 this.value = undefined;// 失败的原因 this.reason = undefined;// 存放 fn1 的回调 this.fn1Callbacks = [];// 存放 fn2 的回调 this.fn2Callbacks = [];// 成功 let resolve = () => {};// 失败 let reject = () => {};// 立即执行 executor(resolve, reject);
}

手写JavaScript相关推荐

  1. 手写JavaScript常见5种设计模式

    想分享的几种设计模式 目前模式:工厂模式,单例模式,适配器模式,装饰者模式,建造者模式 建造者模式 简介:建造者模式(builder pattern)比较简单,它属于创建型模式的一种. 白话:4个部分 ...

  2. JavaScript 自定义对象 及 new()原理与实现 如何完整地手写实现new

    JavaScript 自定义对象 及 new() 原理与实现 作者: 李俊才 邮箱 :291148484@163.com CSDN 主页:https://blog.csdn.net/qq_285502 ...

  3. JavaScript基础小节——手写重点整理02

    接上一篇博客<JavaScript基础小节--手写重点整理01>:点这里  继续手写整理了一些我认为容易混淆的一些知识点 如图所示:

  4. HTML5期末大作业:商城网站设计——仿唯品会购物商城(5页) 纯手写-高质量 HTML+CSS+JavaScript

    HTML5期末大作业:商城购物网站设计--仿唯品会商城(5页) 纯手写 HTML+CSS+JavaScript 期末作业HTML代码 学生网页课程设计期末作业下载 web网页设计制作成品 常见网页设计 ...

  5. JavaScript手写(持续更新)

    类型判断 主要是利用 Object.prototype.toString.call() ,其中toString方法返回反映这个对象的字符串. 如果此方法在自定义对象中未被覆盖,toString() 返 ...

  6. 史上最全!56个JavaScript的「手写」知识点,扫盲啦!

    关注公众号 前端开发博客,领27本电子书 回复加群,自助秒进前端群 今天就带着大家来复习一下JavaScript的56个「手写」知识点哦~~~ 大厂手写题 1.实现原生 AJAX 封装 const a ...

  7. 【bind()函数】JavaScript手写bind()及详解-超详细~~~

    这两天学习了手写call.apply.bind,手写bind思考了很久才实现了MDN的示例的结果,所以记录下来~ 因为是第一篇文章,所以可能存在一些错误,希望各位大佬批评指正,不吝赐教. 也欢迎不懂的 ...

  8. JavaScript进阶必会的手写功能

    JavaScript进阶的必要性 无论是学习react还是vue,它们都是js的应用框架.剥去他们的壳子看到的始终是js,所以作为一个前端大厨必须要熟练掌握好js这个大勺,才能烧出一顿好菜 无论是自我 ...

  9. JavaScript进阶必会的手写功能(二)

    JavaScript进阶必会的手写功能(一) 6. 手写浅拷贝 6.1 JavaScript数据类型分类 1. 简单数据类型: Number. String.Boolean.null.undefine ...

最新文章

  1. 机器学习基础(一)——人工神经网络与简单的感知器
  2. 浅析日常网站建设中运营与优化的工作重点
  3. 在IIS中写Python的CGI脚本
  4. 自定义UserControl的属性为什么不能在设计时显示在属性窗口中
  5. U盘病毒及其相关资源的分析(patch shell32.dll)
  6. 直方图均衡化计算过程步骤
  7. Flutter功能 组件描边,圆角
  8. 【雕爷学编程】Arduino动手做(3)---微波雷达感应开关模块
  9. HDR(高动态范围)
  10. 分享一个商品历史价格查询的网站
  11. 如何用软件测试交易系统的胜率,通达信官网程序交易测试
  12. 华硕主板关闭Secure Boot步骤 :(支持b460/b560/b660主板)
  13. 电商用户价值分析——基于RFM模型、KMeans聚类
  14. cid unmatched [object Object] at view.umd.min.js:1 TypeError: Invalid attempt to destructure non-ite
  15. 16 tia 内容说明 安装包_TIA Portal V16 软件安装包 安装教程 授权
  16. c++头文件iomanip.h中的setw、setprecision、setfill和setbase函数
  17. python2.7安装pyqt5版本,py3
  18. C语言之对char*与char[]的理解
  19. 为什么lol计算机内存不足怎么办,win7玩LOL英雄联盟提示“内存不足”怎么处理?(图文)...
  20. 使用ICSharpCode.SharpZipLib对文件进行压缩或解压

热门文章

  1. (二)编译PVE内核5.10.6-1-pve及安装内核补丁fullconeNat
  2. 工具包-POST请求
  3. idea 解决java文件导入java 文件灰色右下角橙色java图标显示
  4. airflow调度方案
  5. ROS2 发展历程和开发环境安装
  6. 外贸ERP系统的操作有什么特点?中小企业适合选择吗?
  7. Linux Signal (2): signal函数
  8. Mysql数据库表结构导出工具介绍
  9. 6、英飞凌-AURIX-TC3XX: PWM实验之使用 GTM -ATOM 实现
  10. 倒计时1天丨相信边缘的力量!