深入理解javascript函数进阶系列第四篇——惰性函数
前面的话
惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。本文将详细介绍惰性函数
使用背景
因为各浏览器之间的行为的差异,经常会在函数中包含了大量的if语句,以检查浏览器特性,解决不同浏览器的兼容问题。比如,最常见的为dom节点添加事件的函数
function addEvent(type, element, fun) {
if (element.addEventListener) {
element.addEventListener(type, fun, false);
}
else if(element.attachEvent){
element.attachEvent('on' + type, fun);
}
else{
element['on' + type] = fun;
}
}
每次调用addEvent函数的时候,它都要对浏览器所支持的能力进行检查,首先检查是否支持addEventListener方法,如果不支持,再检查是否支持attachEvent方法,如果还不支持,就用dom0级的方法添加事件
这个过程,在addEvent函数每次调用的时候都要走一遍,其实,如果浏览器支持其中的一种方法,那么它就会一直支持了,就没有必要再进行其他分支的检测了。也就是说,if语句不必每次都执行,代码可以运行的更快一些
解决方案就是惰性载入
函数重写
在介绍惰性函数之前,首先介绍函数重写技术。由于一个函数可以返回另一个函数,因此可以用新的函数来覆盖旧的函数
function a(){
console.log('a');
a = function(){
console.log('b');
}
}
这样一来,第一次调用该函数时会console.log('a')会被执行;全局变量a被重定义,并被赋予新的函数。当该函数再次被调用时, console.log('b')会被执行
惰性函数
惰性函数的本质就是函数重写。所谓惰性载入,指函数执行的分支只会发生一次,有两种实现惰性载入的方式
1、第一种是在函数被调用时,再处理函数。函数在第一次调用时,该函数会被覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。代码重写如下
function addEvent(type, element, fun) {
if (element.addEventListener) {
addEvent = function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if(element.attachEvent){
addEvent = function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else{
addEvent = function (type, element, fun) {
element['on' + type] = fun;
}
}
return addEvent(type, element, fun);
}
在这个惰性载入的addEvent()中,if语句的每个分支都会为addEvent变量赋值,有效覆盖了原函数。最后一步便是调用了新赋函数。下一次调用addEvent()时,便会直接调用新赋值的函数,这样就不用再执行if语句了
但是,这种方法有个缺点,如果函数名称有所改变,修改起来比较麻烦
2、第二种是声明函数时就指定适当的函数。把嗅探浏览器的操作提前到代码加载的时候,在代码加载的时候就立刻进行一次判断,以便让addEvent返回一个包裹了正确逻辑的函数
var addEvent = (function () {
if (document.addEventListener) {
return function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if (document.attachEvent) {
return function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else {
return function (type, element, fun) {
element['on' + type] = fun;
}
}
})();
深入理解javascript函数进阶系列第四篇——惰性函数的更多相关文章
- 深入理解javascript函数进阶系列第三篇——函数节流和函数防抖
前面的话 javascript中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制的.在这些场景 ...
- 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法
× 目录 [1]方法 [2]非实时 [3]缺陷 前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuer ...
- 深入理解javascript选择器API系列第三篇——HTML5新增的3种selector方法
前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuery的称赞,很多是由于jQuery方便的元素选择器 ...
- Python进阶【第四篇】函数
一.变量 变量是记录一系列状态变化的量 1.变量分为可变类型与不可变类型——可变 与不可变是根据变量在内存中占据的位置 可变类型:列表list[ ].字典dicta{ } 不可变类型:字符串str.数 ...
- 深入理解javascript函数系列第四篇——ES6函数扩展
× 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...
- 深入理解DOM事件机制系列第四篇——事件模拟
× 目录 [1]引入 [2]模拟机制 [3]自定义事件 前面的话 事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发.但实际上,也可以使用javascript在任意时刻来触发特定的事 ...
- 深入理解DOM事件类型系列第四篇——剪贴板事件
× 目录 [1]定义 [2]对象方法 [3]应用 前面的话 剪贴板操作可能看起来不起眼,但是却十分有用,可以增强用户体验,方便用户操作.本文将详细介绍剪贴板事件 定义 剪贴板操作包括剪切(cut).复 ...
- 深入理解脚本化CSS系列第四篇——脚本化样式表
× 目录 [1]CSSStyleSheet [2]CSSRule 前面的话 关于脚本化CSS,查询样式时,查询的是计算样式:设置单个样式时,设置的是行间样式:设置多个样式时,设置的是CSS类名.脚本化 ...
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
随机推荐
- [转载] Dubbo架构设计详解
转载自http://shiyanjun.cn/archives/325.html Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合 ...
- Python之Queue模块
Queue 1.创建一个“队列”对象 >>> import Queue >>> queue = Queue.Queue(maxsize=100) >>& ...
- C语言一些知识点回顾
1.多行宏定义 #include <stdio.h> #define _PyObject_HEAD_EXTRA \ struct _object *_ob_next; \ struct _ ...
- ASP.NET Core教程【一】关于Razor Page的知识
关键文件和目录结构 按照asp.net core WEB应用程序向导,创建一个工程之后 你会发现如下几个目录和文件 wwwroot:放置网站的静态文件的目录 Pages:放置razor页面的目录 ap ...
- LINQ学习系列-----1.4 匿名对象
本篇内容接着上一篇继续讲述,本篇简单讲解匿名对象 一.匿名对象介绍 上代码: var result=new { ID=, Name="张三", Age= ...
- C#图片压缩上传
/// <summary> /// 压缩图片 /// </summary> /// <param name="iSource">图片文件< ...
- Android视频编辑SDK--RDVECore来自锐动的无UI,高度抽象化API
1 RDVECore功能概述 RDVECore是锐动推出的无UI,高度抽象化API的视频编辑SDK,支持以下功能: 1.1 丰富的编辑功能 RDVECore包含了丰富的基础功能,对于编辑中的视频.图片 ...
- uva11636-Hello World!
题意:已知有一行printf(“Hello World!”\n);以后就可以复制,问多少次之后就可以达到所需要的行数. 题解:模拟: #include<iostream> #include ...
- Nginx如何配置虚拟主机?
注意,该环境是依赖于http://www.php20.com/forum.php?m ... &extra=page%3D1 基础上进行配置.默认不具备这些文件 .下面是增加一个mytest点 ...
- 组件嵌套时报:Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
在组件嵌套的过程中,报了一个错误: 这里报错的原因是:vue的组件(模板)只能有一个根节点,即.vue文件中的<template>标签下只能有一个子元素. 因此,建议大家在写.vue组件的 ...