JavaScript的一些常见误区
原文出处: 色拉油的博客
接触JavaScript两年多遇到过各种错误,其中有一些让人防不胜防,原来对JavaScript的误会如此之深,仅以此文总结一下常见的各种想当然的误区。
String replace
string的replace方法我们经常用,替换string中的某些字符,语法像这样子
1 |
string.replace(subStr/reg,replaceStr/function) |
第一个参数是要查找的字符串或者一个正则表达式,第二个参数是想替换成的字符串或一个方法,我们可以这么使用
1 |
"I'm Byron".replace("B","b") // I'm byron |
记过和我们想得一样,但是
1 |
"I'm a student, and you?".replace("n","N"); // I'm a studeNt, and you? |
和我们预期的不一样,第二个'n'没有被替换。字符串的 replace 方法如果第一个参数传入字符串,那么只有第一个匹配项会被替换。如果要替换全部匹配项,需要传入一个 RegExp 对象并指定其 global 属性。
1 |
"I'm a student, and you?".replace(/n/g,"N"); // I'm a studeNt, aNd you? |
这样才可以达到我们目的,关于string replace方法详细使用可以看看JavaScript string 的replace
Date 对象
我们可以这样构造一个Date对象
1 2 3 4 |
new Date() //Date {Fri Aug 02 2013 16:50:33 GMT+0800 (China Standard Time)} new Date(milliseconds) //Date {Fri Aug 02 2013 16:53:26 GMT+0800 (China Standard Time)} new Date("2013/08/02") //Date {Fri Aug 02 2013 00:00:00 GMT+0800 (China Standard Time)} new Date(year,month,day,hours,minutes,seconds,ms) |
前三种方式没有什么问题,但第四种得到的结果回合我们预期的不一致
1 |
new Date(2013,08,02) //Date {Mon Sep 02 2013 00:00:00 GMT+0800 (China Standard Time)} |
,返回的结果却是九月。这是因为Date对象的月份是从0开始计数的(天却不是),即0代表一月,1代表二月…11代表12月。在调用Date实例的getMonth方法时尤其要注意
1 2 |
var d = new Date(2012, 4, 15); // 2012年5月15日 alert(d.getMonth()); // 结果为4 |
Date.parse
Date.parse方法可以识别两种格式的字符串参数(标准的长日期格式,比如带星期的那种,也可以识别,不过不常用):
位则作为 19xx 处理
2."yyyy-MM-dd" 或 "yyyy/MM/dd": 注意月和日都必须是两位
Date.parse 的返回结果不是一个Date对象,而是从1970-01-01午夜(GMT)到给定日期之间的毫秒数。可以用Date的构造函数将其转换为Date对象。
1 2 3 |
new Date(Date.parse("8/2/2012")); // 正确识别为2012年8月2日 new Date(Date.parse("2012-08-02")); // 正确识别为2012年8月2日 new Date(Date.parse("2012-8-2")); // 不能识别 |
for…in 遍历数组
for…in用来遍历一个对象中的成员(属性,方法),如果用来遍历数组的到的结果并不是预期中数组每项的值,方法神马的会被遍历出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Array.prototype.contains = function(item) { for (var i = 0; i <= this.length - 1; i++) { if(this[i] == item) return this[i]; } } var staff = [ "Staff A", "Staff B" ]; // Normal Enumeration: Only the 2 items are enumerated for (var i = 0; i <= staff.length - 1; i++) { var singleStaff = staff[i]; alert(singleStaff); } // for...in Enumeration: the method "contains" are enumerated, too for (var singleStaff in staff) { alert(singleStaff); } |
事实上很多时候我们都会给数组加上其他属性。比如 jQuery 对象就是一个数组对象加上一些扩展方法;再比如 String.prototype.match 方法返回值就是一个数组(正则表达式及其子表达式的匹配项)加上 index 和 input 两个属性。
parseInt
语法: parseInt(string, radix)
参数 |
描述 |
string |
必需。要被解析的字符串。 |
radix |
可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 "0x" 或 "0X" 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。 |
,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。
举例,如果 string(开头结尾空格自动省略) 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 NaN。
1 2 3 4 5 6 |
parseInt("10"); //返回 10 parseInt("19",10); //返回 19 (10+9) parseInt("11",2); //返回 3 (2+1) parseInt("17",8); //返回 15 (8+7) parseInt("1f",16); //返回 31 (16+15) parseInt("010"); //未定:返回 10 或 8 |
setTimeout/setInterval执行时机
setTimeout()和setInterval()经常被用来处理延时和定时任务。setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式,而setInterval()则可以在每隔指定的毫秒数循环调用函数或表达式,直到clearInterval把它清除。
JavaScript其实是运行在单线程的环境中的,这就意味着定时器仅仅是计划代码在未来的某个时间执行,而具体执行时机是不能保证的,因为页面的生命周期中,不同时间可能有其他代码在控制JavaScript进程。在页面下载完成后代码的运行、事件处理程序、Ajax回调函数都是使用同样的线程,实际上浏览器负责进行排序,指派某段程序在某个时间点运行的优先级。
我们可以可以把JavaScript想象成在时间线上运行。当页面载入的时候首先执行的是页面生命周期后面要用的方法和变量声明和数据处理,在这之后JavaScript进程将等待更多代码执行。当进程空闲的时候,下一段代码会被触发
除了主JavaScript进程外,还需要一个在进程下一次空闲时执行的代码队列。随着页面生命周期推移,代码会按照执行顺序添加入队列,例如当按
钮被按下的时候他的事件处理程序会被添加到队列中,并在下一个可能时间内执行。在接到某个Ajax响应时,回调函数的代码会被添加到队列。JavaScript中没有任何代码是立即执行的,但一旦进程空闲则尽快执行。定时器对队列的工作方式是当特定时间过去后将代码插入,这并不意味着它会马上执行,只能表示它尽快执行。
关于setTimeout/setInterval执行时机详细说明可以看看 setTimeout()和setInterval() 何时被调用执行
预解析
1 2 3 4 |
console.log(a); //Error:a is not defined ,直接报错,下面语句没法执行,一下结果为注释该句后结果 console.log(b) //undefined var b="Test"; console.log(b);//Test |
很奇怪前两句变量a,b都没有声明,第一句却报错,第二句能够输出undefined?这是因为JavaScript 是解释型语言,但它并不是直接逐步执行的,JavaScript解析过程分为先后两个阶段,一个是预处理阶段,另外一个就是执行阶段。在预处理阶段 JavaScript解释器将完成把JavaScript脚本代码转换到字节码,然后第二阶段JavaScript解释器借助执行环境把字节码生成机械
码,并顺序执行。
也就说JavaScript值执行第一句语句之前就已经将函数/变量声明预处理了,var b="Test" 相当于两个语句,var b;(undefined结果的来源,在执行第一句语句之前已经解析),b="Test"(这句是顺序执行的,在第二句之后执行)。这也是为什么我们可以
在方法声明语句之前就调用方法的原因。
1 2 3 4 5 |
showMsg(); // This is message function showMsg() { alert('This is message'); } |
块级作用域
JavaScript没有块级作用域,只有函数级作用域,这就意味着{}在JavaScript中只能起到语法块的作用,而不能起到作用域块作用
1 2 3 4 5 |
if(true){//语法块,保证{}内代码if条件成立执行 //... var a=3; } console.log(a); //3 |
上面例子可以清楚看到属于window的console.log方法依然可以访问貌似是局部变量的a
闭包
首先从一个经典错误谈起,页面上有若干个div,
我们想给它们绑定一个onclick方法,于是有了下面的代码
1 2 3 4 5 6 |
<div id="divTest"> <span>0</span> <span>1</span> <span>2</span> <span>3</span> </div> <div id="divTest2"> <span>0</span> <span>1</span> <span>2</span> <span>3</span> </div> |
1 2 3 4 5 6 7 8 |
$(document).ready(function() { var spans = $("#divTest span"); for (var i = 0; i < spans.length; i++) { spans[i].onclick = function() { alert(i); } } }); |
,简单的修改就好使了
1 2 3 4 5 6 7 8 9 10 |
var spans2 = $("#divTest2 span"); $(document).ready(function() { for (var i = 0; i < spans2.length; i++) { (function(num) { spans2[i].onclick = function() { alert(num); } })(i); } }); |
闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数,只要存在调用内部函数的可
能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废
弃,JavaScript的垃圾收集器才能释放相应的内存空间。
这笔书的很肤浅,想简单了解闭包可以看看JavaScript 闭包究竟是什么
结束
关于JavaScript的坑坑洼洼真不少,一边学习一边总结吧。
JavaScript的一些常见误区的更多相关文章
- NODE.JS学习的常见误区及四大名著
NODE.JS学习的常见误区及四大名著 前段时间由于不满于社区里很多人对于NODE.JS的种种误解而写了一篇文章名为: NODE.JS之我见:http://www.cnblogs.com/pugang ...
- 绝对定位常见误区:position:absolute相对于谁定位、及当溢出时怎么隐藏
1.绝对定位元素溢出父元素,怎么隐藏问题? 通常,为了让DIV子元素超出部分隐藏,都是在父元素设置overflow:hidden,这样即可防止子元素撑开父元素,使子元素能够溢出隐藏! 但是,对于pos ...
- nginx反向代理跨域基本配置与常见误区
最近公司前后端分离,前端独立提供页面和静态服务很自然的就想到了用nginx去做静态服务器.同时由于跨域了,就想利用nginx的反向代理去处理一下跨域,但是在解决问题的同时,发现网上有些方案的确是存在一 ...
- (Frontend Newbie)JavaScript基础之常见数据类型
JavaScript中的数据类型分为两种,一种是简单数据类型,包括Undefined.Null.Boolean.Number和String,另一种是复杂数据类型,即Object,也可称作为引用类型. ...
- 【原创】C语言和C++常见误区(一)
本文仅在博客园发布,认准原文地址:https://www.cnblogs.com/jisuanjizhishizatan/p/15414469.html 问题1:int类型占几个字节? 常见误区:占4 ...
- oc常见误区
1.同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作, 2.异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然 ...
- JavaScript要点 (二) 使用误区
赋值运算符应用错误 注:赋值语句返回变量的值. 在 JavaScript 程序中如果你在 if 条件语句中使用赋值运算符的等号 (=) 将会产生一个错误结果, 正确的方法是使用比较运算符的两个等号 ( ...
- 也许是关于C#的一些常见误区
写这点东西主要是看到知乎上有人在讨论相关的问题,但是有不少人都在说一些不严谨,甚至是完全错误 但是流传甚广的东西,甚至是一些大神都在说,以下根据我的回答总结. 一个很常见又很低级的误区是:认为引 ...
- javascript:面向对象和常见内置对象及操作
本文内容: 面向对象 常见内置对象及操作 首发日期:2018-05-11 面向对象: JavaScript 是面向对象的编程语言 (OOP).OOP 语言使我们有能力定义自己的对象和变量类型. 对象是 ...
随机推荐
- SELINUX设为Disable 影响java SSH工具包Jsch 0.1.49.jar的一个案例
最近项目中遇到一个典型事件,当RHEL 的SELINUX设为DISABLE时 使用JAVA的Jsch 库调用SSH命令时将随机返回空字符串,我使用的版本是0.1.49,最新版本0.1.51未测试. 关 ...
- jboss 占用cpu 100%
通过Java thread dump分析找到耗费CPU最高的源代码 分类: 9. Java2010-04-11 23:06 9272人阅读 评论(4) 收藏 举报 threadjavaeclipse插 ...
- 有关npm rum的3个简洁技巧
[编者按]本文作者为来自 MongoDB 的 NodeJS 工程师 Valeri Karpov.Valeri 专注于维护常见的 Mongoose ODM,是<Professional Angul ...
- Delphi的Socket编程步骤
ClientSocket 和ServerSocket几个重要的属性: 1.client和server都有port属性,需要一致才能互相通信 2.client有Address属性,使用时填写对方 ...
- 线上问题 - MySQL SQL state [HY000]; error code [1366]
一.问题描述 另外一个系统调用服务接口api:/xxx/create?aName=&time=&...,数据没有保存成功提示SQL state [HY000]; error code ...
- EOF的一点注记
int ch; while( (ch = getchar()) != EOF ) { putchar(ch); } 执行程序,输入:we are the,然后回车.运行结果如下: [purple@lo ...
- linux ps命令详解
ps工具标识进程的5种状态码: D 不可中断 uninterruptible sleep (usually IO) R 运行 runnable (on run queue) S 中断 sleeping ...
- java反射机制浅谈
一.Java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...
- NPOI之Excel——合并单元格、设置样式、输入公式
首先建立一个空白的工作簿用作测试,并在其中建立空白工作表,在表中建立空白行,在行中建立单元格,并填入内容: //建立空白工作簿 IWorkbook workbook = new HSSFWorkboo ...
- mysql使用过程中碰到的问题
start job failed to start mysql ubuntu 原因时我将var整个目录的组权限设置为www-data了, 试了网上的办法都不行(有个妥协方法是重新安装, 但很不好), ...