偶遇this之坑
前言
在写一个懒加载插件时,遇到一个坑,就是this的指向问题,我想这种情况大部分人都会遇到,就写下来,新手也有个参考。
事件
有些页面图片比较多,但用户还不一定会全看,这样的话,全部去加载这些图片,就有点浪费资源了,于是想写一个通用的插件来解决这个问题
想法
根据滚动条高度加屏幕高度来判断是否加载这张图片,需要懒加载的图片这样写
<img data-src="image/bg.jpg">
凡是加上这个属性的都会做懒加载处理。
this之坑
以下是最终的代码
function SetImg(top){
	var imgs = Array.prototype.slice.apply(document.getElementsByTagName("img"));
	this.imgs = imgs.filter(function(item,index){
		return item.dataset.src;
	});
	this.top = top || 150;
}
SetImg.prototype = {
	init:function(){
		this.event();
	},
	setSrc:function(){
		if(this.imgs.length===0){
			window.removeEventListener("scroll",this.setSrc);
		};
		var _this = this;
		this.imgs.forEach(function(item,index){
			if(document.documentElement.clientHeight+document.body.scrollTop+_this.top>item.offsetTop||item.offsetTop<document.documentElement.clientHeight){
				item.src = item.dataset.src;
				_this.imgs.splice(index,1);
			}
		})
	},
	event:function(){
		this.setSrc = this.setSrc.bind(this);
		window.addEventListener("load",this.setSrc);
		window.addEventListener("scroll",this.setSrc);
	}
};
new SetImg().init();
这个代码已经解决了this的指向问题,也就是下面这句
this.setSrc = this.setSrc.bind(this);
一开始是没有这句话的,但问题是,我在setSrc里面使用了this,而恰恰那里面的this指向的是window,为什么指向window?因为这句话
window.addEventListener("load",this.setSrc);
window.addEventListener("scroll",this.setSrc);
我们说this始终指向一个对象,而现在给添加的事件,就是在window身上添加的,正如
element.addEventListener("click",fn);
这句不就是指向element吗,那上面的那个指向window,也就不足为奇了。因此这也是为什么最后我添加这么一句
this.setSrc = this.setSrc.bind(this);
其实一开始我没想要这么做,但这也是迫不得已的事,一开始我是这样写的:
window.addEventListener("load",this.setSrc.bind(this));
window.addEventListener("scroll",this.setSrc.bind(this));
但这样的问题是,bind返回的是一个新对象,而不是原本的this.setSrc。一般情况下,这也不是什么大问题,但坑就坑在this.setSrc里面的这句
if(this.imgs.length===0){
    window.removeEventListener("scroll",this.setSrc);
};
看似一切都正常,但这是一个大坑,这里面的this.setSrc指向的是SetImg.setSrc,而
window.addEventListener("scroll",this.setSrc.bind(this));
this.setSrc.bind(this)这是一个新对象,因此你根本就无法remove掉这个新对象。所以最终才想出个迫不得已的方法就是让this.setSrc变成新的那个对象。
可能有些朋友,不太懂为什么要写这么一句:
if(this.imgs.length===0){
    window.removeEventListener("scroll",this.setSrc);
};
这句话的作用是,如果所有图片都加载完毕了,这个滚动事件,就不需要了。当然如果你直接使用window.onscroll这种情势来写,或许这个问题可以很好的解决,但作为一个插件用addEventListener是迫不得已的,因为我不知道哪个页面使用了onscroll事件,如果我直接那样写,就会把其他人写的事件覆盖掉。
结语
这种情况出现的概率还是蛮高的,导致这种问题的出现就是,事件里面的this和构造函数里面的this,指向的是不同的对象,所以啊这就是坑点。
说到正题,这个插件还不能用T_T,再改改吧
偶遇this之坑的更多相关文章
- 偶遇vue-awesome-swiper的坑
		
最近用vue重构一个移动端的项目,碰到了不少坑,今天拿移动端最著名的轮播插件swiper为例来说,由于这个项目没用UI库,纯手写的样式,沿用老的插件,自然而然的选择了vue-awesome-swipe ...
 - 彻底理解js中this的指向,不必硬背。
		
首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...
 - this指向详解及改变它的指向的方法
		
一.this指向详解(彻底理解js中this的指向,不必硬背) 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是 ...
 - 详解lastindex,正则test()与全局匹配g偶遇,带来一会true一会false的坑
		
一.简单的需求与奇怪的问题 周一接到需求文档,产品分类页的输入框,需要加一个智能下拉提醒的功能,大概就是用户输入啥,找到符合输入字段的产品名,进行下拉推荐,同时将此字段标红,有点类似于百度搜索的智能提 ...
 - 【转】Vue 脱坑记 - 查漏补缺(汇总下群里高频询问的xxx及给出不靠谱的解决方案)
		
前言 文章内容覆盖范围,芝麻绿豆的破问题都有,不止于vue; 给出的是方案,但不是手把手一字一句的给你说十万个为什么! 有三类人不适合此篇文章: “喜欢站在道德制高点的圣母婊” – 适合去教堂 “无理 ...
 - Android,我待你入初恋啊,你就别坑我了!
		
最近做了好多东西,东忙忙,西茫茫,ms最后都空欢喜一场. 1.小黄图,说是小黄图,其实只是网上爬下来的写真阿自拍阿什么的,绝对没有反党反共淫秽内容.后来的后来,admob被google停用了,不开心. ...
 - Vue 脱坑记
		
问题汇总 Q:安装超时(install timeout) 方案有这么些: cnpm : 国内对npm的镜像版本 /* cnpm website: https://npm.taobao.org/ */ ...
 - 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
		
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
 - 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
		
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
 
随机推荐
- MIP开发常见问题解答
			
校验相关 1. MIP 页面的 <a>链接校验报错,MIP 是强制 target="_blank" 吗? 如果想直接跳转MIP页,可以用mip-link 组件:MIP ...
 - JS核心系列:浅谈函数的作用域
			
一.作用域(scope) 所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的. function scope(){ var foo = "global&quo ...
 - .NetCore中的日志(2)集成第三方日志工具
			
.NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...
 - 【原】实时渲染中常用的几种Rendering Path
			
[原]实时渲染中常用的几种Rendering Path 本文转载请注明出处 —— polobymulberry-博客园 本文为我的图形学大作业的论文部分,介绍了一些Rendering Path,比较简 ...
 - 23种设计模式--代理模式-Proxy
			
一.代理模式的介绍 代理模式我们脑袋里出现第一个词语就是代购,其实就是这样通过一个中间层这个中间成是属于什么都干什么都买得,俗称"百晓生",在平时得开发中我们经常会听到 ...
 - redis集成到Springmvc中及使用实例
			
redis是现在主流的缓存工具了,因为使用简单.高效且对服务器要求较小,用于大数据量下的缓存 spring也提供了对redis的支持: org.springframework.data.redis.c ...
 - iOS开发之多种Cell高度自适应实现方案的UI流畅度分析
			
本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...
 - enote笔记法使用范例(2)——指针(1)智能指针
			
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
 - mysql 行级锁的使用以及死锁的预防
			
一.前言 mysql的InnoDB,支持事务和行级锁,可以使用行锁来处理用户提现等业务.使用mysql锁的时候有时候会出现死锁,要做好死锁的预防. 二.MySQL行级锁 行级锁又分共享锁和排他锁. 共 ...
 - Linux 权限设置chmod
			
Linux中设置权限,一般用chmod命令 1.介绍 权限设置chmod 功能:改变权限命令.常用参数: 1=x(执行权execute) 2=w(写权write) 4=r(读权Read) setuid ...