js 的 惰性函数

2 篇文章 0 订阅

在这里插入图片描述

惰性函数

知识点: 函数进阶函数重写预编译堆栈内存


1. 概念:

​ 官方说法:惰性函数 表示 函数执行的分支 只会在函数第一次调用的时候执行,在第一次调用的过程中,该函数会被 覆盖 为 另一个按照书写好的函数,之后,再次调用该函数时,就不再经过之前的分支了,执行的函数, 也不是之前的函数了,而是 经过修改后的函数;
总结说:就是在执行函数时,函数他 改变 函数自己;(自己理解)。

​ 哈哈哈,听不懂,那看一下例子吧 。


2. 背景:

​ 为了解决浏览器的兼容问题,我们会使用 if 判断,来判断 api 是否存在,从而来执行不同的代码 。

​ 通常以 给元素添加绑定事件 来举例子:

function addEvent(type, element, fnu) {
    if (element.addEventListener) {
        element.addEventListener(type, fun, false)
    } else if (element.attachEvent) {
        element.attachEvent('on' + type, fun)
    } else {
        element['on' + type] = fun
    }
}

解释

addEventListener:兼容 谷歌,火狐等

attachEvent:兼容 IE7, 8

都是给元素绑定事件的方法 ;判断是否存在,然后给传入的元素绑定方法,和以下的方法一样:

<body>
    	<button id="btn">点击</button>
</body>

<script>
    const btn = document.getElementById('btn')
    
    // 兼容 谷歌,火狐等
	btn.addEventListener('click', function() {
        console.log(2)
    }, false)

    
    // 不兼容 谷歌等,所以使用谷歌测试时,会报错
    btn.attachEvent('onclick', function() {
        console.log(3)
    })
    
    // 不太懂,好像都兼容
    btn['onclick'] = function() {
		console.log(21)
	}
</script>

下一个,我们使用 addEvent 函数来给 元素绑定事件:

<body>
	<button id="btn">点击</button>
    
<script>
	const btn = document.getElementById('btn')

	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('click', btn, function() {
		console.log(1)
	})

</script>
</body>

我们这样 每次调用 都会执行 if判断,调用一千次,就会进行一千次的判断;为了不进行那么多的判断,我们可以使用 懒惰函数 来完善这个方法;

在那之前先理解一下,函数重写


3. 函数重写:

就是在函数里面,对原函数本函数进行重新赋值,执行一次函数后,以后再调用这个函数时,调用的都是 重新赋值的函数 。

function fn () {
    console.log('我是函数fn')
    fn = function () {
        console.log('我是重写的fn')
    }
}

fn() // => 我是函数fn
fn() // => 我是重写的fn
fn() // => 我是重写的fn
  • 执行函数 fn()
  • 输出 我是函数fn
  • fn 重新赋值一个新的函数;
  • 下一次调用 fnfn 就是我们重新赋值的这个函数了(输出 “我是重新的fn”),
  • 而不是之前的那个(”我是函数fn“)!

在这里插入图片描述



4. 惰性函数:

惰性函数没有一种具体的写法,以下有2种写法:

第一种 :

<body>
	<button id="btn">点击</button>
    
<script>
const btn = document.getElementById('btn')

function addEvent(type, element, fun) {
    if (element.addEventListener) {
        console.log(1)
        addEvent = function(type, element, fun) {
            element.addEventListener(type, fun, false)
        }
    } 
    else if (element.attachEvent) {
        console.log(2)
        addEvent = function(type, element, fun) {
            element.attachEvent('on' + type, fun)
        }
    } 
    else {
        console.log(3)
        addEvent = function(type, element, fun) {
            element['on' + type] = fun
        }
    }

    console.log(100)
    return addEvent(type, element, fun)
}


// 使用函数,为元素绑定事件
addEvent('click', btn, function() {
    console.log(1)
})

</script>
</body>

可以实现按钮的点击,以上的实现和 函数重写 的原理是一样的,在第一次调用 函数时,就确定了 之后函数的内容,之后调用函数,就不用执行判断,来判断当前浏览器所兼容的 语法了。只需调用一次,就明白了 。


我们在函数中,输出值一开始输出:

> 1
> 100
// 继续点击按钮,后面输出的都是 1, 就说明了 之后调用函数,都是 另一个新函数,不然会输出 100 的;
> 1 n

但如果之后想要改变 函数的名字,就要一个一个改,比较麻烦;



第二种:

使用 立即执行函数,在一开始,就进行 兼容性的判断,然后返回不同的方法函数,然后使用 变量接收返回的函数,使用变量来调用函数就可以了 。

const 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
        }
    }
})();

addEvent('click', btn, function() {
    console.log(1)
})

注意,里面的 document 哦 。



5. 自己加点菜:

var getTimeStamp = (function() {
    var timeStamp = new Date().getTime()
    console.log(1)

    return function() {
        console.log(100)
        return timeStamp
    }
})();

console.log(getTimeStamp())
console.log(getTimeStamp())
console.log(getTimeStamp())

其实,只输出 1 一次,然后 100 三次;

页面执行时:会形成一个全局作用域 window,

变量提升: var getTimeStamp 和 自执行函数执行(注意,会执行哦,然后把函数的返回值,返回给 变量;

代码执行: console.log(getTimeStamp()) 时执行的是 自执行函数返回的 函数,不是自执行函数 。

看看控制台输出的:

在这里插入图片描述

是不是和我们想实现的功能有点相似。



6. 一点练习:

如何让以下的函数 只执行一遍 判断 呢?

let timeStamp = null

function getTimeStamp () {
    if (timeStamp) {
        console.log('进入判断')
        return timeStamp
    }

    console.log('没有进入判断')
    timeStamp = new Date().getTime()
    return timeStamp
}

console.log(getTimeStamp())
console.log(getTimeStamp())
console.log(getTimeStamp())
console.log(getTimeStamp())
console.log(getTimeStamp())

在这里插入图片描述


输出的都是一样的时间戳,具体的执行顺序是
1,变量提升 timeStamp = undefined; getTimeStamp = 函数堆内存,存储 代码字符串
2,赋值: timeStamp = null,执行函数 getTimeStamp();
3,执行函数,判断 timeStamp 是否存在值!
     是: 返回值;
     否: 给他赋值一个时间戳;

4, 第一次 timeStamp 为 null,所以(不进入if)执行  
		timeStamp = new Date().getTime() 然后返回值;
    第二次 timeStamp 为之前 赋值 的时间戳,进入 if判断,返回值;
    第三次 timeStamp 为之前的 时间戳,进入 if判断,返回值;
    第n次 也和以上的一样,都是 进入 if判断,返回值;
    如何证明呢?
    你看控制台的输出结果就知道了!
    只执行一次 没有进入 if判断,其余的调用都进入到了 if判断中了 。


5, 但是,有人提出了,调用函数 getTimeStamp(),都会执行一次 if判断,想要在 时间戳 存在,下一次就不进行 if 判断了,这该怎么做?

可以用 惰性函数 试试:

var timeStamp = null
function getTimeStamp () {
    timeStamp = new Date().getTime();
    
    getTimeStamp = function () {
        console.log(2)
        return timeStamp
    }
    
    console.log(1)
    return timeStamp
}

console.log(getTimeStamp())
console.log(getTimeStamp())
console.log(getTimeStamp())

在这里插入图片描述

  • 第一次: getTimeStamp() 时,给 timeStamp 赋值了当前时间戳,并改变了 getTimeStamp 的指向,指向了一个新的函数,输出 1,并返回 timeStamp 值;
  • 第二次:再次调用 getTimeStamp() 时,执行了一个新函数,输出 2, 并返回之前赋值的 时间戳;
  • 第三次:还是和第二次一样,输出2,返回 时间戳;
  • 如果有点听不懂,想想 函数重写的这个原理 。


最后有一个学习视频和网站推荐给大家看看:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值