前面的话

  惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。本文将详细介绍惰性函数

使用背景

  因为各浏览器之间的行为的差异,经常会在函数中包含了大量的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函数进阶系列第四篇——惰性函数的更多相关文章

  1. 深入理解javascript函数进阶系列第三篇——函数节流和函数防抖

    前面的话 javascript中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制的.在这些场景 ...

  2. 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法

    × 目录 [1]方法 [2]非实时 [3]缺陷 前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuer ...

  3. 深入理解javascript选择器API系列第三篇——HTML5新增的3种selector方法

    前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuery的称赞,很多是由于jQuery方便的元素选择器 ...

  4. Python进阶【第四篇】函数

    一.变量 变量是记录一系列状态变化的量 1.变量分为可变类型与不可变类型——可变 与不可变是根据变量在内存中占据的位置 可变类型:列表list[ ].字典dicta{ } 不可变类型:字符串str.数 ...

  5. 深入理解javascript函数系列第四篇——ES6函数扩展

    × 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...

  6. 深入理解DOM事件机制系列第四篇——事件模拟

    × 目录 [1]引入 [2]模拟机制 [3]自定义事件 前面的话 事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发.但实际上,也可以使用javascript在任意时刻来触发特定的事 ...

  7. 深入理解DOM事件类型系列第四篇——剪贴板事件

    × 目录 [1]定义 [2]对象方法 [3]应用 前面的话 剪贴板操作可能看起来不起眼,但是却十分有用,可以增强用户体验,方便用户操作.本文将详细介绍剪贴板事件 定义 剪贴板操作包括剪切(cut).复 ...

  8. 深入理解脚本化CSS系列第四篇——脚本化样式表

    × 目录 [1]CSSStyleSheet [2]CSSRule 前面的话 关于脚本化CSS,查询样式时,查询的是计算样式:设置单个样式时,设置的是行间样式:设置多个样式时,设置的是CSS类名.脚本化 ...

  9. 深入理解javascript函数进阶系列第一篇——高阶函数

    前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...

随机推荐

  1. [转载] Dubbo架构设计详解

    转载自http://shiyanjun.cn/archives/325.html Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合 ...

  2. Python之Queue模块

    Queue 1.创建一个“队列”对象 >>> import Queue >>> queue = Queue.Queue(maxsize=100) >>& ...

  3. C语言一些知识点回顾

    1.多行宏定义 #include <stdio.h> #define _PyObject_HEAD_EXTRA \ struct _object *_ob_next; \ struct _ ...

  4. ASP.NET Core教程【一】关于Razor Page的知识

    关键文件和目录结构 按照asp.net core WEB应用程序向导,创建一个工程之后 你会发现如下几个目录和文件 wwwroot:放置网站的静态文件的目录 Pages:放置razor页面的目录 ap ...

  5. LINQ学习系列-----1.4 匿名对象

    本篇内容接着上一篇继续讲述,本篇简单讲解匿名对象 一.匿名对象介绍              上代码: var result=new { ID=, Name="张三", Age= ...

  6. C#图片压缩上传

    /// <summary> /// 压缩图片 /// </summary> /// <param name="iSource">图片文件< ...

  7. Android视频编辑SDK--RDVECore来自锐动的无UI,高度抽象化API

    1 RDVECore功能概述 RDVECore是锐动推出的无UI,高度抽象化API的视频编辑SDK,支持以下功能: 1.1 丰富的编辑功能 RDVECore包含了丰富的基础功能,对于编辑中的视频.图片 ...

  8. uva11636-Hello World!

    题意:已知有一行printf(“Hello World!”\n);以后就可以复制,问多少次之后就可以达到所需要的行数. 题解:模拟: #include<iostream> #include ...

  9. Nginx如何配置虚拟主机?

    注意,该环境是依赖于http://www.php20.com/forum.php?m ... &extra=page%3D1 基础上进行配置.默认不具备这些文件 .下面是增加一个mytest点 ...

  10. 组件嵌套时报: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组件的 ...