JavaScript学习笔记(一)

初学JavaScript,不过之前已经学过很多语言了。刚看JavaScript的时候,感觉很多内容其实和python挺像的,只不过这里初始化时没有要求变量类型。没错,java和JavaScript的区别就是雷锋和雷峰塔的区别。感觉对于编程来说,时间长了,太容易自己为是了。以致于一个很简单的小问题最后可以烦死你,还死活看不出来。所以开始记下笔记,记下容易出错或者一些平时不大注意的细节,以后温故时候,也挺舒服的。

大小写区别:

JavaScript区分大小写,而HTML并不区分大小写(尽管XHTML区分大小写)。

关于换行:

在JavaScript中,如果各语句独占一行,通常可以省略语句之间的分号(程序结尾或者右花括号之前的分号也可以省略)。但在return、break和continue和随后的表达式直接不能有换行。如果添加了换行,程序只有在极特殊的情况下才会报错,而且程序的调试非常不方便。

例如:

return

true;

JavaScript会解析成(本意是return true;)

return;

true;

还有一个例外是涉及++和- -的时候,如果将其用作后缀表达式,它和表达式应当在同一行。否则,行尾将填补分号。

例如:

x

++

y

解析成“x; ++y”

关于数字:

JavaScript中的非数字值有一点特殊:它和任何值都不相等,包括自身。因此,不能通过x==NaN来判断变量x是否是NaN,只能使用x!=x来判断:当且仅当x为NaN的时候,表达式的结果才是true。

JavaScript中的数字具有极高的精度,并可以极其近似于0.1。但是,数字不能精确的表述的确带来了一些问题。

例如:

var x = .3 -.2;

var y = .2 - .1 ;

x == y //false:两值不相等!

由于舍入误差,0.3和0.2之间的近似差值实际上并不等于0.2和0.1之间的近似差值。这个问题并不只在JavaScript中出现,理解这一点非常重要:在任何使用二进制浮点数的编程语言中都会有这个问题。

关于文本:

空字符串长度为0,JavaScript中并没有表示单个字符的“字符型”。

一个长度为2的JavaScript字符串(两个16位值)有可能表示一个Unicode字符:

var p = "π" ; // π由16内码表示0x03c0

var e = "e" ; //e由17位内码表示0x1d452

p.length
// 1

e.length
// 2

包装对象:

存取字符串、数字或布尔值的属性时创建的临时对象称作包装对象,它只是偶尔用来区分字符串值和字符串对象、数字和数值对象以及布尔值和布尔对象。

关于对象:

对象的比较并非值的比较:即使两个包含同样的属性及相同的值,它们也是不相等的。各个索引元素完全相等的两个数组也不相等。

例如:

var o = {x:1}, p={x:1};

o === p
// false

var a =[], b = [];

a ===b
//false

对象值都是引用,对象的比较均是引用的比较:当且仅当它们引用同一个基对象时,他们才相等。

关于类型转换:

除了null和undefined之外的任何值都具有toString()方法,这个方法的挤过通常和String()方法的返回结果一致。

几个类型转换的惯用法:

x + ""
// 等价于String(x)

+x //
等价于Number(x),也可以写成x-0

!!x
// 等价于Boolean(x)

toFixed()根据小数点后的指定位数将数字转换为字符串,从不使用指数记数法。

toExponential()使用指数记数法将数字转换为指数形式的字符串,其中小数点前只有一位,小数点后的位数则有参数指定。

toPrecision()根据指定的有效数字位数将数字转换为字符串。如果有效数字的位数少于数字整数部分的位数,则转换为指数形式。

如果用Number()转换函数传入一个字符串,它会视图将其转换为一个整数或浮点数直接量,这个方法只能基于十进制数进行转换,并且不能出现非法的尾随字符。

parseInt()函数只解析整数,而parseFloat()则可以解析整数和浮点数。如果字符串前缀是“0x”或者“0X”,parseInt()将其解释为十六进制数,parseInt和parseFloat()都会跳过任意数量的前导空格,尽可能解释更多字符,并忽略后面的内容。如果第一个非空格字符是非法数字直接量,将最终返回NaN。

parseInt()可以接受第二个可选参数,这个参数指定数字转换的基数,合法的取值范围是2~36.

对象转换为原始值:所有的对象(包括数组和函数)都转换为true。

关于变量作用域:

在函数体内,局部变量的优先级高于同名的全局变量。

尽管在全局作用域编写代码时可以不写var语句,但声明局部变量时必须使用var语句。

关于函数作用域和声明提前:

JavaScript中没有块级作用域,取而代之的使用了函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数内都是有定义的。这意味着变量在声明之前甚至已经可用。JavaScript的这个特性被非正式的称为声明提前,即JavaScript函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部。

关于作为属性的变量:

使用var声明一个变量时,创建的这个属性时不可配置的,也就是说无法通过delete运算符删除。如果没有使用严格模式并给一个未声明的变量赋值的话,JavaScript会自动创建一个全局变量。以这种方式创建的变量是全局对象的正常可配置属性,并可以删除它们。

关于作用域链:

在不包含嵌套的函数体内,作用域链上有两个对象,第一个是定义函数函数和局部变量的对象,第二个是全局对象。在一个嵌套的函数体内,作用域链上至少有三个对象。

关于原始表达式:

在一个方法体内,this返回调用这个方法的对象。

关于属性访问表达式:

两种:

expression . identifier

expression [ expression ]

.identifier的写法更加简单,但是这种方式只适用于要访问的属性名称是合法的标识符,并且需要知道访问的属性的名字。

关于方法调用:

执行函数体的时候,作为属性访问主题的对象和数组便是其调用方法内this的指向。

关于对象创建表达式:

如果一个对象创建表达式不需要传入任何参数给构造函数的话,那么这对空圆括号是可以省略掉的。

关于左值:

在JavaScript中,变量、对象属性和数组元素均是左值。ECMAScript规范允许内置函数返回一个左值,但自定义的函数则不能返回左值。

关于算术表达式:

一个很容易忽略的现象:

假设存在a=1,那么“b=(a++)+a”将如何计算结果呢?

正确顺序:

(1)计算b

(2)计算a++(假设值为c)

(3)计算a

(4)计算c+a

(5)将c+a的结果赋值给b

按照“++”的含义,第二步中a++的结果依然是1,即c为1,随后a立即增1,因此在执行第三步时,a的值已经是2.所以b的结果为3.

求余运算符的操作数通常是整数,但也适用于浮点数,比如6.5%2.1结果是0.2

关于比较:

对于数字和字符串操作符来说,加号运算符和比较运算符的行为都有所不同,前者更偏爱字符串,如果它的其中一个操作数是字符串的话毛泽进行字符串连接操作。而比较运算符更偏爱数字,只有在两个操作数都是字符串的时候,才会进行字符串的比较。

分享
匿名评论