今天顶着头疼去做网易笔试题,果然考的一塌糊涂。虽然如此,里面有一道编程题还是让我记忆尤深。
题目的大致要求是计算最长子字符串长度。但是在编写程序的时候发现了一个奇怪的问题。
var s=11110101110+"";
console.log(s.charAt(0))//1
var s2=01111+"";
console.log(s2.charAt(0))//5
var s3=new String("011101")
console.log(s3.charAt(0))//0
var s4=String("011")
console.log(s4.charAt(0))//0
在s2
中,本应该输出结果为0
,但却输出了5
。
①number类型在进行类型转换之前就已经被改变了
②number类型在进行类型转换时被改变了。
var s=0111;
var s2=100;
var s3=0x11;
var s4=0b11;
console.log(s);//73
console.log(s2);//100
console.log(s3);//17
console.log(s4);//3
结果很明显,在Number对象把变量的值当成了八进制数值,在最后输出结果时再转成了十进制数值。
那么使用字面量创建变量对象是到底发生了什么?
要想知道字面量创建变量对象都发生了什么,就必须先了解字面量。
字面量一共7种,分别是
1.空值字面量: NullLiteral
2.布尔值字面量: BooleanLiteral
3.数值字面量: NumericLiteral
4.字符串字面量:StringLiteral
5.正则表达式字面量 : RegularExpressionLiteral
6.对象字面量:Object literals
7.数组字面量:ArrayLiteral
空值字面量和布尔值字面量都是比较简单,前者的字面量值只能是null
,而后者只能是true
或false
。
例如:
var s=null;
var s2=true;
var s3=false;
对于数值字面量,MDN和ES5给出了不同的解释。
ES5中数值字面量分为十进制值字面量(DecimalLiteral)和16进制值字面量(HexIntegerLiteral)。
MDN中数值字面量分为了整数字面量(Intergers)和浮点数字面量(Floating-point literals)
虽然两者内容上并无太大差异,但是从理解上来说,MDN的解释更加容易通俗易懂。
整数字面量包括以下几种:
①十进制整数
十进制整数字面量由一串数字序列组成,且没有前缀0。
②八进制整数
八进制的整数以 0(或0O、0o)开头,只能包括数字0-7。
严格模式下,八进制整数字面量必须以0o或0O开头,而不能以0开头。③十六进制整数
十六进制整数以0x(或0X)开头,可以包含数字(0-9)和字母 a~f 或 A~F。
④二进制整数:
二进制整数以0b(或0B)开头,只能包含数字0和1。
整数字面量判断过程如下:
1. 如果首个字符为非零整数,第2个字符不为“.”且后面为数字序列,那么该数字解析为十进制整数。
2. 如果首个字符是“0”(或0O、0o)且第2(3)个字符不为“.”且后面为数字序列,那么该数字被解析为八进制整数。
3. 同理,如果前两个字符是0x则被解析为十六进制,如果前两个字符是0b则被解析为二进制。
浮点数字面量由以下几个部分组成
指数部分以“e”或“E”开头,后面跟着一个整数,可以有正负号(即前缀“+”或“-”)。浮点数字面量至少有一位数字,而且必须带小数点或者“e”(大写“E”也可)。
语法:
[(+|-)][digits][.digits][(E|e)[(+|-)]digits]
例如:
3.14
-.2345789 // -0.23456789
-3.12e+12 // -3.12*1012
.1e-23 // 0.1*10-23=10-24=1e-24
字符串字面量必须是由双引号(”)对或单引号(’)括起来的零个或多个字符。除了闭合用的引号字符、反斜杠、回车符、行分隔符、段落分隔符、换行符之外的所有字符都可以直接出现的字符串字面量里。
例如:
var s='adc';
var s2='123'
var s3="abc123"
var s4="one line \n another line";
console.log(s);\\abc
console.log(s2);\\123
console.log(s3);\\abc123
console.log(s4);
\\one line
\\another line
转义序列 | 代码单元值 | 名称 | 符号 |
---|---|---|---|
\b | \u0008 | 退格符 | |
\t | \u0009 | 水平制表符 | |
\n | \u000A | 换行符 | |
\v | \u000B | 垂直制表符 | &VT;BS> |
\f | \u000C | 换页符 | |
\r | \u000D | 回车符 | |
\” | \u0022 | 双引号 | “ |
\’ | \u0027 | 单引号 | ‘ |
\\ | \u005C | 反斜杠 | \ |
值得多说一句的是ES6中引入了模板字符串(template literals),实现了多行字符串的引用。
例如:
//如果是使用ES5的话
var s="你好,我是猫猫。\n 很高兴见到你。";
console.log(s);
//你好,我是猫猫。
//很高兴见到你。
//使用ES6的模板字符串
var s2=`
模板字符串使用反引号包裹内容,
可以一次性实现多行字符串引入,
使用起来非常的方便。`;
console.log(s2);
//模板字符串使用反引号包裹内容,
//可以一次性实现多行字符串引入,
//使用起来非常的方便。
正则表达式字面量是一个输入元素,它在每次被解析执行时候都会转换成一个 RegExp对象 的。当程序中的两个正则表达式字面量解释执行为正则表达式对象后就不能用 === 来比较它们是否相等,即使它们所包含的内容相同。
var s=/abc/,
s2=/abc/;
console.log(s===s2)//false
注: 正则表达式字面量不能为空;并不是说正则表达式字面量不能代表空,字符 // 会启动一个单行注释。要指定一个空的正则表达式,使用:/(?:)/ 。
对象字面值是封闭在花括号对({})中的一个对象的零个或多个”属性名-值”对的(元素)列表。你不能在一条语句的开头就使用对象字面值,这将导致错误或产生超出预料的行为, 因为此时左花括号({)会被认为是一个语句块的起始符号。
其实说到底,对象字面量跟new创建对象的方式是一样的。对象字面量只是一种语法糖罢了,本质上还是var o=new Object()
;
唯一需要主要的是使用{}
修改(重写)对象原型,会切断构造函数与实例之间的联系。
例如:
function foo(){};
foo.prototype={
a:"a",
b:"b"
}
var f1=new foo();
console.log(f1.constructor == foo)//false
console.log(f1 instanceof foo)//true
虽然instanceof能够返回正确的结果,但是通过constructor属性却已经无法确定对象的类型。不过我们能够修正这个错误。
function foo(){};
foo.prototype={
constructor:foo,//设置显示的引用
a:"a",
b:"b"
}
var f2=new foo();
console.log(f2.constructor == foo)//true
console.log(f2 instanceof foo)//true
数组字面值是一个封闭在方括号对([])中的包含有零个或多个表达式的列表,其中每个表达式代表数组的一个元素。当你使用数组字面值创建一个数组时,该数组将会以指定的值作为其元素进行初始化,而其长度被设定为元素的个数。
注意:若你在同一行中连写两个逗号(,),数组中就会产生一个没有被指定的元素,其初始值是undefined。
例如:
var a = ["1", , "3"];
console.log(a[1])//undefined
注意:尾部的逗号在早期版本的浏览器中会产生错误,因而编程时的最佳实践方式就是移除它们。
JavaScript在创建变量时会检测源文本(右值),然后与目标符进行匹配。
目标符分成两种情况,分别是:
InputElementDiv 目标符
WhiteSpace——空白字符
LineTerminator——行终止符
Comment——注释
Token——标识标识包括标识符,标点符号,数值字面量,字符串字面量
DivPunctuator——块级标点符号(
/
和/=
,前者是除运算符,后者是除赋值)InputElementRegExp 目标符
WhiteSpace——空白字符
LineTerminator——行终止符
Comment——注释
Token——标识标识包括标识符,标点符号,数值字面量,字符串字面量
RegularExpressionLiteral——正则表达式字面量
InputElementDiv 目标符和InputElementRegExp 目标符除了最后一步不一样之外,其他都是一样的。
这表示不存在DivPunctuator开头又允许RegularExpressionLiteral存在的语法!(即不允许除运算符和除赋值与正则表达式共存。)
①源文本被从左到右地扫描
②如果源文本是被[]
形式描述,则对源文本进行数组对象初始化
③如果源文本是被{}
形式描述,则对源文本进行对象初始化
④否则将源文本转化成元素序列
⑤与(目标符||空值字面量||布尔值字面量)进行匹配
⑤匹配成功则进行赋值运算,否则返回语法错误
参考资料:
Grammar and types:语法和数据类型
ES5/词法