了解Javascript中函数作为对象的魅力


Posted in Javascript onJune 19, 2019

前言

Javascript赋予了函数非常多的特性,其中最重要的特性之一就是将函数作为第一型的对象。那就意味着在javascript中函数可以有属性,可以有方法, 可以享有所有对象所拥有的特性。并且最重要的,她还可以直接被调用

我们简单的试验一下就可以发现

// 简单实验 函数作为对象的存在
let fn = function () {}
fn.prop = 'fnProp'
console.log(fn.prop) // fnProp

为函数添加属性的这个特性我觉的大家在平时的开发中基本没什么尝试或者是使用过,但是在一些JS库或者是事件回掉管理中都能发挥出很大的用处。下面一起来看几个例子。

函数缓存

在某有一些的情况下我们可以要存储一组相关但是相互又独立的函数。这个需求看起来很easy,实现起来也不复杂。最显而易见的做法是使用一个数组来保存所有的函数,
这样不是不可以,但是显然这种做法不是最好的。下面通过为函数属性我们呢来实现这个我们的目的

// 1:函数缓存示例
let store = {
nextId: 1, // id
cache: {}, // 缓存
add (fn) {
// 如果函数中没有id属性那么就缓存
if (!fn.id) {
console.log(`begin add func ${fn.name}`)
fn.id = store.nextId ++
// 设置完缓存之后返回true
return !!(store.cache[fn.id] = fn)
} else {
console.log(`${fn.name} is already in cache`)
}
}
}
function storeCache() {}
store.add(storeCache) // begin add func storeCache
store.add(storeCache) // storeCache is already in cache

上面的这一段代码逻辑清晰,store对象用来管理我们的缓存,cache属性用来存储函数,nextId属性用来保存当前的缓存Id,add()方法用来设置存储,先来判断当前函数是否已经在缓存中然后再去设置缓存,这样就能限制函数的重复添加,最后返回true。

!!构造是一种可以将任意Javascript表达式转化为其等效布尔值的简单方式。

缓存记忆函数

这种函数可以记住之前已经计算过的结果,避免了不必要的计算,这显然是能够提升代码性能的。

在举例之前我们先来看看这种方式的优缺点

优点

  • 缓存了之前的结果,最终用户享有性能优势
  • 实际上是发生在幕后,操作无感

缺点

  • 内存的牺牲这是肯定的
  • 打破了存粹性(一个函数或者方法应该只做好一件事)
  • 如果方法中有算法,那么很难测量这个算法的性能

了解了优缺点我们来看一个简单的计算素数的例子(不是很严谨)

// 2: 缓存记忆函数
function isPrime (value) {
if (!isPrime.anwers) isPrime.anwers = {}
// 先从缓存里面取
if (isPrime.anwers[value] != null ) {
return isPrime.anwers[value]
}
// 开始进行判断和计算
let prime = value != 1
for (let index = 2; index < value; index++) {
if (value % index == 0) {
prime = false
break;
} 
}
// 保存计算出来的值
return isPrime.anwers[value] = prime
}
console.log(isPrime(5))
console.log(`从函数记忆中直接读取${isPrime.anwers[5]}`)

这里呢 好处是特别明显的我们再次的取用isPrime.anwers[5]的时候不需要经过任何的计算,但是大型的计算要主要内存的使用

缓存记忆DOM元素

通过元素的标签查询DOM的操作的的代价是昂贵的,各位前端大佬肯定都很清楚。我们下面使用缓存记忆的方式来进行这个操作

// 3:缓存记忆DOM元素
function getElements (name) {
if (!getElements.cache) getElements.cache = {}
return getElements.cache[name] = getElements.cache[name] || document.getElementsByTagName(name);
}
console.log(getElements('div')) // HTMLCollection
console.log(getElements.cache['div']) // HTMLCollection

这个函数和上面的缓存使用的同一个手法,而且这简单的4句代码能为我们的性能带来大幅度的提升。这也算是一种超能力吧。函数的很多特性都和其上下文有关,接下来我们研究一个和上下文又换的例子。

伪造数组方法(上下文相关)

在一些情况下我们想创建一个包含一组数据的对象,但是这个数据包含很多的状态,比如和集合项有关的元数据那么我们用数组来存就不太合适了。那么这里我们就用对象的方式来假扮数组。通过改变上下文来完成一些“不法的行为”

// 4:伪造数组方法
// <input type="button" id="add" >
// <input type="button" id="remove" >
let elems = {
length: 0, //为了保存个数
add (elem) {
Array.prototype.push.call(this, elem)
},
gather (id) {
this.add(document.getElementById(id))
}
}
elems.gather('add')
elems.gather('remove')
console.log(elems[0]); // <input type="button" id="add" >
console.log(elems[1]); // <input type="button" id="remove" >
console.log(elems.length); // 2
console.log(elems);
/**
0: input#add
1: input#remove
add: ƒ add(elem)
gather: ƒ gather(id)
length: 2
*/

在我还对JS懵懵懂懂的时候看到这样的操作被秀了一脸,简直是刺激了我幼小的心灵。

我们在add函数中实现了把元素添加到了集合中,而且Array又正好提供push方法, 不用白不用。这种操作也是直白的展示了函数上下文的超强特性。

总结

Javascript强大的灵活性, 也带来更多的可能性。 路漫漫其修远兮,吾将上下而求索。

代码地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js日期对象兼容性的处理方法
Jan 28 Javascript
JS取request值以及自动执行使用示例
Feb 24 Javascript
jquery实现先淡出再折叠收起的动画效果
Aug 07 Javascript
avalon js实现仿微博拖动图片排序
Aug 14 Javascript
javascript日期操作详解(脚本之家整理)
Sep 05 Javascript
分享15个大家都熟知的jquery小技巧
Dec 02 Javascript
[原创]JS基于FileSaver.js插件实现文件保存功能示例
Dec 08 Javascript
详解JavaScript时间处理之几个月前或几个月后的指定日期
Dec 21 Javascript
Bootstrap的popover(弹出框)在append后弹不出(失效)
Feb 27 Javascript
利用PM2部署node.js项目的方法教程
May 10 Javascript
利用JS做网页特效_大图轮播(实例讲解)
Aug 09 Javascript
JS实现判断有效的数独算法示例
Feb 25 Javascript
利用vue-i18n实现多语言切换效果的方法
Jun 19 #Javascript
使用JQuery自动完成插件Auto Complete详解
Jun 18 #jQuery
使用异步controller与jQuery实现卷帘式分页
Jun 18 #jQuery
使用jQuery mobile NuGet让你的网站在移动设备上同样精彩
Jun 18 #jQuery
如何使用CSS3和JQuery easing 插件制作绚丽菜单
Jun 18 #jQuery
如何用webpack4.0撸单页/多页脚手架 (jquery, react, vue, typescript)
Jun 18 #jQuery
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 #jQuery
You might like
ADODB结合SMARTY使用~超级强
2006/11/25 PHP
FCKeditor添加自定义按钮
2008/03/27 PHP
PHP性能优化 产生高度优化代码
2011/07/22 PHP
php中unserialize返回false的解决方法
2014/09/22 PHP
PHP面向对象程序设计类的定义与用法简单示例
2016/12/27 PHP
nodejs中exports与module.exports的区别详细介绍
2013/01/14 NodeJs
Javascript自定义排序 node运行 实例
2013/06/05 Javascript
JavaScript中的函数模式详解
2015/02/11 Javascript
javascript实现点击按钮弹出一个可关闭层窗口同时网页背景变灰的方法
2015/05/13 Javascript
jQuery+jsp下拉框联动获取本地数据的方法(附源码)
2015/12/03 Javascript
使用Bootstrap美化按钮实例代码(demo)
2017/02/03 Javascript
使用get方式提交表单在地址栏里面不显示提交信息
2017/02/21 Javascript
微信小程序 setData的使用方法详解
2017/04/20 Javascript
jquery easyui如何实现格式化列
2017/07/30 jQuery
详解Vue打包优化之code spliting
2018/04/09 Javascript
详解操作虚拟dom模拟react视图渲染
2018/07/25 Javascript
bootstrap动态调用select下拉框的实例代码
2018/08/09 Javascript
Vue+Django项目部署详解
2019/05/30 Javascript
es6数组includes()用法实例分析
2020/04/18 Javascript
小程序开发之模态框组件封装
2020/04/23 Javascript
js实现ajax的用户简单登入功能
2020/06/18 Javascript
[01:13:18]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
TensorFlow用expand_dim()来增加维度的方法
2018/07/26 Python
Django数据库连接丢失问题的解决方法
2018/12/29 Python
python 实现在一张图中绘制一个小的子图方法
2019/07/07 Python
Python学习笔记之lambda表达式用法详解
2019/08/08 Python
Django自带的加密算法及加密模块详解
2019/12/03 Python
完美解决keras保存好的model不能成功加载问题
2020/06/11 Python
大学生文员专业个人求职信范文
2014/01/05 职场文书
出纳员岗位职责
2014/03/13 职场文书
婚前财产公证书
2014/04/10 职场文书
管理标语大全
2014/06/24 职场文书
银行主办会计岗位职责
2014/08/13 职场文书
2014年招商引资工作总结
2014/11/22 职场文书
民主评议党员个人总结
2015/02/13 职场文书
vue本地构建热更新卡顿的问题“75 advanced module optimization”完美解决方案
2022/08/05 Vue.js