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

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

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

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

问题描述

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

代码演示:

var funcArr = [];
for(var i=1;i<=10;++i){
    var func = function(){
        console.log("这是第 "......

阅读更多

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对象,用来获取传递来的所有参数。
因此最开始我写了如下的代码:

function test(){
    for(var i = 0;i<arguments.length;++i){
        console.log(arguments[i]);
    }
}

test(1,2,3);//打印出1 2 3

test(4,5,6,7);//打印出4 5 6 7

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

阅读更多

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

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

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

例一:

function fun() {
  var num = 5;
  var say = function() { console.log(num); }
  num++;
  return say......

阅读更多

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

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

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

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

接下来看代码:

最熟悉的for循环:

var arr = [1,2,3,4,5,6,7,8,9,10];

for(var i=0;i<arr.lengt......

阅读更多

JavaScript预编译以及变量提升

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

为什么要说是陷阱呢?

一、JavaScript预编译

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

var str = '123';
f();
function f(){
    console.log(str);
}

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

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

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

这是因为JavaScript代码在运行……

阅读更多

JavaScript深入理解闭包

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

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

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

阅读更多

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

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

这是书中的介绍。

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

function change(arg){
    arg = 'changed';
}
var a = 1;
change(a);
console.log(a)
//输出
1

这里定义了一个函数change,函数将传来的参数arg的修改为字符串’changed’,之后定义了变量a,并赋值为1,将a传递给函数change,如果js的参数传递是值传递,那么arg只是a的一个拷……

阅读更多