文章目录
  1. 1. 语言核心部分
  • 核心部分
    1. 语言核心
      1. 变量及变量类型
        1. 1. 原始类型
        2. 2. 对象类型
      2. 严格模式:use strict
  • 模糊点
    1. 包装对象
    2. 变量声明提前和变量可配置性
    3. eval 运算符
    4. 标签语句
    5. throw/try/catch/finally 语句
    6. 函数名
    7. this 引用丢失
  • 记录阅读《javascript权威指南》中,个人认为比较核心或是比较容易混乱的地方。
    同时会加入在阅读过程中参阅的一些优秀的扩展文章。

    更新记录

    2016-01-18 更新到try-except-finally语句

    2016-04-07 文章改名。将文章结构分为核心和模糊点

    我认为书中的核心部分

    语言核心部分

    1. 变量类型
    2. strict模式
    3. 词法作用域、函数,闭包、this、call、apply、bind
    4. 原型系统

    核心部分

    语言核心

    变量及变量类型

    javascript中的变量本身没有类型,给一个变量赋值时,其实是这个变量引用了这个值。这根python中是一致的。

    他们都区别于C语言等固定类型的变量,在C语言中,当声明一个变量时,需要指定它的类型,这个变量其实就是一个固定大小的空间,直接用于存放变量的值。数组也是一样,一个数组只能存储同样类型的值,C语言需要根据类型决定如何分配内存大小,比如int是4个字节。

    而javascript和Python中,无需声明变量类型。变量只是对数据的引用,而类型是数据本身决定的,这个变量引用了什么类型,这个变量就是什么类型,javascript中的数据类型分为两类(貌似是借鉴了java):

    原始类型

    • 原始类型 primitive type(5种)
      • 数字
      • 字符串
      • 布尔值
      • null
      • undefined

    注意:原始类型不是对象,但你可能会见过 APrimitiveType.method的调用形式,这是因为数字,字符串,布尔值存在 「包装对象」 这个概念。

    对象类型

    • 对象类型(object)(除了5种原始类型的数据类型,都是对象类型)
      • 普通对象(名值对对象)
      • 数组
      • 函数
        • javascript可以将function对象当做普通对象对待

    严格模式:use strict

    如果你了解一些javascript的历史,就会清楚javascript是 Brendan Eich花了十天时间设计出来的,主要参考了Scheme, Self,C,Java 等语言。虽然有现成的语言可以借鉴,但是在如此短的时间内,想要完成一个非常严格的设计是不太现实的。因此Javascript本身在设计之初就带有一些隐藏的缺陷。再加上浏览器大战时的迅速推广,这些缺陷没有足够的时间得到修正,便开始成为标准。所以使得这些缺陷一直保留了下来。

    关于这些缺陷,可以简单参考阮一峰的文章: javascript的十个设计缺陷,以及书籍:《javascript: the good parts》

    use strict其实是ECMAscript 5 中加入的指令,非常接近于语句,但又有所区分:不包含关键字,只是个字符串字面量,而且只能出现在特定的位置。

    use strict的目的是使其后的代码使用js的「严格模式」执行,它是js的一个子集,修正了一些语言的重要缺陷,并提供健壮的查错功能和增强的安全机制。严格模式与非严格模式有一些重要的区别。

    • 严格模式中不能使用with语句
    • 严格模式中变量都要先var声明(非严格模式不声明使用会给全局对象添加一个新属性)
    • 严格模式中,函数调用时this值为undefined,而不是全局对象。

    模糊点

    包装对象

    原始类型不是对象,但你可能会见过 APrimitiveType.method的调用形式,这是因为数字,字符串,布尔值存在 「包装对象」 这个概念。也就是说,档使用上面的.运算时,javascript会自动调用 new String(s) | new Number(s) | new Boolean(s) 的方式将这三种基本类型临时转换为对象,并继承相应类型的方法。

    1
    2
    3
    4
    //一个经典的例子
    var s = "test";
    s.len = 4; //因为点运算,这里会临时建立一个string对象,但是随即又销毁了
    var t = s.len; //这里也会创建一个string对象,但是已经不是上面那个了,故undefined
    • null和undefined没有包装对象

    • 可以使用构造函数显式地构造包装对象。

    变量声明提前和变量可配置性

    • 声明提前
      • 指的是var声明变量时,会提前到其所在作用域的顶部
    • 可配置性
      • 全局变量是全局对象的属性,但局部变量没有此规定
      • var声明的全局变量是不可配置的,无法通过delete运算符删除

    eval 运算符

    eval()实际上是个函数,但它早已被当成运算符看待。ECMAscript会尽量约束eval()的表现,使其看起来像个表达式。

    这是因为如果将eval当做普通的函数对待,不做任何限制的话,会有很多缺点。一是因为eval()会动态的执行代码段,破坏原来的代码结构,解释器难以优化。二是因为如果eval是普通的函数,那么它就可以被赋值给其他的变量名,比如 g = eval, 这样导致任何使用g的地方,也会产生上述问题,导致javascript的代码优化变得困难,性能堪忧。

    综上所述,如果eval的表现行为像一个运算符的话,就不会有上述这么严重的问题。所以在ECMAscript语法中不断的约束它,让其表现更接近为运算符。

    标签语句

    主要用于配合continue和break使用,来实现更灵活一些的跳转。

    throw/try/catch/finally 语句

    之前写过一篇那些年我在python中扑过的街,在其中提到过python中,try/except/finally中容易进的坑。

    这个坑在javascript中也是同样的,就像那篇文章里说的那样,因为finally的设计目的就是无论如何都会执行,那么一旦finally中出现了跳转语句,其他语句中的返回内容就会被忽略。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function finallyTest(){
    var x = 'catch', y = 'except', z = 'finally';
    try {
    k = x + y;
    a = b;
    console.log("here is try------------");
    } catch(e) {
    console.log("here is catch----------");
    return x;
    } finally{
    console.log("here is finally---------");
    return z;
    }
    }
    //执行
    finallyTest()
    //返回值
    here is catch----------
    here is finally---------
    'finally'

    函数名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 直接声明函数是具有函数名的
    function foo(){}
    foo.name // 函数名为foo
    var bar = foo
    bar.name // 将函数赋值给一个变量,只是让变量指向了函数结构,并不会改变函数结构本身
    // 函数表达式生成的是匿名函数
    var foo = function(){}
    foo.name // "" (空字符串)
    // 函数名称只存在于函数自身结构内,被传递时不会改变这个结构
    function foo(){}
    var o ={
    a: 'a',
    bar: foo
    };
    o.bar.name // foo

    this 引用丢失

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 函数被多次传递时可能发生
    function foo(){
    console.log(this.a);
    }
    var obj = {
    a: 2,
    foo: foo
    };
    var bar = obj.foo;
    var a="oops, global";
    bar(); //"oops, global"
    // 回调函数中可能发生(异步)
    // 代码同上
    setTimeout(obj.foo, 100); // "oops, global"
    文章目录
    1. 1. 语言核心部分
  • 核心部分
    1. 语言核心
      1. 变量及变量类型
        1. 1. 原始类型
        2. 2. 对象类型
      2. 严格模式:use strict
  • 模糊点
    1. 包装对象
    2. 变量声明提前和变量可配置性
    3. eval 运算符
    4. 标签语句
    5. throw/try/catch/finally 语句
    6. 函数名
    7. this 引用丢失