了解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 相关文章推荐
JavaScript 对象链式操作测试代码
Apr 25 Javascript
通过js动态操作table(新增,删除相关列信息)
May 23 Javascript
jquery next nextAll nextUntil siblings的区别介绍
Oct 05 Javascript
深入浅出ES6之let和const命令
Aug 25 Javascript
ionic在开发ios系统微信时键盘挡住输入框的解决方法(键盘弹出问题)
Sep 06 Javascript
详谈js中window.location.search的用法和作用
Feb 13 Javascript
js转换对象为xml
Feb 17 Javascript
浅谈实现vue2.0响应式的基本思路
Feb 13 Javascript
vue 子组件向父组件传值方法
Feb 26 Javascript
微信小程序用户授权弹窗 拒绝时引导用户重新授权实现
Jul 29 Javascript
js动态添加带圆圈序号列表的实例代码
Feb 18 Javascript
javascript中闭包closure的深入讲解
Mar 03 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
非洲第一个咖啡超凡杯大赛承办国—卢旺达的咖啡怎么样
2021/03/03 咖啡文化
特详细的PHPMYADMIN简明安装教程
2008/08/01 PHP
PHP 变量的定义方法
2010/01/26 PHP
php 运算符与表达式详细介绍
2016/11/30 PHP
解决遍历时Array.indexOf产生的性能问题
2012/07/03 Javascript
javascript预加载图片、css、js的方法示例介绍
2013/10/14 Javascript
JavaScript中伪协议 javascript:使用探讨
2014/07/18 Javascript
Bootstrap每天必学之简单入门
2015/11/19 Javascript
js实现滚动条滚动到某个位置便自动定位某个tr
2021/01/20 Javascript
深入分析javascript中console命令
2016/08/14 Javascript
JS获取checkbox的个数简单实例
2016/08/19 Javascript
JavaScript实现倒计时跳转页面功能【实用】
2016/12/13 Javascript
js和jQuery以及easyui实现对下拉框的指定赋值方法
2018/01/23 jQuery
简单了解JavaScript中的执行上下文和堆栈
2019/06/24 Javascript
在Vue中使用HOC模式的实现
2020/08/23 Javascript
解决vue数据不实时更新的问题(数据更改了,但数据不实时更新)
2020/10/27 Javascript
vue实现验证用户名是否可用
2021/01/20 Vue.js
[03:27]《辉夜杯》线下训练营 导师CU和海涛指点迷津
2015/10/23 DOTA
Mac下Supervisor进程监控管理工具的安装与配置
2014/12/16 Python
python在控制台输出进度条的方法
2015/06/20 Python
简单讲解Python中的字符串与字符串的输入输出
2016/03/13 Python
详解 Python中LEGB和闭包及装饰器
2017/08/03 Python
Python3中关于cookie的创建与保存
2018/10/21 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
2018/12/12 Python
BP神经网络原理及Python实现代码
2018/12/18 Python
python+ffmpeg批量去视频开头的方法
2019/01/09 Python
Python基于OpenCV实现人脸检测并保存
2019/07/23 Python
浅谈pytorch torch.backends.cudnn设置作用
2020/02/20 Python
Django中使用Celery的方法步骤
2020/12/07 Python
Theo + George官方网站:都柏林时尚品牌
2019/04/08 全球购物
爱我中华教学反思
2014/04/28 职场文书
车间统计员岗位职责
2015/04/14 职场文书
Java使用Unsafe类的示例详解
2021/09/25 Java/Android
Java 关于String字符串原理上的问题
2022/04/07 Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
2022/04/13 Java/Android
MySQL普通表如何转换成分区表
2022/05/30 MySQL