(七)严格模式
①ECMAScript5 引入了严格模式(strict mode)的概念。
严格模式是为JavaScript定义了一种不同的解析与执行模型,在这种模式下,ECMA3Script中的一些不确定的行为将得到处理,对不安全的操作也会抛出错误。
②启用方法:
整个脚本:
顶部添加 “use strict”
某个函数:
函数内部的第一行(花括号之后的第一行)添加 “use strict”
③兼容严格模式的浏览器:IE10+、FireFox 4+、Safari 5.1+、 Opcra 12+和Chrome
④在严格模式下,很多原本可以正常跑的代码,都不可以了,会抛出异常,或者结果有所区别。典型的就是:
function test(value) {
"use strict"
value = 7;
console.log(value, arguments[0]);
}
function test2(value) {
value = 7;
console.log(value, arguments[0]);
}
test(10);
test2(10);
严格模式的结果是7,10;
非严格模式的结果是7,7;
原因在于,非严格模式对参数的操纵会影响arguments中的值,而严格模式是不影响的。
参考链接:
http://www.xiabingbao.com/javascript/2015/02/14/javascript-strict
(八)变量的声明
应避免以下这种声明方式:
function test() {
var a = b = 1;
}
test();
console.log(b);
原因在于,这种情况下,变量a的作用域是代码块,脱离函数后被成功销毁;
但变量b变成了全局变量,在console.log(b)中可以正确的显示其结果。
但以下这种声明方式是可以的:
function test() {
var a = 1,
b = 1;
}
(九)变量,类型
①typeof
注:输出结果都是字符串,因此可以在if语句里用===某个字符串来匹配是否是某个类型
typeof以下类型变量 | 输出结果 |
声明未赋值/未声明变量 | undefined |
布尔值 | boolean |
数值 | number |
对象或者null | object |
函数 | function |
②null和undefined
null == undefined 返回值为true;
null === undefined 返回值为false
原因在于,undefined是null派生而来的。
③boolean
true == 1 返回值true
true == ‘1’ 返回值true
true === 1 返回值false
false同理
Boolean('')和Boolean(' ')的值,分别是false和true
Boolean是一个布尔类型的强制转换函数
转换后为false 的:(1)空字符串;(2)数字0;(3)null;(4)NaN;(5)undefined;(6)false本身
放在if等判断语句里,会自动转换;
④number
(1)八进制:赋值时,0开头,且符合要求(例如每位数字都在0~7之间),如果数字超出,忽略开头的0,当做10进制解释(不使用数字除外,会出错);
八进制严格模式下(“use strict”)无效
十六进制:赋值时,0x开头(或0X),如果使用非范围内数字字母,会出错,字母可大写可小写;
十进制:其他正常赋值时。
计算时,会转为十进制来计算。
(2)浮点数:即小数;
l 存在精度问题(17位);
l 末尾0很多时(var a = 0.000000000000000000001或var a = 10000000000000000000000)会被转化为1e然后后面跟一个整数或者负数;
l 不要计算两个浮点数相加后和另外一个浮点数他们之间的结果是否相等(0.1+0.2 == 0.3的结果是false,其值为0.30000000000000004),除此之外还有0.1+0.7结果是0.7999999999999999等
l 最小值大概是5e-324,最大值是1.7xxxx e+308。假如某次计算超出这个数值,会转换为Infinity(正无穷)或 -Infinity(负无穷);Infinity减去或除以Infinity的结果是NaN,乘以或者加上依然是Infinity;Infinity - 1结果还是Infinity;Infinity*0结果是NaN,/0结果是Infinity;1/0结果也是Infinity(火狐和chrome,其他未验证),而不是书上说的NaN,但0/0是结果是NaN
(3)NaN 非数值,是一种特殊的数值
0/0结果是NaN,其他数值除以0则不是;
NaN == NaN 的结果是false,包括三个等号的结果
isNaN()可以用于测试一个数值是否是NaN,能被转化为数值的为false(比如字符串),不能转化为数值的为true,比如字符串为true,true/false为false,undefined为true等;
可以检测对象,但并非必然是true。检测方式是调用对象的valueOf()方法,之后是toString(),根据其值决定是true还是false(有一个为false即为false,都是true才是true),;空对象返回true,但例如以下情况则返回false:
var a = {}; //true
var a = { valueOf: 1}; //true
var a = { valueOf: function(){return 1}}; //false
var a = { toString: function(){return 1;}} //false
var a = { toString: function(){return "a";}} //true
(4)数值转换
三个转换函数:Number(), parseInt(), parseFloat()
Number()
源 | 目标 |
true/false | 1或0 |
数字 | 返回数字 |
null | 0 |
undefined | NaN |
字符串:纯数字 | 作为十进制数字转换,忽略开头0,因此不存在八进制识别 |
字符串:浮点数(无其他干扰) | 浮点数 |
字符串:十六进制格式 | 十六进制数识别,然后转换为十进制 |
字符串:空 | 0 |
字符串其他:例如在以上情况下有其他字符干扰 | NaN |
parseInt()
源 | 结果 |
字符串开头有非0~9非空格字符 | NaN |
空格开头的字符串 | 忽略空格后看上一行,不符合的话看下一行 |
0x开头后面跟数字比如0x1 | 当十六进制数字识别,剩下的看第六行 |
失效 |
实际测试失效,例如parseInt("070") 返回70而不是56 |
普通数字开头 | 当做十进制数字识别 |
数字后跟字母或空格 (重要) | 如果是十六进制数,遇见非a~f字母后,从该位置开始忽略后面的; 如果是十进制数字,遇见字母后,从第一个字母开始忽略后面的 |
小数 | 识别为整数 |
当parseInt()当存在第二个参数时,第二个参数用于作为转换时的基制,即多少进制;假如以下是
例如parseInt("11",2)的结果是3,parseInt("11",11)的结果是12。前者是作为二进制识别,后者是作为十一进制识别。
第二个参数为1时NaN,0则使用默认,当第一个参数不是十进制数字时,返回值为0,例如parseInt("0x11",2)作为二进制解析时,其值为0(x不能作为二进制识别);
0x开头的,第二个参数只能使用16(转换为十六进制),否则无法识别(正常识别,识别结果为0)。
当使用第二个参数时,则不会将其设法转换为十六进制,而是作为普通字符串来处理。
按照教程所说:
如果我们要默认其以某个进制来转换,应该显式的在第二个参数声明他,例如第二个参数写10,默认其为10进制,这样的话,当其看起来像16进制数字,可以避免用十六进制来解释
parseFloat()
和parseInt()类似的识别方式,只不过他会忽视开头的0或者空格,识别到非浮点数为止。也就是说,他不认十六进制或者其他。
例如:parseFloat("0x1.1")返回0(不识别十六进制);
parseFloat("0000.11")返回0.11(前面加若干空格结果也一样)
parseFloat(" 0 000.11")返回0,因为从开始识别的位置之后,他不会忽视空白字符。
⑤string类型
【1】转义字符:
字符 | 表示 |
\n | 换行 |
\t | 制表符 |
\b | 空格 |
\r | 回车 |
\f | 走纸换页 (然而并不明白所以给个搜索链接https://www.google.com/#newwindow=1&q=%E8%B5%B0%E7%BA%B8%E6%8D%A2%E9%A1%B5) |
\xnn | nn是十六进制字符,x需要小写。需要2位n。 用于表示字符,其是ASCII字符集,比如41转换为十进制为65,ASCII中65表示A |
\unnnn | 类似上面,x小写,n十六进制,四位n都要有,表示Unicode字符集。 |
对象无toString方法 | "[object Object]" |
对象有toString方法 | toString方法的返回值 |
【2】.length属性
字符串都有;
不能正确识别汉字是两个字符的长度;
转义字符是转义后的长度。例如”\x41”表示字母A,他的长度则为1
【3】其他类型转为字符串:
(1)调用toString()方法;
l .toString()方法在加上参数后,可以将一个数字转换为2~36进制中的任何一个;例如:(113).toString(30)的返回值是"3n"
l true转为”true”;
l 普通数字转为数字;
l 十六进制数字转为10进制数字后输出。例如:(0x1a).toString()返回26
l null和undefined没有这个方法,会出错。
l 字符串本身也有这个方法。但这个方法不能被覆写。例如var a=”a”;a.toString = function(){return "b"}; 这个时候再调用a.toString(),则返回值依然为”a”,而不是”b”
(2)使用String()方法,被转换的变量作为参数
假如一个方法有toString()方法,则调用之;
假如没有(只剩null和undefined),则null变为”null”,undefined变为”undefined”
(3)通过+号连接符,隐式调用toString方法
比如说拼接;
var a={};
a.toString = function(){return "bb"}
a+”aa”的返回值是”bbaa”
⑥object对象
【1】每个object对象都具有的方法:
(1)constructor:显示一个对象构造函数的方法;
用例一:查看某个对象的构造函数。
假如有一个我们自定义的函数
function test(a, b) {
this.a = a;
this.b = b;
}
我们new一个他的实例
var m = new test();
这个时候m的constructor是什么呢,就是上面那个函数;
用例二:
我们如何判断一个对象是否是某个类的实例,很简单,就像在上面那样,调用constructor属性和原类进行比值(可以用三个等号)。
例如:
function test(a, b) {
this.a = a;
this.b = b;
}
var m = new test();
console.log(m.constructor === test);
其返回子是true
类似,数组的constructor的值是Array(没有引号),字符串是String,数字是Number,布尔值是Boolean
var test = new Array;
console.log(test.constructor === Array);
【2】hasOwnPrototype(“某属性”)
(1)用于检测某个对象的实例是否具有某个属性;
(2)只检测当前实例有没有,跟原型有没有无关;
(3)原型链上继承来的属性无法检测到。
示例:
function test(a) {
this.a = a;
}
var m = new test(1);
console.log(m.hasOwnProperty("a")); //检测有没有a属性,原型有,所以有
console.log(m.hasOwnProperty("b")); //检测有没有b属性,原型没有,目前没有
m.b = function(){};
console.log(m.hasOwnProperty("b")); //检测有没有b属性,原型没有,但后来赋值了,所以有
返回值依次是:true, false, true
证明了(1)和(2)
function test(a) {
this.a = 1;
}
var a = new test();
test.prototype.test2 = function () {
return "1";
}
console.log(a.test2());
console.log(a.hasOwnProperty("test2"));
返回值依次为1和false
说明实例的原型继承到的方法,是被实例所继承的,但是无法通过hasOwnPrototype来检测。
扩展:
之前的情况,可以通过in来检测,例如;
console.log("test2" in a);
返回值为true
for in方法也是可以检测到的
for (var i in a) {
console.log(i)
}
输出:a和test2
但据说老版本的浏览器上是不可以的,参照《for in的缺陷》:
http://www.cnblogs.com/snandy/archive/2011/03/03/1970132.html
【3】obj1.prototype.isPrototypeOf(obj2)
(1)用于检测调用这个方法的对象obj1,是否是参数obj2的原型;
例如:
function test(a) {
this.a = 1;
}
var b = new test();
console.log(test.prototype.isPrototypeOf(b));
返回值为true;
说明test是b的原型。
(2)************* 问题 *************:
按照说明,他会检查原型链上的继承,但我自己测试后,假如是继承,那么返回值依然为false,如下:
function test() {
}
function test2() {
}
test2.prototype.test = test;
var m = new test2();
console.log(test2.prototype.isPrototypeOf(m));
console.log(test.prototype.isPrototypeOf(m));
返回值依次为true和false
test的确在test2的原型链上,但是返回值为false。搞不懂。
也许是我搞错了原型链上的继承。
【4】.propertyIsEnumerable(属性名)
(1)检测某个属性能否使用for in语句来枚举,参数需要是字符串类型
(2)无视原型链上的内容(即无法检测原型链上的)
例如:
function test() { //原型
this.a = 1;
}
test.prototype.b = "test"; //test2方法是test的一个属性
var m = new test();
console.log(m.propertyIsEnumerable("b"));
console.log(m.propertyIsEnumerable("a"));
var n = {a: 1, b: 2};
console.log(n.propertyIsEnumerable("a"));
返回值依次为false,true,true
在这里,m是test的实例;b是test继承的一个属性;
因此,这两个都可以通过for in来显示,但由于a是test的属性,而b是通过继承来的,因此propertyIsEnumberable是无法检测到b的。故一个返回false,一个返回true
n有属性a,因此其返回值为true
【5】toLocaleString()
(1)返回对象的字符串表示;
(2)该字符串与执行环境的地区对应。
具体不太清楚,先放置吧,也许和下面的有关系?
【6】toString()
(1)返回对象的字符串表示。可以通过手动覆写的方法,使其可以用于对象可以和字符串相加,然后返回字符串。例如:
var m = {a: 1, b: 2};
m.toString = function () {
return "m";
}
console.log(m + "n");
返回值是字符串mn
此时:
console.log(m.toLocaleString());
输出的值也是字符串m
【7】valueOf()
(1)按照说明:返回对象的字符串、数值、或布尔值表示。通常与toString()的返回值相同。但并不是这样,个人觉得是和对象本身的值是一样的
例如:
var m = {a: 1, b: 2};
console.log(m.toString());
console.log(m.valueOf());
输出值是:字符串[object Object]和对象Object {a: 1, b: 2}
即使覆写m的toString()方法,valueOf()输出的值依然是Object {a: 1, b: 2}