踩坑 JavaScript循环中的闭包引起的问题

关于for循环中的闭包问题,其实早在之前我学习闭包的时候,就看过不下两篇文章提到过了,算是一个很经典的问题了。

尴尬的是,当同事叫我帮忙看这个问题的时候,我虽然一眼就看出了问题产生的原因,但是却死活想不起来解决方法,没办法只好又去google了一下才解决。

所以今天额外写一篇采坑记录加深印象

问题描述

问题产生的原因就是在for循环中使用了闭包,导致了“出乎意料”的结果。

代码演示:

像上面这一份代码,目的是创建10个函数,每个函数都打印自己生成时的序号。

那么在写这一份代码的时候,心里肯定已经有这样的预期输......

阅读更多

JavaScript 浅拷贝与深拷贝

这篇文章介绍一下js中的浅拷贝与深拷贝。

拷贝的意思就是把一个变量的值复制给另一个变量。

由于js中变量类型分为基础类型和引用类型,在对这两种类型进行copy时的结果会有截然不同的效果,因此在进行变量拷贝时需要多考量一下。

先简单的给浅拷贝和深拷贝下个定义:
浅拷贝就是复制一份对变量的引用,每个持有引用的对象都指向同一份内存空间,所以每个对象都可以修改内存空间中的值。
(就像几个人同时租了一套房子,房东给每个人都发了一把钥匙,有钥匙的人都可以进房子入住)
而深拷贝则是复制变量的值,对于非基本变量,则递归的为基本变量后再复制,复制完成后复制对象与原对象拥有不同的内存空间,因此修改复制对象将......

阅读更多

vue是如何实现双向绑定的

用过vue的开发者肯定都暗爽于双向绑定带来的便利,但是就像那句话说的一样

哪有什么岁月静好,只是有人替你负重前行。

虽然我们用的方便,那可是vue辛苦换来的。

这篇文章就来简单介绍一下vue是如何实现双向绑定的。

vue的双向绑定是通过数据劫持来实现的,而数据劫持的核心方法则是javascript语法中的Object.defineProperty()来实现的。

Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

defineProperty的语法为:

Object.defineProper......

阅读更多

miniRouter 一个前端路由的简单实现

之前介绍sprite框架的单页应用实现原理时,提到了单页应用的重要组成部分——前端路由。

本篇文章就介绍如何自己实现一个前端路由。

前端路由,顾名思义是由前端来实现路由控制。

简单来说路由控制就是一个url对应一个逻辑,请求不同的url将会得到不同的页面效果。

但是由于请求一个完整的url,会使得浏览器向服务器请求数据,并且刷新整个页面。如果只想刷新页面中的一部分,那么一次完整的http请求将显得有些浪费资源了。

所以就提出了前端路由的概念,采用改变并监听url的hash值,从而在前端实现路由的逻辑。由于url的hash值发生变化,不会使浏览器刷新页面,这意味着url的变化将不会......

阅读更多

JavaScript中的伪数组(array-like)

之前在项目里遇到一个问题:
调用某个函数时,传过来的参数是动态的,不能预先估计会传来多少个,因此我需要遍历函数的arguments对象,用来获取传递来的所有参数。
因此最开始我写了如下的代码:

通过一个for循环,遍历arguments对象,就可以取到每次调用该函数时传递的所有参数了。

我们都知道因为js是没有的块级作用域的,因此上面的函数在使用for循环时,会向该函数的作用域中增加一个额外的变量i,如果在之后的代码中又使用了变量i,某些情况就会导致错误,因此最好使用js提供的循环方法来替代for循环,例如forEach。......

阅读更多

有助于理解JavaScript闭包的几个例子

之前写过一篇详解js闭包的文章,后来重新读了一遍后感觉自己还是功力不够,很多知识点讲得都不够明白,文中举的例子也不够典型,而且动辄就是长篇大论,写了一大段文字却没有一个足够简单直白的例子,导致我自己再看的时候都觉得费劲。

功力不够,那就退而求其次,只好多找几个我觉得能够帮助更深刻地理解闭包的代码样例来分析。
(本次的例子都是我在stackoverflow上翻到的,然后加上了自己的解释)

例一:

这个例子在函数fun中创建了一个内部函数say,函数say中引用了函数fun中的变量num。定义了函数say后,对num这个变量......

阅读更多

JavaScript中的循环、遍历方法总结

最近写的js代码比较多,但是在做数组循环的时候,老是记不起来javascript提供用来遍历和循环数组的方法,又因为不想打断思路,就懒得去网上查,导致每次都很挫地直接写最原始的for循环。

这次回家来翻了翻书,做一个总结。

在javascript中遍历数组的方式很多,大概分为下面几种:
1. for
2. while
3. every
4. some
5. filter
6. forEach
7. map
8. for in

接下来看代码:

最熟悉的for循环:

for循环是每个程序员最熟悉不过的语法了,因此每次在需......

阅读更多

JavaScript预编译以及变量提升

本文介绍JavaScript中的两个小陷阱,预编译和变量提升。

为什么要说是陷阱呢?

一、JavaScript预编译

先说JavaScript预编译,来看看下面的例子:

可以猜猜看,上面的代码在执行f()时,是会提示:f is not defined 函数f未定义呢,还是打印出str的值“123”?

答案正常打印出str的值“123”。

但是从代码上面来看,在执行f()时,函数f明明都还没有被定义,为什么还能被执行呢?

这是因为JavaScript代码在运行时有预编译和执行两个阶段,JavaScript在执行js......

阅读更多

JavaScript深入理解闭包

谈到闭包,这是一个让很多非JavaScript程序员甚至JavaScript程序员都觉得充满着神秘感的词语,很多使用JavaScript的程序员也许在不知情的情况下,已经使用了闭包,但是并不知道闭包到底是个什么东西。

闭包这个东西,说难确实难,它算是js中一个比较高大上的概念,但是说不难其实也不难,如果能明白JavaScript执行环境和作用域链这两个核心概念,那么理解闭包也就水到渠成了,因为闭包正是通过执行环境和作用域链这两个概念衍生的。

(注:JavaScript执行环境和作用域链我在之前的博文《JavaScript执行环境、上下文、作用域链详解》里已经深入的介绍过,如果对这两个概念还......

阅读更多

JavaScript函数传参是传值还是传引用

ECMAScript中的所有参数传递的都是值,不能通过引用传递。
——《JavaScript高级程序设计》

这是书中的介绍。

下面通过一个例子来证实JavaScript函数传参,到底是传值还是传引用:

这里定义了一个函数change,函数将传来的参数arg的修改为字符串'changed',之后定义了变量a,并赋值为1,将a传递给函数change,如果js的参数传递是值传递,那么arg只是a的一个拷贝副本,对arg的任何操作都不会影响a,因此a的值就不会变为'changed',如果js的参数传递是引用传递,则对......

阅读更多