精华内容
下载资源
问答
  • 5个 JavaScript 怪异行为及其原因

    千次阅读 多人点赞 2020-12-19 20:39:51
    如果你用 JavaScript 写过项目或者参加过面试,那一定遇到过不少令人匪夷所思的问题。JavaScript 早期的规范不统一,也没有严格的标准,再加上它的语法灵活多样,有些看起来就不正确的代码却能正常执行,一些看起来...

    如果你用 JavaScript 写过项目或者参加过面试,那一定遇到过不少令人匪夷所思的问题。JavaScript 早期的规范不统一,也没有严格的标准,再加上它的语法灵活多样,有些看起来就不正确的代码却能正常执行,一些看起来符合逻辑的代码,运行结果却相差十万八千里。这些问题在日常开发中经常会导致 BUG,更重要的是,很多面试官会把它们拿出来当考验咱们 JS 工程师的能力。那么这篇文章就总结了 5 个 JavaScript 比较坑的问题,以及它们出现的原因和解决方法。

    1、可选分号

    问题:

    function foo() {
    	return 
      {
         value: 1
      };
    }
    console.log(typeof foo());
    

    你可能会认为它的输出结果是 “function”,但是结果却是 undefined。乍一看代码好像没什么问题,但是细心一点可以看到 return 语句返回的对象放到了下一行,那么问题就来了:JavaScript 的分号是可选的,return 语句在换行后,JavaScript 会自动给它的结尾加上分号,而在 return 之后的代码都不会执行,所以 foo() 的返回结果是 undefined。解决方法是在每行结尾都写上分号,这样就能清楚的知道代码在哪里结束。

    2、this 指向

    问题:

    var a = 5;
    var obj = {
    	a: 3,
      foo: function() {
        console.log(this.a);
      }
    }
    
    var objFoo = obj.foo;
    objFoo();
    

    答案为 5。在调用函数时,它内部的 this 指向的是调用对象,例如 obj.foo() this 指向的是 obj 对象。如果在全局调用函数时, this 指向的是全局对象,在浏览器中为 window。objFoo 相当于是在获取了 obj 对象的 foo 方法引用后,在全局进行调用,所以 this 指向的是 window 对象。使用 var 在顶级作用域中定义的变量会添加到 window 中,所以 objFoo() 调用打印的是全局中的 a,即 5。

    3、数组长度

    问题:

    const arr = [1, 2, 3, 4];
    arr.length = 0;
    console.log(arr[0]);
    

    结果为 undefined, 因为 array 的 length 属性同时也能反过来控制数组的元素数量,在给 arr.length 设置为 0 时,arr 就变成了空数组,再访问里边的元素就都是 undefined 了。

    4、提升(Hoisting)

    问题:

    function bar() {
      return foo;
      foo = 10;
      function foo() {}
      var foo = '11';
    }
    console.log(typeof bar());
    

    结果为 function。使用 var 声明的变量和使用 funtion 定义的函数会提升到当前作用域的顶部,所以变量可以先赋值,后使用 var 进行声明,而函数则可以先调用后定义。但是要注意的是,使用 var 定义(指在声明的同时进行赋值)的变量,只会提升声明部分,赋值部分不会被提升,例如示例中的 var foo = '11' 会提升 var foo,但 foo = 11 保留在原位。在定义 bar() 函数时,同时会创建一个作用域,提升会把相关变量和函数放到 bar() 函数的第一行。 综合上边的规则,可以知道 foo() 函数和 foo 变量的声明进行了提升,因为 foo 变量与同名,但是只有声明,所以不会覆盖函数的值,foo 仍然指向的是函数。之后就直接使用 return 语句返回了结果,后边的代码就不会再执行了。bar() 中的代码其实是下边这种形式:

    function bar() {
      function foo() {}
      var foo;
      return foo;
      foo = 10;
      var foo = '11';
    }
    

    5、作用域与闭包

    问题:

    for(var i = 0; i < 3; i++) {
      setTimeout(() => {
        console.log(i);
      });
    }
    

    你可能会认为上方代码的结果为 0 1 2,但实际上是 3 3 3,这是因为使用 var 关键字定义的变量没有块级作用域,在 for 循环中定义的 i 相当于是全局变量,它会添加到 window 变量中,即使在 for 循环退出后也能访问 i 的值。这样就导致了一个问题,使用 setTimeout() 推迟的函数会在 for 循环结束后才执行,此时 i 的值已经变成 3 了,所以 3 个 setTimeout() 中的函数都会打印出 3。要解决这个问题有两种方法。

    第 1 种是使用 let 关键字定义变量 i,这样在每次循环时,都会创建一个新的作用域,因此每个作用域中的 i 是相互独立的,这样就能打印出 0 1 2

    第 2 种方法是使用自执行函数,例如下边代码这样:

    for(var i = 0; i < 3; i++) {
    	(function(i) {
        setTimeout(() => {
          console.log(i);
        })
      })(i)
    }
    

    这时,i 通过参数传递给了匿名的自执行函数,同时自执行函数创建了一个闭包,所以它会捕获 i 的值,相当于在内部复制了参数 i 的值,所以无论外边的 i 怎么变化,它内部的值都不会发生改变。这样也能打印出 0 1 2

    小结

    这 5 个问题揭露了 JavaScript 中常见的一些坑,稍微不注意就会留下隐患,并且难以察觉,例如一个简单的换行、 this 指向的改变、意外修改数组的长度、变量和函数提升、作用域的创建都有可能出现异外的情况。这些问题可能在日常开发中并不多见,但是经常会出现在 JS 笔试和面试中,用于考察面试者对 JS 的熟悉程度。另外, JS 中的坑远不止这些,所以需要在日常中多积累,另外也可关注本博客,我会不定时的更新 JavaScript 使用上的问题,感谢!

    欢迎访问我的博客访问更多内容!

    展开全文
  • parseInt() 的怪异行为 parseInt(numericalString)始终将其第一个参数转换为字符串(如果不是字符串),然后将该数字字符串解析为整数值。 这就是为什么你可以(但不应该)使用parseInt()提取浮点数的整数部分的...

    作者:Joe Seifi
    译者:前端小智
    作者:Dmitri Pavlutin

    有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

    本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

    parseInt()是内置的 JS 函数,用于解析数字字符串中的整数。 例如,解析数字字符串'100'

    const number = parseInt('100');
    number; // 100
    

    如预期的那样,'100'被解析为整数 100

    parseInt(numericalString, radix)还接受第二个参数:从 2 到 36,表示字符串的基数。例如指定 16 表示被解析值是十六进制数。请注意,10 不是默认值,最常见的是 2、8、10 和 16。

    例如我们使用 parseInt 以二进制方式解析数字字符串:

    const number = parseInt('100', 2);
    number; // 4
    

    100 对应的二进制数是 4,所以返回 4。

    1. parseInt() 的怪异行为

    parseInt(numericalString)始终将其第一个参数转换为字符串(如果不是字符串),然后将该数字字符串解析为整数值。

    这就是为什么你可以(但不应该)使用parseInt()提取浮点数的整数部分的原因:

    parseInt(0.5);      // => 0
    parseInt(0.05);     // => 0
    parseInt(0.005);    // => 0
    parseInt(0.0005);   // => 0
    parseInt(0.00005);  // => 0
    parseInt(0.000005); // => 0
    

    提取浮点数的整数部分,如0.50.05等,结果为0, 这和预期的一样。

    那提取0.0000005的整数部分怎么样?

    parseInt(0.0000005); // => 5
    

    parseInt() 将浮点数 0.0000005 解析为 5。为什么 parseInt(0.0000005) 有这样一个怪异的行为?

    2.解决parseInt()怪异行为

    我们再看一看 parseInt(numericalString) 的第一个参数:如果它不是字符串,则将其转换为字符串,然后解析,并返回解析后的整数。

    这可能是第一个线索。

    然后,我们尝试将浮点数手动转换为字符串表示形式:

    String(0.5);      // => '0.5'
    String(0.05);     // => '0.05'
    String(0.005);    // => '0.005'
    String(0.0005);   // => '0.0005' 
    String(0.00005);  // => '0.00005'
    String(0.000005); // => '0.000005'
    
    String(0.0000005); // => '5e-7'
    

    显式转换为string(0.0000005)字符串的行为与其他浮点数不同:它的表示方式是用指数的形式。

    这是第二个重要的线索!

    当指数符号被解析为整数时,我们会得到数字5

    parseInt(0.0000005); // => 5
    // same as
    parseInt(5e-7);      // => 5
    // same as
    parseInt('5e-7');    // => 5
    

    parseInt('5e-7')考虑第一个数字'5',但跳过'e-7'

    谜团已揭开! 因为 parseInt() 始终将其第一个参数转换为字符串,所以小于10负6次方的浮点数将以指数表示。 然后 parseInt() 从 float 的指数表示法中提取整数。

    另外,为了安全地提取浮点数的整数部分,建议使用 Math.floor() 函数:

    Math.floor(0.5);      // => 0
    Math.floor(0.05);     // => 0
    Math.floor(0.005);    // => 0
    Math.floor(0.0005);   // => 0
    Math.floor(0.00005);  // => 0
    Math.floor(0.000005); // => 0
    
    Math.floor(0.0000005); // => 0
    

    3.总结

    parseInt() 是将数字字符串解析为整数的函数。

    尝试使用parseInt()提取浮点数的整数部分时必须小心。

    小于10的-6次方 (例如0.0000005,也就是5*10-7)的浮点数转换成字符串时被写成指数表示法(例如5e-7是0.0000005的指数表示法)。这就是为什么在 parseInt() 中使用这么小的浮点数会导致意想不到的结果:只有指数表记的重要部分(例如 5e-7 中的 5)会被解析。

    那么现在大家可以试着解释为什么 parseInt(999999999999999999999)等于1?

    完,我是刷碗智,去保健了,下期见


    代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

    原文:https://dmitripavlutin.com/parseint-mystery-javascript/

    交流

    有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

    本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

    展开全文
  • js new Date怪异行为

    2018-11-22 12:19:38
    new Date('2018-12-9') Sun Dec 09 2018 00:00:00 GMT+0800 (CST) new Date('2018-12-10') Mon Dec 10 2018 08:00:00 GMT+0800 (CST) 为什么两个日期new出来的hour会不相同 答案: www.xuanfengge.com/js-date-obj... ...

    new Date('2018-12-9') Sun Dec 09 2018 00:00:00 GMT+0800 (CST)

    new Date('2018-12-10') Mon Dec 10 2018 08:00:00 GMT+0800 (CST)

    为什么两个日期new出来的hour会不相同

    答案: www.xuanfengge.com/js-date-obj…

    转载于:https://juejin.im/post/5bf69eb5e51d457b027ab799

    展开全文
  • 但进入页面后页面不断的触发以上方法,刷新页面,这个webkit的对popstate的诡异行为导致的。 对这个差异的认知就是webkit中诡异行为的原因。webkit并没有把HTML5的History和传统的区分开,而根据官方文档对...

    由于ios的性能在缓存页面比较好,所以一般页面的后退都会保存之前的历史页面,

    不会触发页面上的js等,所以可以触发到popstate事件,而webkit的某些版本对popstate

    的理解与官方标准不一致,导致每次访问页面都会同步为访问了这个页面的历史纪录,

    所以popstate就被触发了,而在项目中需要IOS一个后退刷新页面

    代码:

    window.addEventListener('popstate', function() {
        window.location.reload();
    });
    

      

    但进入页面后页面不断的触发以上方法,刷新页面,这个webkit的对popstate的诡异行为导致的。

    对这个差异的认知就是webkit中诡异行为的原因。webkit并没有把HTML5的History和传统的区分开,而根据官方文档对popstate的描述,只要访问历史记录就会触发popstate。而传统的History中访问页面和生产历史记录是同时的。所以在webkit中,无论是刷新还是访问一个新网页都会触发popstate。而其它浏览器中这个popstate仅作用于HTML5的History,并不响应传统的History,更不用说刷新和访问新网页的情况了。

    解决方法:
      延迟事件加载,让页面上加载完成后才进行popstate事件加载。
     
    window.οnlοad=function(){
      setTimeout(function(){
      window.addEventListener('popstate', function() {
        window.location.reload();
    });  
    },0)  
    }
    

      

     

    转载于:https://www.cnblogs.com/zhangzhicheng/p/9508742.html

    展开全文
  • 与爱因斯坦的《科学量子纠缠》(QE)和纳加拉胡纳(《东方哲学家》)的《太阳穴》(Sunyata)的概念相吻合的是,GH Mead和CH Cooley是社会行为主义者的理论,它们强调了社会对自然的肯定的重要性。 这项工作将表明,...
  • sprintf的怪异行为

    2015-05-06 15:27:02
    在一次开发中,需要用到数字转换字符串,总所周知使用sprintf就可以完成。而且网上也有好多关于缓冲区要足够大,否则会出现问题。 MSDN中在Remarks中有这么一句话:If copying occurs between strings that overlap...
  • setState可以说是React中使用频率最高的一个函数了,我们都知道,React是通过管理状态来实现对组件的管理的,当this.setState()被调用的时候,React会重新调用render方法来重新渲染UI 但实际使用的时候,我们会发现...
  • 其实也不算是怪异吧,主要还是自己对table用的较少,没有掌握得比较好而已。具体经过如下: 项目中需要做一个页面,效果如下: 本也没有什么大的问题,关键就是设置好td的“colspan”和“rowspan”,但是做出来的...
  • IE下,将input的父级标签增加 disabled 属性之后,input 的行为变得怪异: 1、input 背景变灰,疑似也被disabled 了。 2、input 仍然可以输入英文数字等字符,但无法切换输入法,无法粘贴 其他浏览器不受影响。 ...
  • [code="ruby"] cvs = ["a",""]; #第一种空格 cvs (3, "") # 第二种空格 cvs.flatten!() puts cvs.inspect cvs.collect! do |item| item.insert(0,"\""); end puts cvs.inspect [/code] ...
  • <!-- @page {margin:2cm} p {margin-bottom:0.21cm} ... 当今,在美国市场上什么怪事都会发生,谷歌Android向微软大送专利税金便是一例。... 1月12日,微软与LG集团又达成一项有关微软专利侵权赔偿的新协议,并且...
  • 在偶然一次执行Oracle 9i的left outer join查询时,发现了一些匪夷所思的问题,在此贴出来和大家讨论一下。先创建一些表和记录来模拟当时的情况: create table temp_test1 ( a num
  • 作者 | 张旭乾 责编 | 欧阳姝黎如果你用 JavaScript 写过项目或者参加过面试,那一定遇到过不少令人匪夷所思的问题。JavaScript 早期的规范不统一,也没有严...
  • 详解 TypyScript 的一个怪异行为

    千次阅读 2020-02-15 10:21:29
    最近我在阅读 Asana 的博客时,看到了一篇关于 TypeScript 怪异行为的文章(https://blog.asana.com/2020/01/typescript-quirks/),文中提到的第一条 TypeScript 的怪异行为引起了我的兴趣。 尽管看上去似乎前后不...
  • 中新网4月9日电 新加坡《联合早报》今日刊发评论,分析中国房价上涨的三个原因:国际游资的进入,地方政府的“托市”,以及不良开发商的“怪异行为”。文章认为,应建立民生状况与官员任免直接关联的机制,打击开发...
  • 分类: Unity3D2012-07-23 16:07 2410人阅读 评论(0) 收藏 举报 vectoruilist ...但不知道为什么,Unity却没有把它做好,让他的行为十分怪异。 我们可以做以下实验 建立一个Vector2类
  • var str = "Visit W3Schiool"; var patt1 = /i[\w]+/g; var patt2 = /(i[\w]+)/; var result1 = patt1.exec(str); var result2 = patt2.exec(str); var result3 = patt1.exec(str); patt1.lastIndex=0;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,531
精华内容 5,812
关键字:

怪异行为