前言
Javascript赋予了函数非常多的特性,其中最重要的特性之一就是将函数作为第一型的对象。那就意味着在html" target="_blank">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中的函数、对象的使用技巧和注意事项,需要的朋友参考一下 JS中的函数声明方式 方式一 function 函数名(){ 函数体 } 方式二 var 函数名=function(){ 函数体 } 方式三 var 函数名=new Function(“函数体”); 执行方式 函数名(); JS中的对象 类似Java中的一些系
我有JavaScript代码,对象如下: 如何将Sizzle选择器引擎作为函数包含在对象中?在Sizzle源代码中,我发现了一个函数Sizzle,但源代码中还有很多函数之外的代码。 包括后我可以打电话:
本文向大家介绍详解JavaScript函数对象,包括了详解JavaScript函数对象的使用技巧和注意事项,需要的朋友参考一下 函数 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。 注释: 形参不需要加上类型; return语句为可选,没有return语句的函数返回undefined; 局部变量与全局变量 在函数内声明:局部变量 在函数外声明:全局变量 向一个新
本文向大家介绍javaScript的函数对象的声明详解,包括了javaScript的函数对象的声明详解的使用技巧和注意事项,需要的朋友参考一下 写作缘由: 平时再用js写函数的时候,一般都是以惯例 function fn () {} 的方式来声明一个函数,在阅读一些优秀插件的时候又不免见到 var fn = function () {} 这种函数的创建,究竟他们用起来有什么区别呢,
作为一个有经验的程序员,不管在喜欢 C# 之前用的是什么语言,都会积累开发更高效代码的经验。有时,能在之前的环境有效的方法在 .NET 环境中会起反作用。当你想手动优化 C# 编译器的算法时就会体会到。你的行为经常会阻止 JIT 编译器更高效的优化。你额外提升性能的工作实际会产生更慢的代码。你最好的让你的代码写的尽可能地清晰。让 JIT 做剩下的工作。最常见的一个例子就是创建一个更长更复杂的函数希
问题内容: 我有一个javascript对象(实际上是通过ajax请求获取数据的): 我已经添加了一些东西: 现在,我要删除状态无效的所有对象(但保持所有顺序相同): 在我看来,所有这些都应该起作用,但是我收到的错误不是函数。我知道为什么它与数组不一样,但是我该怎么办? 问题答案: 适用于数组,而不是对象,因此请使用正确的数据结构。