你不知道的javascript(语法部分读书笔记)

134 阅读5分钟

语句的结果值

一般获得结果值最直接的方法就是在浏览器中打印
如:

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语句会被忽略