首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
138 阅读
2
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
131 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
107 阅读
4
如何在 Clash for Windows 上配置服务
77 阅读
5
Uniapp如何引入自定义样式文件
75 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
624
篇与
的结果
2024-10-21
从输入URL到页面加载完成的过程中都发生了什么
从输入URL到页面加载完成的过程中都发生了什么。本篇文章主要是翻译stackoverflow的一个回答,他没有非常繁琐和底层的介绍,从寥寥的几个步骤中,我们就能了解各大概了。当然,如果想看更详细的内容,可以参考这篇文章:从输入 URL 到页面加载完成的过程中都发生了什么事情?这篇文章的stackoverflow链接是what happens when you type in a URL in browser 1.browser checks cache; if requested object is in cache and is fresh, skip to #9 1.浏览器检查缓存,若缓存中存储着要请求的内容,并且内容是最新的,直接跳转到第9步 2.browser asks OS for server's IP address 2.浏览器请求操作系统(OS)解析服务器的IP地址 3.OS makes a DNS lookup and replies the IP address to the browser 3.操作系统做DNS解析,查找并返回IP地址给浏览器 4.browser opens a TCP connection to server (this step is much more complex with HTTPS) 4.浏览器与服务器建立TCP连接(若使用的是https协议,连接过程会更加的复杂) 5.browser sends the HTTP request through TCP connection 5.浏览器通过TCP连接发送http请求 6.browser receives HTTP response and may close the TCP connection, or reuse it for another request 6.浏览器接收到http相应后,关闭(断开)TCP连接或者利用TCP发送其他http请求 7.browser checks if the response is a redirect (3xx result status codes), authorization request (401), error (4xx and 5xx), etc.; these are handled differently from normal responses (2xx) 7.浏览器检测http相应是否是重定向(http状态码为3xx),授权相应(401),错误相应(4xx和5xx)等;浏览器对这些状态码的处理与正常的相应(2xx)是不同的 8.if cacheable, response is stored in cache 8.若可以被缓存,则将相应存储到缓存中 9.browser decodes response (e.g. if it's gzipped) 9.浏览器解压相应(比如页面被gzip压缩过) 10.browser determines what to do with response (e.g. is it a HTML page, is it an image, is it a sound clip?) 10.浏览器决定以什么样式的方式解析http相应(比如他可能是个html网页,可能是一张图片,或者可能是个音频短片等) 11.browser renders response, or offers a download dialog for unrecognized types 11.若相应的是浏览器不能解析的格式,则下载该文件;否则浏览器就解析相应其实,这些都是用很简介的语言概括了一下,这里的每个步骤都能展开很多的篇幅来进行讲解。同时,除了上面的这些,也还有其他的操作(比如:处理输入的地址,把当前页面添加到浏览器浏览历史中,给用户展示加载进度,通知插件和扩展,在页面下载的同时就开始进行渲染,流水线操作,保持跟踪连接等)
2024年10月21日
6 阅读
0 评论
0 点赞
2024-10-21
取其精华,去其糟粕
今天差不多读完了《JavaScript 语言精粹》,虽然这本书写的比较早,当时还是 ES3 的标准,不过依然还是有很多借鉴意义的。有些事情在当时的环境和浏览器的性能下,还是比较流行的,但是现在却是另一种情况了。比如数组转换为字符串,那时候 IE6~IE8 还比较盛行的时候,更多的是推荐Array.join('')来进行转换,但是现在,更加推荐使用+进行字符串的拼接。不过说实话,虽然书名是《JavaScript 语言精粹》,但是读完后,除了记住 js 中各种各样的糟糕状况,还真没想起几个精华来。JavaScript 作为一个 10 天就设计出来的语言,承受了超乎想象的流行程度。它一诞生,就在短到令人吃惊的时间里被全世界所接受。它从来没有在实验室里被试用和打磨。当它还非常粗糙时,它就被直接集成到网景的浏览器中。虽然 java 的小应用程序(java applets)的失败,JavaScript 变成了默认的‘web 语言’。不过,JavaScript 还是多多少少有其自身的特点的。比如强大的对象字面量,原型继承,强大的数组和字符串操作等。好吧,精华还真想不出什么来,谁让它在目前来说是唯一的一个脚本编程语言呢。JavaScript 的糟粕还是不少的。比如:1.全局变量:全局变量可以被程序的任何部分在任意时间修改,这些都是不可控的。本来你一直这么使用全局变量的,可是其他人根据他的需要修改了全局变量的值,就会导致你的程序出现 Bug。针对这种情况,我们需要尽量地避免使用全局变量,如果非得需要不可的话,我们可以把全局变量放到一个命名空间里,当其他人声明全局变量时,要么使用你的命名空间,要么使用它的命名空间,这样就能尽量地减少全局变量的重复了:var Wenzi = Wenzi || {}; Wenzi.WEBBASEURL = 'www.xiabingbao.com'; Wenzi.SERVER_TIME = 1431871979; 2.作用域:JavaScript 提供了块级语法,却没有提供块级作用域,在该作用域内声明的变量,在其外部也能够使用。比如:for (var i = 0; i < 10; i++) {} console.log(i); // 输出10 3.自动添加分号:使用 JavaScript 进行编程,不用担心末尾没有写分号而导致程序不能运行。可是如果没有良好的编程习惯,就会产生很严重的逻辑错误。在下面的代码中,我们本意是要返回一个 json 结构,可是因为 js 自动添加了分号,导致返回了一个空。return; { name: 'wenzi'; } 4.+的使用:+运算符既可以用作拼接字符串,也可用作数字的相加。这个符号产生什么作用,取决于两端的云算数的类型:若两端的云算数都是数字,那么就是两个数的相加;若其中一个为字符串或两个都为字符串,那么就是字符串的拼接;若是其他的类型,那么就将其转换为字符串进行拼接。...其实 JavaScript 中还有相当多的糟粕,目前就暂时总结这几种吧。也可以看看之前总结的【Javascript 的严格模式】,在严格模式下,能预防很多低级错误的发生。虽然 JavaScript 有着这样的不好那样的不好,但是,正是因为它的这些特性,让 web 的脚本编程更加的丰富。web 前端发展到现在,真是处于百花齐放的盛况:jQuery, augular, node, react 等。而且现在还有 CMD 和 AMD 规范。到这里,或许会有人问我,这本书值不值得读,值不值得买。我可以很肯定的说:‘值得买’,但是,不是所有人都需要买。就我目前读完的感觉,这本书比较适合学习 6~12 个月的学习者购买。若学习 javascript 时间太短,书里说的那些知识点可能都没有接触到;若学习的时间稍微长一些,比如 2 年左右的(如本人),购买的价值就下降了,因为书上很多的精华与糟粕,其实在你的项目中早已经接触到了;而且,若你一直使用 ES5 的严格模式进行开发,就能避免很多潜在的问题。
2024年10月21日
7 阅读
0 评论
0 点赞
2024-10-21
html5实现图片预览和查看原图
html5 从一开始就给开发者很多的期待,提供众多新的 API,不用再想以前一样,为了实现某个功能写很多的代码。在以前,如果要实现图片预览会怎么做呢,因为为了安全的原因,web 端的 js 是不能读取文件的本地真实路径的,那么只能将图片上传到服务器上,然后再拿到图片的链接,这样才能实现图片预览。而服务器呢,比如有两个文件夹,一个是临时文件夹,一个是正式文件夹,临时文件夹会定时进行清理,正式文件夹是用户确认使用的图片存储的位置。 1. fileReader # 现在 html5 提供的 API 不再让图片预览那么麻烦,FileReader 提供了很多的方法来进行图片预览和文本读取,同时也提供了一整套完整的事件来捕获文件的状态,如下:FileReader 接口的方法 FileReader 接口有 4 个方法,其中 3 个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result 属性中。 方法名 参数 描述 readAsBinaryString file 将文件读取为二进制编码 readAsText file[, encoding] 按照格式将文件读取为文本,encode默认为UTF-8 readAsDataURL file 将文件读取为DataUrl abort (none) 终端读取操作 FileReader 接口事件 FileReader 接口包含了一套完整的事件模型,用于捕获读取文件时的状态。 事件 描述 onabort 中断 onerror 出错 onloadstart 开始 onprogress 正在读取 onload 成功读取 onloadend 读取完成,无论成功失败 2. 使用 fileReader 读取图片 # 从上面的表格中,我们可以大致了解 fileReader 提供哪些方法和事件,不过本文主要是讲解图片的读取,那么我们就是用readAsDataURL()就可以了。不过,在进行这一切之前,我们必须检测当前的浏览器是否支持 html5 的 fileReader,别进行了一系列的处理和操作,结果 js 报错,说 fileReader 没有定义。就好像对一个女孩儿又亲又啃,马上要提枪上马了,结果发现这是个纯爷们。if (!(window.FileReader && window.File && window.FileList && window.Blob)) { show.innerHTML = '您的浏览器不支持fileReader'; upimg.setAttribute('disabled', 'disabled'); return false; } 好的,让我们先看下 demo 演示:【狠狠点击这里】 2.1 读取单张图片 # 使用 input[type=file]控件读取文件,然后监听这个控件的 change 事件,若读取的文件个数大于零,那么就进行下一步的操作: var upimg = document.querySelector('#upimg'); upimg.addEventListener('change', function (e) { var files = this.files; if (files.length) { // 对文件进行处理,下面会讲解checkFile()会做什么 checkFile(this.files); } }); 现在我们只能选取一张图片,针对选取的这张图片,我们使用 fileReader 进行图片的处理// 图片处理 function checkFile(files) { var file = files[0]; var reader = new FileReader(); // show表示,用来展示图片预览的 if (!/image\/\w+/.test(file.type)) { show.innerHTML = '请确保文件为图像类型'; return false; } // onload是异步操作 reader.onload = function (e) { show.innerHTML = ''; }; reader.readAsDataURL(file); } 现在,就可以在页面上看到图片了。审查元素后我们能够看到,图片地址是个 base64 的字符串,如:'data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sA......' 2.2 读取多张图片 # 多张图片和单张图片的处理过程很相似,但是也还是有区别的,因为 reader.onload()是一个异步的操作,进行下一步的操作时必须在这个方法里 // change事件没有改动 // 图片处理 function checkFile(files) { var html = '', i = 0; var func = function () { if (i >= files.length) { // 若已经读取完毕,则把html添加页面中 show.innerHTML = html; } var file = files[i]; var reader = new FileReader(); // show表示,用来展示图片预览的 if (!/image\/\w+/.test(file.type)) { show.innerHTML = '请确保文件为图像类型'; return false; } reader.onload = function (e) { html += ''; i++; func(); //选取下一张图片 }; reader.readAsDataURL(file); }; func(); } 2.3 拖拽拉取图片 # 拖拽事件,采用的是 html5 中的 drag 和 drop,本文不着重介绍这两个方法,仅仅是讲解如何使用。首先,我们设置一块拖拽区域,告诉用户应该把图片拖拽到什么位置: .drag{ width: 400px;height: 100px;border: 1px dotted #333; text-align: center; line-height: 100px; color: #aaa; display: inline-block;} .drag_hover{background: #FAD6F9;} 拖拽区域 然后,我们给 drag 区域绑定上拖拽事件var drag = document.getElementById('drag'); drag.addEventListener( 'dragenter', function (e) { // 拖拽鼠标进入区域时 this.className = 'drag_hover'; }, false ); drag.addEventListener( 'dragleave', function (e) { // 拖拽鼠标离开区域时 this.className = ''; }, false ); drag.addEventListener( 'drop', function (e) { // 当鼠标执行‘放’的动作时,执行读取文件操作 var files = e.dataTransfer.files; this.className = ''; if (files.length != 0) { checkFile(files); } e.preventDefault(); }, false ); drag.addEventListener( 'dragover', function (e) { // 当对象拖动到目标对象时触发 e.dataTransfer.dragEffect = 'copy'; e.preventDefault(); }, false ); 这里有个需要注意的地方:需要给 dragover 和 drop 添加阻止默认事件,否则浏览器会采用file:///的方式打开文件。drop 事件执行后就是进行 checkFile(),后续的操作与使用 input[type=file]的操作一样。 3. 点击查看原图 # 当我们点击图片查看原图时,需要知道图片的原始尺寸。可能你会想到使用 img.width 和 img.height,对,这个确实能获取到图片的长和宽,但是,这个长和宽是经过 css 修饰后的,不是图片原始的尺寸。如果要获取图片的原始尺寸,我们可以在 js 中创建一个 Image 对象,然后把那张图片的地址给了这个 Image 对象,然后获取 Image 对象的尺寸,这样就能获取到图片的原始尺寸了。var img = new Image(); img.src = img.src; // 给新的img对象链接 console.log(img.width, img.height); 而在 html5 中,我们不用再那么麻烦的创建一个无用的 img 对象了,直接使用给出的属性即可。console.log(img.naturalWidth); // 获取图片的原始的宽度 console.log(img.naturalHeight); // 获取图片的原始的高度 获取到图片的原始尺寸后,就能做出‘查看原图’的效果了。 4. 总结 # html5 真是个好东西,还有着很多的东西等着我们去挖掘。“蹿腾吧,程序员”!
2024年10月21日
26 阅读
0 评论
0 点赞
2024-10-21
javascript设计模式之构造函数模式
在学习设计模式之前,我们首先要确定几个要点,应该从哪几个方向研究设计模式,当我们搞清楚这个设计模式后,我们应该在什么场合使用这个模式: 模式的名称和实现方式; 模式的适用场景,即这个模式是为了解决什么问题而设计出来的; 模式的整体结构是什么,我该怎么使用(有的模式有改进型,混合型等各种变形); 该模式与其他模式的比较 总结,模式的优点与缺点 下面我们就根据这几个点开始学习 1. 模式的名称和实现方式 # 本文研究的是构造函数模式,名称当时构造函数(Constructor)模式了。构造器模式用于创建特定类型的对象——准备好对象以备使用,同时接受构造函数可以使用的参数,以在第一次创建对象时,设置成员属性和方法的值。既然是构造函数模式,那就必然是以构造函数为基础的模式。如Array(), String(), Object()等js本来提供的构造函数,也是能形成构造函数模式的。var arr = new Array(1, 2, 3, 4); var str = new String('this is a string'); var obj = new Object({ 'name':'wenzi', 'age':'25', 'sex':'male' }) 当然,js里提供了这些构造函数的字面量声明的简单方式,不用再那么麻烦的new了,而且更加推荐使用以下的方式进行构建。var arr = [1, 2, 3, 4]; var str = 'hello world'; var obj = { 'name':'wenzi', 'age':'25', 'sex':'male' } 同时,我们也可以使用自己定义的构造函数,一般构造函数的首字母大写,这是一种良好的编码规范。如:function Person(name, age){ this.name = name; this.age = age; this.getName = function(){ return this.name; } } var parent = new Person('jack', 46); var son = new Person('jack', 21); 2. 模式的适用场景 # 构造函数模式通常使用在对象的属性较少,相对来说比较简单的地方,比如仅仅需要包装出一个对象,或者想用一个变量存储几个属性。 3. 模式的整体结构 # 模式的整体刚才在第1部分讲解了一下,主要有:原生构造函数,对象字面量,自定义构造函数等。在上面的自定义构造函数中,我们可以确认parent和son两个属性值的比较结果parent.name === son.name; // true parent.age === son.age; // false 可是parent.getName===son.getName会输出什么呢?运行之后,我们就会发现,这个比较式会输出false。为什么呢?函数名一样,都是getName,而且函数体也一样,可是为什么会输出false呢?其实,每次在使用Person进行对象创建的时候,都会创建一个新的函数给getName,因此,虽然看起来是一样,但实际上是两个函数。如果创建的对象比较多的话,那么创建的getName函数也会比较的多,可是getName的功能是一样的,没必要跟着也创建好多次。因此我们可以做如下的改进:function Person(name, age){ this.name = name; this.age = age; this.getName = getName; } function getName(){ return this.name; } var parent = new Person('jack', 46); var son = new Person('jack', 21); parent.getName === son.getName; // true 这样使用 Person 创建的对象使用getName时,都会将引用指向getName()这个函数。因此,上面的比较式会输出出。这样写能够减少getName的创建次数,减少内存的使用。不过其实这种方式,也是有缺点的,如果构造函数里的方法很多呢,那是不是得写好多全局的函数,用来引用呢。还有一种方式是,把方法写在原型prototype上,调用js构造器创建一个对象后,新对象就会具有构造器原型的所有属性。function Person(name, age){ this.name = name; this.age = age; } Person.prototype.getName = function(){ return this.name; } var parent = new Person('jack', 46); var son = new Person('jack', 21); parent.getName === son.getName; // true 针对这三种方式,应该考虑实际情况使用,而不是一味的采用第三种方式。如果构造函数相对来说比较简单,而且创建出的对象也不多,也就没比较使用原型。 4. 总结 # 为什么没有和其他模式的比较呢?因为还没有开始其他模式的讲解,哈哈!构造函数模式的优点就是构造简单,使用方便,而且容易理解。当然缺点也是比较明显的,就是扩展性差,每个实例的方法都是独立的,多数情况下同个对象的实例方法都是一样的。
2024年10月21日
4 阅读
0 评论
0 点赞
2024-10-21
javascript中的闭包
1. 简要介绍 # 闭包可谓是js中的一大特色了,即使你对闭包没概念,你可能已经在不知不觉中使用到了闭包。闭包是什么,闭包就是一个函数可以访问到另一个函数的变量。这就是闭包,解释起来就这么一句话,不明白?我们来看一个简单的例子:function getName(){ var name='wenzi'; setTimeout(function(){ console.log(name); }, 500); } getName(); 这就其实已经是闭包了,setTimeout中的function是一个匿名函数,这个匿名函数里的name是geName()作用域中的变量,匿名函数里只有一个输出语句:console.log();还有一个很经典的例子也可以帮助我们理解什么是闭包:function create(){ var i=0; // 返回一个函数,暂且称之为函数A return function(){ i++; console.log(i); } } var c = create(); // c是一个函数 c(); // 函数执行 c(); // 再次执行 c(); // 第三次执行 在上面的例子中,create()返回的是一个函数,我们暂且称之为函数A吧。在函数A中,有两条语句,一条是变量i自增(i++),一条是输出语句(console.log)。第一次执行执行c()时会产生什么样的结果?嗯,输出自增后的变量i,也就是输出1;那么第二次执行c()呢,对,会输出2;第三次执行c()时会输出3,依次累加。这个create()函数依然满足了我们在刚开始时的定义,函数A使用到了另一个函数create()中的变量i。可是为什么会产生这样的输出呢,为什么i就能一直自增呢,create函数已经执行完并返回结果了呀,可是为什么还能接着使用i呢,而且i还能自增。这里就涉及到了三个比较重要的概念,讲解完这三个概念,我们对闭包就可以有一个比较好的理解了。 2. 三个重要概念 # 2.1 执行环境与变量对象 # 执行环境是JavaScript中一个重要的概念,它决定了变量或函数是否有权访问其他的数据,决定了它们各自的行为。每个执行环境都有一个与之对应的变量对象,执行环境中定义的所有变量和函数都保存在这个对象中。虽然我们的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。我们用一个比较简单的比喻来形容这两个概念。执行环境就是一个人,变量对象就是这个人的身份证号,每个人都有其对应的身份证号。他这个人决定了他身上的很多属性和方法(动作),而且这个人的属性和方法都在他的身份证号上,当这个人消亡的时候,身份证号也就随之就注销了。全局执行环境是最外层的一个执行环境。在web浏览器中,全局执行环境被认为是window对象,因为所有的全局变量和全局函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或者浏览器——时才会被销毁),被垃圾回收机制回收。每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入到一个环境栈中。而在函数执行后,栈将其环境弹出,把控制权返回给之前的执行环境。 2.2 作用域链 # 作用域链是当代码在一个环境中执行时创建的,作用域链的用途就是要保证执行环境中能有效有序的访问所有变量和函数。作用域链的最前端始终都是当前执行的代码所在环境的变量对象,下一个变量对象是来自其父亲环境,再下一个变量对象是其父亲的父亲环境,直到全局执行环境。标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)。其实,通俗的理解就是:在本作用域内找不到变量或者函数,则在其父亲的作用域内寻找,再找不到则到父亲的父亲作用域内寻找,直到在全局的作用域内寻找! 2.3 垃圾回收机制 # 在js中有两种垃圾收集的方式:标记清除和引用计数。标记清除:垃圾收集器在运行时会给存储在内存中的所有变量都加上标记(具体的标记方式暂时就不清楚了),待变量已不被使用或者引用,去掉该标记或添加另一种标记。最后,垃圾收集器完成内存清除工作,销毁那些已无法访问到的这些变量并回收他们所占用的空间。引用计数:一般来说,引用计数的含义是跟踪记录每个值被引用的次数。当声明一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数便是1,如果同一个值又被赋给另一个变量,则该值的引用次数加1,相反,如果包含对这个值引用的变量又取得了另一个值,则这个值的引用次数减1。当这个值的引用次数为0时,说明没有办法访问到它了,因而可以将其占用的内存空间回收。除了一些极老版本的IE,目前市面上的JS引擎基本采用标记清除来除了垃圾回收。但是需要注意的是IE中的DOM由于机制问题,是采用了引用计数的方式,所以会有循环引用的问题,造成内存泄露。var ele = document.getElementById(“element”); var obj = new Object(); ele.obj = obj; // DOM元素ele的obj引用obj变量 obj.ele = ele; // obj变量的ele引用了DOM元素ele 这样就造成了循环引用的问题,导致垃圾回收机制回收不了ele和obj。不过,可以在不使用ele和obj时,对这两个变量进行 null 赋值,然后垃圾回收机制就会回收它们了。 3. 理解闭包 # 在第2部分讲解了三个重要的概念,这三个概念有助于我们更好的理解闭包。我们再次拿出上面的这个例子:function create(){ var i=0; // 返回一个函数,暂且称之为函数A return function(){ i++; console.log(i); } } var c = create(); // c是一个函数,即函数A c(); // 函数执行 c(); // 再次执行 c(); // 第三次执行 从上面的“每个函数都有自己的执行环境”可以知道:create()函数是一个执行环境,函数A也是一个执行环境,且函数A的执行环境在create()的里面。这样就形成了一个作用域链:window->create->A。当执行c()时,函数A就会首先在当前执行环境中寻找变量i,可是没有找到,那么只能顺着作用域链向后找;OK,在create()的执行环境中找到了,那么就可以使用了变量i了。可是我们还有一个疑问,按照上面的说法,函数create()执行完毕后,create()不再有其他的操作,这个函数与里面的变量和方法应该被回收了呀,可是为什么函数c()多次执行时依然能够输出变量i呢。这就是闭包的独特之处。函数create()执行完毕后被垃圾回收机制进行回收,虽然它的作用域链会被销毁,即不再存在window->create这个链式关系,但是函数A()[c()]的作用域链还依然引用着create()的变量对象,还存在着window->create->A的链式关系,导致垃圾回收机制不能回收create()的变量对象,create()的变量对象仍然停留在内存中,直到函数A()[c()]被销毁后,create()的变量对象才会被销毁。因此,虽然create()已经执行完毕了,但是create()的变量对象并没有被回收,还停留在内存中,依然可以使用。有些同学对变量i的变化可能还有一些疑问“每次执行c()时,应该都是向上一级寻找变量i,每次寻找到时变量i应该都是0呀,为什么会自增呢?”。在这里再详细的解释一下,若当前作用域没有这个变量时,就会向上一级的作用域进行寻找,一直到能寻找到该变量(或出错为止),当寻找这个变量后,当前的作用域就会保存这个变量的引用。因此,若下次使用这个变量时,就会直接使用,而且使用的是同一个变量i。所以,上面多次运行c()后,能够使i自增,而不是每次都获取到0。从上面的讲解中我们可以看到,闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。当页面中存在过多的闭包,或者闭包的嵌套很多很深时,会导致内存占用过多。因此,在这里建议:慎用闭包。 4. 闭包与变量 # 有很多新手为DOM元素绑定事件时,通常会这么写:function bindClick(){ var li = document.getElementsByTagName('li'); // 假设一共有5个li标签 for(var i=0; ibindClick->匿名函数。可是这跟输出的i有关系么?有。作用域链中的每个变量对象保存的是对变量和方法的引用,而不是保存这个变量的某一个值。当执行到匿名函数时,bindClick()其实已经执行完毕了,变量i的值就是5,此时每个匿名函数都引用着同一个变量i。不过我们稍微修改一下,以满足我们的预期:/* // 错误,onclick绑定的是立即执行函数的返回值, // 而此立即执行并没有返回值,也就是onclick = undefined function bindClick(){ var li = document.getElementsByTagName('li'); for(var i=0; i
2024年10月21日
3 阅读
0 评论
0 点赞
1
...
12
13
14
...
125