前言

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强大的灵活性, 也带来更多的可能性。 路漫漫其修远兮,吾将上下而求索。

代码地址

您可能感兴趣的文章:

文章同步发布: https://www.geek-share.com/detail/2771904322.html

了解Javascript中函数作为对象的魅力的更多相关文章

  1. 转:JavaScript中函数与对象的关系

    来自:http://www.nowamagic.net/javascript/js_RelationOfFunctionAndObject.php 在ajax兴起以前,很多人写JavaScript可以 ...

  2. JavaScript中的事件对象

    JavaScript中的事件对象 JavaScript中的事件对象是非常重要的,恐怕是我们在项目中使用的最多的了.在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含这所有与事件有 ...

  3. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  4. Javascript学习1 - Javascript中的类型对象

    原文:Javascript学习1 - Javascript中的类型对象 1.1关于Numbers对象. 常用的方法:number.toString() 不用具体介绍,把数字转换为字符串,相应的还有一个 ...

  5. 详解javascript中的this对象

    详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...

  6. JavaScript中函数是不能重载原因

    以前有一次写JS插件的时候,由于后台写习惯了,妄想在JS中写重载函数,可惜不能成功,原因花了一点时间记了下来 首先要理解重载的含义:函数返回值不同或者形式参数个数不同但函数名相同的函数 JavasSc ...

  7. javascript中如何获取对象名

    javascript中如何获取对象名 一.总结 一句话总结:将对象传入参数,看参数是否为函数(js中的对象和函数是一个意思么(函数肯定是对象)),对象参数.name属性即可获得 //版本4 funct ...

  8. JavaScript中的global对象,window对象以及document对象的区别和联系

    JavaScript中的global对象,window对象以及document对象的区别和联系 一.概念区分:JavaScript中的global对象,window对象以及document对象 1.g ...

  9. 改变JavaScript中函数的内部this指向!

    改变JavaScript中函数的内部this指向! 第一种方法 call call 可以 调用函数 + 改变函数内的this指向! var obj = { name: 'lvhang' } funct ...

随机推荐

  1. STM32的三种启动方式

  2. Centos7 vsftpd虚拟用户权限控制(vsftpd虚拟用户限制IP访问)

    实验目标:(新增限制虚拟机用户登陆的IP) 实现在同一跟目录下对admin,upload,download三个虚拟用户的不同权限的控制.具体权限控制列表如下: 用户名 权限说明 admin 管理员,可 ...

  3. 使用Selenium从IEEE与谷歌学术批量爬取BibTex文献引用

    搞科研的小伙伴总是会被期刊严苛的引用文献格式搞的很头疼.虽然常用的文献软件可以一键导出BibTex,但由于很多论文在投稿之前都会先发上Arxiv占坑,软件就很可能会把文献引出为来自Arxiv.我用的是 ...

  4. 004:ZYNQ_AXI总线学习笔记(1)

    1.    WHAT IS AXI? AXI是一种高级可扩展接口,是ARM AMBA的一部分. 2.    WHAT IS AMBA? AMBA是高级微控制器总线架构,开放的片内互联总线标准. 3.A ...

  5. 第三方跨平台进程和系统监控库gopsutil

    gopsutil psutil是一个跨平台进程和系统监控的Python库,而gopsutil是其Go语言版本的实现.本文介绍了它的基本使用. Go语言部署简单.性能好的特点非常适合做一些诸如采集系统信 ...

  6. 基于TensorRT优化的Machine Translation

    基于TensorRT优化的Machine Translation 机器翻译系统用于将文本从一种语言翻译成另一种语言.递归神经网络(RNN)是机器翻译中最流行的深度学习解决方案之一. TensorRT机 ...

  7. 不是都需要ARM吗?

    不是都需要ARM吗? ARM系统架构简介 什么是ARM处理器,为什么没有听说? ARM-缩写:Advanced RISC Machines 该处理器起源于1984年的英格兰.在成立之初,ARM代表Ac ...

  8. wrk(2)- Lua 脚本的使用

    背景 要用 wrk 进行压测 看了下其他同事的压测,都用了 Lua 脚本来自定义一些东西 所以这一篇主要讲 Lua 脚本 Lua 介绍 Lua 脚本是一种轻量小巧的脚本语言,用标准 c 语言编写,并以 ...

  9. centos7 安装 bbr加速

    脚本安装 1 查看内核版本 # [root@os]# uname -a Linux os 3.10.0-1127.13.1.el7.x86_64 x86_64 x86_64 x86_64 GNU/Li ...

  10. VNC 相关

    vncserver启动报错root A VNC server is already running as :1 [root@42 ~]# service vncserver startStarting ...