[JS权威指南笔记] 第4、5章

第4章 表达式和运算符

4.1 原始表达式

原始表达式(primary expression)是表达式的最小单位——它们不再包含其它表达式。

1)直接量:数字直接量、字符串直接量、正则表达式直接量

2)保留字:true、false、null、this

3)变量

 

4.2 对象和数组的初始化表达式

也称“对象直接量”和“数组直接量”,不是原始表达式

数组直接量中的列表逗号之间的元素可以省略,空位填充undefined

 

4.3 函数定义表达式

也称函数直接量

eg:

var square = function(x){return x*x;}

 

4.4 属性访问表达式

方括号或点

"." 和 "[" 之前的表达式总会先计算,如果计算结果是null或undefined,表达式会抛出一个类型错误异常

 

4.5 调用表达式(invocation expression)

 

4.6 对象创建表达式(object creation expression)  -> 创建一个对象并调用一个函数(构造函数)初始化新对象的属性,对象创建表达式有一个关键字new

 

4.7 运算符概述

一个需要注意的例子 -> "5"*"3"结果是数字15

 

4.8 算术表达式

JS中,所有的数字都是浮点型的,除法运算的结果也是浮点型,比如 5/2=2.5

0/0 -> NaN,  someNum/0 -> 正负无穷大 (注意:不会报错)

-5%2 = -1, 6.5%2.1 = 0.2

"1"+2 => "12"

true + ture => 2

2 + null => 2

2 + undefined => NaN

 

注意:"++" 运算符从不进行字符串连接操作

表达式++x并不总和x=x+1完全一样,例如x是"1",前者是2,后者是"11"

 

4.9 关系表达式

 

4.9.1 相等和不相等运算符

"===" 严格相等运算符(strict equality)或恒等运算符(identity operator)

"==" 相等运算符(equality operator)

 

建议:

"="      得到 或 赋值

"=="    相等  

"==="  严格相等

"!="     不相等

"!=="   不严格相等

 

控制台检验的一些例子:

1=="1"   => true

null==undefined    => true

null===undefined  => false

--------------------------

下面两个和书里写的不一样

null===null

undefined===undefined

--------------------------

"1"==true   => true, 如果一个值是数字,另一个是字符串,先将字符串转换为数字

 

4.9.2 比较运算符

一些例子:

"1" + 2          => 2转换为"2",结果是"12"

"11"  < "3"   => 字符串比较,结果为true,注意所有大写的ASCII字母都“小于”小写的ASCII字母

"11" < 3       => 数字比较,"11"转换为11,结果为false

"one" < 3     => 数字比较,如果其中一个操作数是(或转换后是)NaN,那么比较操作符总是返回false>=,=<同理)

 

4.9.3  in运算符

 

如果右侧的对象拥有一个名为左侧操作数值(可以转换为字符串)属性名,那么表达式返回true

 

var point = { x:1, y:1 };      // 定义一个对象
"x" in point                   // => true:对象有一个名为"x"的属性
"z" in point                   // => false:对象中不存在名为"z"的属性
"toString" in point            // => true:对象继承了toString()方法
 
var data = [7,8,9];            // 拥有三个元素的数组
"0" in data                    // => true:数组包含元素"0"
1 in data                      // => true:数字转换为字符串
3 in data                      // => false:没有索引为3的元素

 

4.9.4  instanceof运算符

如果左侧的对象右侧类的实例,则表达式返回true

第9章将会讲到,JavaScript中对象的类是通过初始化它们的构造函数来定义的。这样的话,instanceof的右操作数应当是一个函数

var d = new Date();// 通过Date()构造函数来创建一个新对象
d instanceof Date;   // 计算结果为true,d是由Date()创建的
d instanceof Object; // 计算结果为true,所有的对象都是Object的实例
d instanceof Number; // 计算结果为false,d不是一个Number对象
var a = [1, 2, 3];   // 通过数组直接量的写法创建一个数组
a instanceof Array;  // 计算结果为true,a是一个数组
a instanceof Object; // 计算结果为true,所有的数组都是对象
a instanceof RegExp; // 计算结果为false,数组不是正则表达式

 

需要注意的是,所有的对象都是Object的实例。当通过instanceof判断一个对象是否是一个类的实例的时候,这个判断也会包含对“父类”(superclass)的检测。如果instanceof的左操作数不是对象的话,instanceof返回false如果右操作数不是函数,则抛出一个类型错误异常

理解原型链(prototype chain)6.2.2节

 

4.10 逻辑表达式

x==0 && y==0  //关系运算符的优先级比“&&”和“||”要高,可以不写括号

!(p && q)   // "!"优先级很高,和操作数紧密绑在一起

 

1.逻辑与

&&并不总是返回true或false

  1. 如果计算结果是假值,则返回左操作数的值
  2. 当左操作数是真值时,将计算右操作数的值并将其返回作为整个表达式的计算结果

&&的行为有时称为短路(short circuiting)

 

eg:以下两行等价

if(a==b) stop();

(a==b) && stop();

 

具有副作用-> 赋值、递增、递减和函数表达式

 

2.逻辑或

最常用的方式是从一组备选表达式中选出一个真值表达式,通常用在函数体内,用来给参数提供默认值

var max = max_width || preferences.max_width || 50;

 

3.逻辑非

总是返回true或false(注意这点和前两者不一样)

可以通过 !!x 得到一个等价的布尔值

 

4.12 表达式计算(没看明白,先跳过)

 

4.13.2 typeof运算符

注意:

>typeof(null)

"object"

 

所有对象和数组的typeof返回object

可执行对象(callable)的typeof返回function

 

了解真正的函数和可执行对象参照8.7.7

 

4.13.3 delete运算符(看完第6章再看看)

 

用来删除对象属性或数组元素

delete也具有副作用,它是用来删除操作数的,不是用来返回一个值的

1)delete希望它的操作数是一个左值(变量、对象属性和数组元素),如果它不是左值,那么delete将不进行任何操作同时返回true

2)否则将试图删除 2.1)删除成功返回true,只有操作数是一个属性访问表达式(4.4节)的时候它才会正常工作

2.2)一些内置核心客户端属性不能删除,用户通过var语句声明的变量不能删除,通过functon语句定义的函数和函数参数也不能删除。如果操作非法,delete操作将抛出一个语法错误(SyntaxError)异常

3)在严格模式下,delete操作删除不可配置的属性(6.7节)时会抛出一个类型错误异常,在非严格模式下不会报错仅返回false

 

第五章 语句

5.2 复合语句和空语句

关于空语句,注意:

[例]

if(( a==0 ) || (b==0)) ;   //这一行代码什么都没做,最后的分号是一条空语句

o = null;   //这一行代码总会执行

 

如果有特殊的目的需要使用空语句,最好在代码中添加注释

[例]

for (i =0; i < a.length; a[i++] = 0) /*empty*/;

 

5.3 声明语句

var和function都是声明语句,它们声明或定义函数或变量。

 

5.3.1 var

 

var语句出现在函数体 -> 局部变量,作用域:这个函数

var语句在顶层代码 -> 全局变量,作用域:整个JS

注意:

全局变量是全局对象的属性,但是var声明的变量不能通过delete删除(3.10.2节有提到)。

如果var语句中的变量没有指定初始化表达式,那么这个变量的值为undefined

 

5.3.2 function

 

两种定义写法

var f = function(x) {return x+1;}  //函数定义表达式

function  f(x){return x+1;}   //函数声明表达式

 

1.区别:两种方法都创建了新的函数对象,但1)函数声明语句中的函数名是一个变量,变量指向函数对象。

 

函数声明语句通常出现在JS代码的最顶层,也可以嵌套在其它函数体内(嵌套时只能出现在所嵌套函数的顶部)。使用函数声明语句,函数名和函数体均提前,可以在声明一个JS函数之前调用它。

 

2)和通过var声明变量一样,函数定义语句中的函数被显式地“提前”到了脚本或函数的顶部。

 

2. 和var语句一样,函数声明语句创建的变量也是无法删除的。

 

5.4 条件语句(else,else if,switch)

 

5.4.3 switch

当执行这条switch语句的时候,它首先计算expression的值,然后查找case子句中的表达式是否和expression的值相同(这里的“相同”是按照“===”运算符进行比较的)。

 

在每一个case语句块的结尾处都使用了关键字break。break语句可以使解释器跳出switch语句或循环语句。在switch语句中,case只是指明了要执行的代码起点,但并没有指明终点。

 

如果在函数中使用switch语句,可以使用return来代替break,return和break都用于终止switch语句,

eg:

function convert(x){
    switch(typeof x){
    case 'number':            // 将数字转换为十六进制数
        return x.toString(16);
    case 'string':            // 返回两端带双引号的字符串
        return '"' + x + '"';
    default:                  // 使用普通的方法转换其他类型
        return String(x);
    }
}

 

"default:"标签一般出现在switch的末尾,位于所有case标签之后。实际上,它可以放置在switch语句内的任何地方。

 

5.5 循环(while,do/while,for,for/in)

 

5.5.2  do/while

do statement
while(expression);  //至少执行一次,最后这个分号不要忘记

 

5.5.3 for

for(initialize ; test ; increment)
statement

 

和以上等价的while循环

initialize;   

while(test){   

statement       

increment;   

}

 

for循环中数字是最常用的,但不是必需的。下面这段代码就使用for循环来遍历链表数据结构,并返回链表中的最后一个对象(也就是第一个不包含next属性的对象):

 
function tail(o) {                               // 返回链表的最后一个节点对象
    for(; o.next; o = o.next) /* empty */ ;      // 根据判断o.next是不是真值来执行遍历
    return o;
}

 

for循环中那三个表达式中的任何一个都可以忽略,但是两个分号必不可少。如果省略test表达式,那么这将是一个死循环,同样,和while(true)类似,死循环的另外一种写法是for(;;)。

 

 

5.5.3 for/in

 

for(variable in object)
      statement

 

使用for循环来遍历数组元素是非常简单的:

 
for(var i = 0; i < a.length; i++)       //i代表了数组元素的索引
    console.log(a[i]);                  //输出数组中的每个元素

 

for/in循环则是用来更方便地遍历对象属性成员

 
for(var p in o)                // 将属性名字赋值给变量p
    console.log(o[p]);         //输出每一个属性的值

 

在执行for/in语句的过程中,JavaScript解释器首先计算object表达式。

1)如果表达式为null或者undefined,JavaScirpt解释器将会跳过循环并执行后续的代码 。

2)如果表达式等于一个原始值,这个原始值将会转换为与之对应的包装对象(wrapper object)(见3.6节)。

3)否则,expression本身已经是对象了。JavaScript会依次枚举对象的属性来执行循环。然而在每次循环之前,JavaScript都会先计算variable表达式的值,并将属性名(一个字符串)赋值给它。

 

例如,可以使用下面这段代码将所有对象属性复制至一个数组中:

 
var o = {x:1, y:2, z:3};
var a = [], i = 0;
for(a[i++] in o)/* empty */;

 

JavaScript数组不过是一种特殊的对象,因此,for/in循环可以像枚举对象属性一样枚举数组索引

例如,在上面的代码之后加上这段代码就可以枚举数组的索引0、1、2:
for(i in a)console.log(i);

 

 

注意:for/in循环并不会遍历对象的所有属性,只有“可枚举”的属性才会遍历到(参照6.7节)。由JavaScript语言核心所定义的内置方法就不是“可枚举的”。比如,所有的对象都有方法toString(),但for/in循环并不枚举toString这个属性。

 

不可枚举(nonenumerable):内置方法、很多内置对象的属性

可枚举(enumerable):代码中定义的所有属性和方法、继承的自定义属性

 

属性枚举的顺序(暂时没看明白 囧)

 

5.6 跳转

 

5.6.1 标签语句

break和continue是JS中唯一可以使用语句标签的语句

 
mainloop: while(token != null){
    // 忽略这里的代码...
    continue mainloop; // 跳转到下一次循环
    // 忽略这里的代码...
}

 

5.6.2 break语句

单独使用break语句的作用是立即退出最内层的循环或switch语句。

 

break labelname;

当break和标签一块使用时,程序将跳转到这个标签所标识的语句块的结束,或者直接终止这个闭合语句块的执行。

当你希望通过break来跳出非就近的循环体或者switch语句时,就会用到带标签的break语句。下面是示例代码:

 
var matrix = getData(); // 从某处得到一个二维数组
// 将矩阵中所有元素进行求和
var sum = 0, success = false;
//从标签名开始,以便在报错时退出程序
compute_sum: if(matrix){
    for(var x = 0; x < matrix.length; x++){
    var row = matrix[x];
    if(!row)break compute_sum;
        for(var y = 0; y < row.length; y++){
            var cell = row[y];
            if(isNaN(cell))break compute_sum;
            sum += cell;
        }
    }
    success = true;
}
//break语句跳转至此
//如果在success == false的条件下到达这里,说明我们给出的矩阵中有错误
//否则将矩阵中所有的元素进行求和

最后,需要注意的是,不管break语句带不带标签,它的控制权都无法越过函数的边界。比如,对于一条带标签的函数定义语句来说,不能从函数内部通过这个标签来跳转到函数外部。

 

5.6.2 continue语句

不管continue语句带不带标签,它只能在循环体内使用。在其他地方使用将会报语法错误。

 

注意:continue语句在while和for循环中的区别,while循环直接进入下一轮的循环条件判断,但for循环首先计算其increment表达式,然后判断循环条件。

 

和break语句类似,带标签的continue语句可以用在嵌套的循环中,用以跳出多层次嵌套的循环体逻辑。

 

5.6.4 return语句

 

return语句只能在函数体内出现。return语句不带表达式,函数会向调用程序返回undefined。

 

5.6.5 throw语句

 

5.6.6 try/catch/finally语句

 

1)当try块内某处发生了异常时,调用catch内的代码逻辑。

catch从句后跟随finally块,后者中放置清理代码,不管try块中是否产生异常,finally块内的逻辑总是会执行。

2)尽管catch和finally都是可选的,但try从句需要至少二者之一与之组成完整的语句。

3)try、catch和finally语句块都需要使用花括号括起来(即使只有一条语句也不能省略)。

 

如果使用try/finally语句,就能使用while循环来正确模拟包含continue的for循环:

 
//模拟for(initialize;test;increment)body;initialize ;
while(test){
    try { body ; }
    finally { increment ; }
}

 

5.7 其它语句类型

 

5.7.1 with语句

with语句用于临时扩展作用域链(scope chain),它具有如下的语法:

 
with(object)statement

这条语句将object添加到作用域链的头部,然后执行statement,最后把作用域链恢复到原始状态。

在严格模式中(参照5.7.3节)是禁止使用with语句的,并且在非严格模式里也是不推荐使用with语句的,尽可能避免使用with语句

 

在对象嵌套层次很深的时候通常会使用with语句来简化代码编写。例如,在客户端JavaScript中,可能会使用类似下面这种表达式来访问一个HTML表单中的元素:

 
document.forms[0].address.value

 

如果这种表达式在代码中多次出现,则可以使用with语句将form对象添加至作用域链的顶层:

 
with(document.forms[0]){
    // 直接访问表单元素,例如:
    name.value = "";
    address.value = "";
    email.value = "";
}

 

不使用with语句的等价代码可以写成这样:

 
var f = document.forms[0];
f.name.value = "";
f.address.value = "";
f.email.value = "";

 

只有在查找标识符的时候才会用到作用域链,创建新的变量的时候不使用它,看一下下面这行代码:

 
with(o)x = 1;

如果对象o有一个属性x,那么这行代码给这个属性赋值为1。但如果o中没有定义属性x,这段代码和不使用with语句的代码x=1是一模一样的。它给一个局部变量或者全局变量x赋值,或者创建全局对象的一个新属性。with语句提供了一种读取o的属性的快捷方式,但它并不能创建o的属性

 

5.7.2 debugger

这条语句用来产生一个断点(breakpoint)

 

5.7.3 “use strict”

“use strict”是ECMAScript 5引入的一条指令。

 

严格模式和非严格模式之间的最重要的三条区别:

1)在严格模式中禁止使用with语句。

2)在严格模式中,所有的变量都要先声明,如果给一个未声明的变量、函数、函数参数、catch从句参数或全局对象的属性赋值,将会抛出一个引用错误异常。

3)在严格模式中,调用的函数(不是方法)中的一个this值是undefined。(在非严格模式中,调用的函数中的this值总是全局对象)。可以利用这种特性来判断JavaScript实现是否支持严格模式:

 var hasStrictMode =(function(){ "use strict"; return this===undefined}());

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值