龙空技术网

前端进阶教程——31个JavaScript技巧总结

半成品牛筋面 284

前言:

当前朋友们对“html技能分享”大致比较注意,兄弟们都需要知道一些“html技能分享”的相关知识。那么小编同时在网摘上汇集了一些关于“html技能分享””的相关内容,希望咱们能喜欢,兄弟们快快来学习一下吧!

过去的几年中,Python已成为机器学习和深度学习的首选编程语言。与机器学习和深度学习相关的大多数书籍和在线课程要么只用Python,要么再带上R语言。Python有着丰富的机器学习和深度学习库、专门优化的实现,具备可伸缩性和大量功能,因而广受欢迎。

但Python并不是编写机器学习应用程序的唯一选择。社区中有越来越多的开发人员正在使用JavaScript来运行机器学习模型。

尽管JavaScript(目前)并不能在机器学习领域替代根基深厚的Python,但掌握JavaScript机器学习技能也是有很多不错的理由的,

1.函数柯里化

函数柯里化的是一个为多参函数实现递归降解的方式。其实现的核心是:

要思考如何缓存每一次传入的参数

传入的参数和目标函数的入参做比较

这里通过闭包的方式缓存参数,实现如下:

使用方式如下:

函数柯里化仅仅只是上面求和的这种运用吗??

这个问题,有必要去一下。其实利用函数柯里化这种思想,我们可以更好的实现函数的封装。

就比如有监听某一事件那么就会有移除该事件的操作,那么就可以利用柯里化的思想去封装代码了。

或者说一个输入A有唯一并且对应的输出B,那么从更大的角度去思想这样的工程项目是更安全,独立的。也便于去维护。

2.关于数组

手写map方法

map()方法根据回调函数映射一个新数组

手写filter方法

filter()方法返回一个数组,返回的每一项是在回调函数中执行结果true。

filter和map的区别:filter是映射出条件为true的item,map是映射每一个item。

手写reduce方法

reduce()方法循环迭代,回调函数的结果都会作为下一次的形参的第一个参数。

手写every方法

every()方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

手写some方法

some()方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。

手写find方法

find()方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined。

拉平数组

将嵌套的数组扁平化,在处理业务数据场景中是频率出现比较高的。那如何实现呢?

利用ES6语法flat(num)方法将数组拉平。

该方法不传参数默认只会拉平一层,如果想拉平多层嵌套的数组,需要传入一个整数,表示要拉平的层级。该返回返回一个新的数组,对原数组没有影响。

利用reduce()方法将数组拉平。

利用reduce进行迭代,核心的思想是递归实现。

模拟栈实现数组拉平

该方法是模拟栈,在性能上相对最优解。

3.图片懒加载&惰性函数

实现图片懒加载其核心的思想就是将img的src属性先使用一张本地占位符,或者为空。然后真实的图片路径再定义一个data-set属性存起来,待达到一定条件的时将data-img的属性值赋给src。

如下是通过scroll滚动事件监听来实现的图片懒加载,当图片都加载完毕移除事件监听,并且将移除html标签。

scroll滚动事件容易造成性能问题。那可以通过IntersectionObserver自动观察img标签是否进入可视区域。

实例化IntersectionObserver实例,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。

当img标签进入可视区域时会执行实例化时的回调,同时给回调传入一个entries参数,保存着实例观察的所有元素的一些状态,比如每个元素的边界信息,当前元素对应的DOM节点,当前元素进入可视区域的比率,每当一个元素进入可视区域,将真正的图片赋值给当前img标签,同时解除对其的观察。

如上是懒加载图片的实现方式。

值得思考的是,懒加载和惰性函数有什么不一样嘛?

我所理解的懒加载顾名思义就是需要了才去加载,懒加载正是惰性的一种,但惰性函数不仅仅是懒加载,它还可以包含另外一种方向。

惰性函数的另一种方向是在重写函数,每一次调用函数的时候无需在做一些条件的判断,判断条件在初始化的时候执行一次就好了,即下次在同样的条件语句不需要再次判断了,比如在事件监听上的兼容。

4.预加载

预加载顾名思义就是提前加载,比如提前加载图片。

当用户需要查看时,可直接从本地缓存中取。预加载的优点在于如果一张图片过大,那么请求加载图片一定会慢,页面会出现空白的现象,用户体验感就变差了,为了提高用户体验,先提前加载图片到本地缓存,当用户一打开页面时就会看到图片。

5.节流&防抖

针对高频的触发的函数,我们一般都会思考通过节流或者防抖去实现性能上的优化。

节流实现原理是通过定时器以和时间差做判断。定时器有延迟的能力,事件一开始不会立即执行,事件结束后还会再执行一次;而时间差事件一开始就立即执行,时间结束之后也会立即停止。

结合两者的特性封装节流函数:

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数。

防抖实现原理是通过定时器,如果在规定时间内再次触发事件会将上次的定时器清除,即不会执行函数并重新设置一个新的定时器,直到超过规定时间自动触发定时器中的函数。

6.实现new关键字 7.实现instanceof

instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。

8.实现call,apply,bind

call

call函数实现的原理是借用方法,关键在于隐式改变this的指向。

apply

apply函数实现的原理和call是相同的,关键在于参数的处理和判断。

实现的关键思路:

bind

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

实现的关键思路:

1、拷贝保存原函数,新函数和原函数原型链接

2、生成新的函数,在新函数里调用原函数

9.封装数据类型函数 10.自记忆函数 11.是否存在循环引用 12.拷贝函数

拷贝数据一直是业务开发中绕不开的技巧,对于深浅拷贝数据之前写过一篇文章来讲述聊聊深拷贝浅拷贝。

通过深度优先思维拷贝数据(DFS)

深度优先是通过纵向的维度去思考问题,在处理过程中也考虑到对象环的问题。

解决对象环的核心思路是先存再拷贝。一开始先通过一个容器用来储存原来的对象再进行拷贝,在每一次拷贝之前去查找容器里是否已存在该对象。这样就切断了原来的对象和拷贝对象的联系。

通过广度优先思维拷贝数据(BFS)

广度优先是通过横向的维度去思考问题,通过创造源队列和拷贝数组队列之间的关系实现拷贝。

之前写过一篇关于Promise的学习分享。

Promsie.all

Promsie.race

14.实现async-await 30.动态属性名称 16.单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现方法一般是先判断实例是否存在,如果存在直接返回,如果不存在就先创建再返回。

17.实现Object.create

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

18.实现ES6的class语法

使用Object.create()方法将子类的实例对象继承与父类的原型对象,通过Object.setPrototypeOf()能够实现从父类中继承静态方法和静态属性。

19.实现一个compose函数

compose函数是用来组合合并函数,最后输出值的思想。在redux源码中用于中间件的处理。

使用while循环实现

使用reduce迭代实现

20.实现异步并行函数

fn是一个返回Promise的函数才可使用下面的函数:

fn不是一个返回Promsie的话那就包一层:

21.实现异步串行函数 22.私有变量的实现

以上是es5实现的私有变量的封装,通过使用WeakMap可以扩展每个实例所对应的私有属性,私有属性在外部无法被访问,而且随this对象的销毁和消失。

这里有个小细节值得一提,请看如下的代码:

如上是挂在到原型上的方法和每个实例独有的方法不同写法。它们有什么区别呢?(ps:可以手动打印)

调用原型上的方法那么私有变量的值是与最近一个实例调用原型方法的值。其上一个实例的值也是随之改变的,那么就出现问题了...

而使用WeakMap可以解决如上的问题:做到将方法挂在到原型,且不同时期同一个实例调用所产生的结果是一致的。

源代码

javascript--,欢迎star

23.ReplaceAll

我们知道string.Replace()函数只会替换第一个项目。

你可以在这个正则表达式的末尾添加/g来替换所有内容。

var example = "potato potato";console.log(example.replace(/pot/, "tom"));// "tomato potato"console.log(example.replace(/pot/g, "tom"));// "tomato tomato"12345复制代码类型:[javascript]
24.提取唯一值

我们可以使用Set对象和Spread运算符,创建一个剔除重复值的新数组。

var entries = [1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 4, 2, 1]var unique_entries = [...new Set(entries)];console.log(unique_entries);// [1, 2, 3, 4, 5, 6, 7, 8]1234复制代码类型:[javascript]
25.将数字转换为字符串

我们只需使用带空引号的串联运算符即可。

var converted_number = 5 + "";console.log(converted_number);// 5console.log(typeof converted_number);// string12345复制代码类型:[javascript]
26.将字符串转换为数字

用+运算符即可。

请注意这里的用法,因为它只适用于“字符串数字”。

the_string = "123";console.log(+the_string);// 123the_string = "hello";console.log(+the_string);// NaN123456复制代码类型:[javascript]
27.随机排列数组中的元素

每天我都在随机排来排去……

var my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9];console.log(my_list.sort(function() {    return Math.random() - 0.5}));// [4, 8, 2, 9, 1, 3, 6, 5, 7]12345复制代码类型:[javascript]
28.展平多维数组

只需使用Spread运算符。

var entries = [1, [2, 5], [6, 7], 9];var flat_entries = [].concat(...entries);// [1, 2, 5, 6, 7, 9]123复制代码类型:[javascript]
29.短路条件

举个例子:

if (available) {    addToCart();}123复制代码类型:[javascript]

只需使用变量和函数就能缩短它:

available && addToCart()1复制代码类型:[javascript]
30.动态属性名称

我一直以为我必须先声明一个对象,然后才能分配一个动态属性。

const dynamic = 'flavour';var item = {    name: 'Coke',    [dynamic]: 'Cherry'}console.log(item);// { name: "Coke", flavour: "Cherry" }1234567复制代码类型:[javascript]
31.使用length调整大小/清空数组

基本上就是覆盖数组的length。

如果我们要调整数组的大小:

var entries = [1, 2, 3, 4, 5, 6, 7];console.log(entries.length);// 7entries.length = 4;console.log(entries.length);// 4console.log(entries);// [1, 2, 3, 4]12345678复制代码类型:[javascript]

如果我们要清空数组:

var entries = [1, 2, 3, 4, 5, 6, 7];console.log(entries.length);// 7entries.length = 0;console.log(entries.length);// 0console.log(entries);// []

ies);// []

);// 0console.log(entries);// []

ies);// []

ies);// []

s);// []

ies);// []

标签: #html技能分享