语句的结果值
一般获得结果值最直接的方法就是在浏览器中打印
如:
var a = 42; //结果值是undefined;
而var a=42;a //它会将a当作储存结果值的变量,并将42输出出来
因为在es5规范中指出,变量声明算法实际上有一个返回值,但是这个返回值给变量语句屏蔽掉了(for..in循环除外)且无法通过代码来访问这个返回值,最后返回结果为undefined
var b;
if(true){
b=38+4;
}
这行代码的结果值就就是b=38+4;
现在就可以打开开发中工具将上述代码复制粘贴在console中,就会发现将42打印出来
但是如果这样呢?
var a,b;
a = if(true){
b =38+4;
}
实际上它会报错,提醒你不应该执行错误的操作
因为语法不允许我们将获得的语句的结果值赋值给另外的变量
但是,凡事都有例外的嘛;《高级程序设计》中最为推崇且最强大的api---eval()函数,还真的能解决这个问题;
var a,b;
a = eval("if(true){b=38+4}")
console.log(a) //42
但是我们不推荐使用eval()函数,它的弊端是明显的,不说存在的安全性问题,此外就是eval能执行传入的代码字符串,能欺骗词法作用域,甚至是别的功能,而它的可读性并没有这么强,优化和维护将会是一个大问题,如果大量使用,运行速度还会有明显降低问题 此外就是es7规范中的 "do表达式":
var a,b;
a=do{
if(true){
b=38+4;
}
}
console.log(a=42)
还真的是神奇呢,它将花括号里执行的代码结果值赋值给了变量,挺有意思的
表达式副作用
大部分是没副作用
var a=1;
var b=a++;
a; //2
b; //1
var b=a++先执行赋值再递增
如果想一行得到b的值是递增后的a呢?
可以这样做:
var b=(a++,a)
b;//2 (完美)
此外如果:
var b=++a++;(会报错,因为优先级执行a++,它的副作用是先赋值给另外一个变量,再自增长。
如果此时再执行++a,它无法对副作用的基础上在执行副作用,因此报错)
所以即使是++(a++)封装起来,实际的执行的本质是诶呦变化的,也会报错
还有=的副作用
var a,b,c
a=b=c=3;
它们会按从右向左的顺序赋值;
c=3的结果值是3,它的副作用就是将3赋值给c
接着是b的结果值是3,最后到a
如果是在某块级作用域内
var a=b=c=3
执行的结果大同小异,不同就是就var只声明的a,b和c都会因为在块级内无法找到,从而在顶层对象下定义一个新的同名变量并赋值
上下文规则
{}+[]; //0
{}被当作是一个独立的代码块,因为[]可以显示转换类型为0,所以输出0
[]+{}; //"[object,object]"
[]显示转换类型"",{}会显示强制转换类型为"[object,object]"
因为
[] == 0 //true
[] == "" //true
代码块
{
foo:"a"
}
这样的代码也是符合语法的,此外就是这样的代码块可以用于解构
var obj = {
a:"a",
b:"b"
}
var {a,b} = obj;
a;//"a"
b;//"b"
等效于:
var a=obj.a
var b=obj.b
关于if(){}else if(){}的问题
其实如果{}内是单行语句,{}可以省略
而且js其实是不存在else if语句的,因为用起来方法易懂,所以就常用的起来
运算符优先级问题
暂时先了解||、&&
或(||)和与(&&)同时出现时,&&的优先级更高一些
且与和或的优先级比三目运算符要高
关联
js默认左关联(从左往右进行判断),但是也存在右关联
如:
当存在多个三目运算符时
true?false:true?true:true; //false
执行过程为:
true?false:(true?true:true) 因此才输出的false
练习:
var a=42;
bar b="foo";
var c=false;
var d=a && b || c ? c || b ? a : c && b : a;
d?
过程如下:
与或的优先级高,接着三目运算符的右关联
可以细分为下面代码执行顺序:
var d = ((a && b) || c) ?(c || b ? a : (c && b) : a)
1.a&&b结果为b ->"foo"
2.b || c 结果为b ->"foo" 为真
3. c|| b 为真 三目运算符结果为a ->42
4.因为上一个运算符结果为真,所以d=42
ASI(自动分号插入)
为一些结尾的程序添加分号(;)
ASI实际上也是一种纠错机制,在一些必要的程序,分号是必要的,所以ASI发挥的作用也是巨大的,防止未添加的分号导致错误的发生
额外记录暂时性死区(TDZ)
{
a =2;
let a;
}
未定义先调用,如let不存在变量提升
函数参数(很有意思的一节内容)
function foo(a=42,b=a+1){
console.log(a,b)
}
foo(); //42,43
foo(undefined); //42,43
foo(5) //5,6
foo(undefined,7) //42,7
foo(1,2) //1,2
foo(null,1) //null,1
理解起来也是比较简单的,即使看起来,好像麻烦又困难的样子
首先在函数上定义的形参a,b;
a=42,将形参的默认值设置为42,如果没有传入参数或传入的是undefined,使用的就是默认值,所以foo(),foo(undefined)输出的是默认值
如果传入了实参就调用实参
简单,easy。
try..finally
try..finally的finally块是无论什么情况下都会执行的 try..finally中 finally中程序带有return 关键字并不会打断try..finally执行try语句,但是会执行完后会跳出函数 同样的finally中如果throw抛出异常,也会终止函数,try语句也会继续执行,但是如果有return的化,return语句会被忽略