共计 6259 个字符,预计需要花费 16 分钟才能阅读完成。
接触 JavaScript 两年多遇到过各种谬误,其中有一些让人防不胜防,原来对 JavaScript 的误会如此之深,仅以此文总结一下常见的各种想当然的误区
String replace
string 的 replace 办法咱们常常用,替换 string 中的某些字符,语法像这样子
string.replace(subStr/reg,replaceStr/function)
第一个参数是要查找的字符串或者一个正则表达式,第二个参数是想替换成的字符串或一个办法,咱们能够这么应用
“I’m Byron”.replace(“B”,”b”) // I’m byron
记功和咱们想得一样,然而
“I’m a student, and you?”.replace(“n”,”N”); // I’m a studeNt, and you?
和咱们预期的不一样,第二个‘n’没有被替换。字符串的 replace 办法如果第一个参数传入字符串,那么只有第一个匹配项会被替换。如果要替换全副匹配项,须要传入一个 RegExp 对象并指定其 global 属性。
“I’m a student, and you?”.replace(/n/g,”N”); // I’m a studeNt, aNd you?
这样才能够达到咱们目标.
typeof
对于 typeof 最容易让人误会的就是 typeof 是操作符,并不是函数,也就是说咱们在判断一变量类型时没必要加括号,间接应用即可
typeof 1; //number
typeof(1); //number, 没必要这么写,然而也没错,等于是给变量或常量包装了一下
typeof 的返回值是字符串,在大多数状况下返回的和咱们预期后果是一样的,然而有几点留神的中央, 咱们晓得 JavaScript 有几种根本类型,number、string、boolean、null、undefined,再就是对象 object 了,咱们看几个例子
typeof 123; //number
typeof NaN //number
typeof “123” //string
typeof false; //boolean
typeof undefined ; //undefined
typeof null //object
typeof new Array(); //object
typeof (new Array()); // 感觉不够清晰能够这么用,后果是一样的
typeof (function(){}); //function
typeof a; //undefined
- 123 是个数字返回 number
- 尽管 NaN 示意不是数字,然而 typeof 依然会返回 number
- “123”变成了字符串,所以返回 string
- false 类型就是 boolean
- undefined 的类型就是 undefined,这个类型的变量只能有一个字面值”undefined”
- null 的类型并不是 null,而是 object,所以咱们不要寄心愿与 typeof 帮咱们判断 null
- typeof 如果判断是对象只会返回 object, 而不会返回 Array、Date 的具体类型
- function 也是 object 的一种,按说也应该间接返回 object。然而 typeof 对它区别对待了,返回了 function,咱们能够用此判断变量是否为函数
- 没定义的变量同样返回 undefined
if 和 ==
在 javascript 中 if 并不仅仅判断 boolean 决定虚实,0、NaN、””、undefined、null、false 都会被认为是假
if (!false) {
console.log(1);
};
if (!0) {
console.log(2);
};
if (!””) {
console.log(3);
};
if (!undefined) {
console.log(4);
};
if (!null) {
console.log(5);
};
if (!NaN) {
console.log(6);
};
在 console 中 123456 都会被打印进去
然而这并不意味着这些值就 ==false
0==false; //true
“0”==false; //true, 这个也是 true
undefined==false //false
null==false //false
null==null //true
NaN==NaN //false
null==undefined //true
纳尼!!!
相等运算符(==、!=)
如果两表达式的类型不同,则试图将它们 转换为字符串、数字或 Boolean 量 。NaN 与包含其自身在内的任何值都不相等。
负零等于正零。null 与 null 和 undefined 相等。
雷同的字符串、数值上相等的数字、雷同的对象、雷同的 Boolean 值或者(当类型不同时)能被强制转化为上述情况之一,均被认为是相等的。其余比拟均被认为是不相等的。
所以说 0==”0”; 返回的也会是 true。
那么应该则么判断两个变量到底是不是一回事儿呢
恒等运算符(===、!==)
除了不进行类型转换,并且类型必须雷同以外,这些运算符与相等运算符的作用是一样的,这下就搞定了。
Date 对象
咱们能够这样结构一个 Date 对象
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)
前三种形式没有什么问题,但第四种失去的后果回合咱们预期的不统一
new Date(2013,08,02) //Date {Mon Sep 02 2013 00:00:00 GMT+0800 (China Standard Time)}
咱们能够看到,传入的月份是 08,返回的后果却是九月。这是因为 Date 对象的月份是从 0 开始计数的(天却不是),即 0 代表一月,1 代表二月…11 代表 12 月。在调用 Date 实例的 getMonth 办法时尤其要留神
var d = new Date(2012, 4, 15); // 2012 年 5 月 15 日
alert(d.getMonth()); // 后果为 4
Date.parse
Date.parse 办法能够辨认两种格局的字符串参数_(规范的长日期格局,比方带星期的那种,也能够辨认,不过不罕用)_:
- “M/d/yyyy”: 美国的日期显示格局。如果年传入 2 位则作为 19xx 解决
2.”yyyy-MM-dd” 或 “yyyy/MM/dd”: 留神月和日都必须是两位
Date.parse 的返回后果不是一个 Date 对象,而是从 1970-01-01 午夜(GMT)到给定日期之间的毫秒数。能够用 Date 的构造函数将其转换为 Date 对象。
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 用来遍历一个对象中的成员(属性,办法),如果用来遍历数组的到的后果并不是预期中数组每项的值,办法神马的会被遍历进去
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。
当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会依据 string 来判断数字的基数。
举例,如果 string__(结尾结尾空格主动省略) 以 “0x” 结尾,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 结尾,那么 ECMAScript v3 容许 parseInt() 的一个实现把其后的源码交易字符解析为八进制或十六进制的数字。如果 string 以 1 ~ 9 的数字结尾,parseInt() 将把它解析为十进制的整数。如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 NaN。
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() 何时被调用执行
预解析
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”(这句是程序执行的,在第二句之后执行)。这也是为什么咱们能够在办法申明语句之前就调用办法的起因。
showMsg(); // This is message
function showMsg()
{
alert(‘This is message’);
}
块级作用域
JavaScript没有块级作用域,只有函数级作用域,这就意味着 {} 在 JavaScript 中只能起到语法块的作用,而不能起到作用域块作用
if(true){// 语法块,保障 {} 内代码 if 条件成立执行
//…
var a=3;
}
console.log(a); //3
下面例子能够分明看到属于 window 的 console.log 办法仍然能够拜访貌似是局部变量的 a
闭包
首先从一个经典谬误谈起,页面上有若干个 div,咱们想给它们绑定一个 onclick 办法,于是有了上面的代码
<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>
$(document).ready(function() {
var spans = $(“#divTest span”);
for (var i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
alert(i);
}
}
});
很简略的性能可是却偏偏出错了,每次 alert 出的值都是 4,简略的批改就好使了
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 的垃圾收集器能力开释相应的内存空间。