《JavaScript语言精粹》内容精选

最近在读《JavaScript语言精粹》这本书,做者是 Douglas CrockfordDouglas Crockford是一名来自 Yahoo!的资深JavaScript架构师,以建立和维护JSONJavaScript object notation)格式而为你们所熟知。他会按期在各种会议上发表有关高级JavaScript的主题演讲。他也是ESMAscript委员会的成员之一。
原本想写一篇读后感的,可是想一想,《JavaScript语言精粹》是我在JavaScript方面阅读的第一本书,算是开拓视野,因此心中只有对这本书的总结,谈不上有感。并且个人目的就是为了节省阅读这本书的时间,帮助你们了解大概的内容,我会尽可能把本身以为其中的精髓传达给想读这本书的朋友。
注意:这本书不是给初学者的,也不是一本傻瓜式的教程。正则表达式

语法 Grammer

  1. JavaScript的两种注释形式:/**/(块注释)和 //(行注释)编程

  2. 块注释的字符对可能出如今如今正则表达式的字面量里,因此块注释相对来讲不安全数组

    例如:
    /*
    var rm_a = /a*/.match(s);
        */
  3. 做者建议尽可能避免使用 /**/注释,用 //来代替它。安全

标识符

  1. 标识符有一个字母开头,其后能够选择性的加上一个或多个字母、数字或下划线。闭包

  2. 标识符不能使用下面这些保留字:架构

abstract
boolean    break    byte
case    catch    char    class    const    continue
debugger    default    delete    do    double
else    enum    export    extends
false    final    finally    float    for    function
goto
if    implements    import    in    instanceof    int    interface
long
native    new    null
package    private    protected    public
return
short    static    super    switch    synchronized
this    throw    throws    transient    true    try    typeof
var    volatile    void
while    with

数字

  1. JavaScript只有一个数字类型。它在内部被表示与64位的浮点数,和Java的double数字类型同样。app

  2. 若是一个数字字面量有指数部分,那么这个字面量的值等于e以前的数字与10的e以后的数字的次方相乘。因此 100和 1e2是相同的数字。函数

  3. 数字拥有方法,JavaScript有一个对象Math,它包含一套用于数字的方法。
    例如,能够用Math.floor(number)方法把一个数字转换为一个整数。工具

字符串

  1. JavaScript没有字符类型。要表示一个字符,只需建立仅包含一个字符的字符串便可。开发工具

  2. 字符串有一个 length属性。例如,"seven".length是5。

  3. 字符串也有一些方法。例如,'cat'.toUpperCase( ) === 'CAT'

语句

  1. 当 var语句被用于函数内部时,它定义的是这个函数的私有变量

  2. 语句一般是按照从上到下的顺序被执行。JavaScript能够经过条件语句(if和switch)、循环语句(while、for和do)、强制跳转语句(break、return和throw)和函数调用来改变执行的序列

表达式

1. . [] ()    ----------提取属性与调用函数
 2. * / %      ----------乘法、除法、求余
 3. &&         ----------逻辑 与
 4.||          ----------逻辑 或
 5.?:        ----------三元

三元运算符?后面跟着另外一个表达式,而后接一个:,其后面接第三个表达式。
三元运算符?有三个运算数。若是第1个运算数的值为真,产生第2个运算数的值;若是为假,则产生第3个是运算数的值。

对象 Objects

JavaScript里的对象是无类型的(class-free),对象能够包含其余对象。
JavaScript包含一种原型链的特征,容许对象继承另外一个对象的属性。正确的使用它能减小对象初始化时消耗的时间和内存。
一、对象字面量 Object Literals

  • JavaScript的标识符中包含链接符“-”是不合法的,可是容许包含下划线“_”,

  • 因此用引号括住“first-name”是必需的。

二、检索 Retrieval

  • 要检索对象里包含的值,能够采用[]后缀中括住一个字符串表达式的方式。

  • 若是字符串表达式是一个字符串字面量,那么也能够用 . 表示法代替。

  • 考虑优先使用 . 表示法,由于它更紧凑且可读性更好。

  • 若是你尝试检索一个并不存在的成员属性的值,将返回undefined

  • 尝试从undefined的成员属性中取值将会致使TypeError异常。这时能够经过 && 运算符来避免错误。

三、原型 Prototype

  • 每一个对象都链接到一个原型对象,而且它能够从中继承属性。全部经过对象字面量建立的对象都链接的Object.prototype,它是JavaScript中标配对象。

  • 当你建立一个新对象时,你能够选择某个对象做为它的原型。JavaScript提供的实现机制杂乱而复杂,但其实能够被明显地简化。咱们将给Object增长一个create方法。这个方法建立一个使用原对象做为其原型的新对象。

if(typeof Object.beget !== 'function') {
    Object.create = function(o) {
        var F = function() {};
        F.prototype = o;
        return new F();
    };
}
var another_stooge = Object.create(stooge);
  • 原型链接在更新时是不起做用的。当咱们对某个对象作出的改变时,不会影响该对象的原型。

  • 若是咱们尝试去获取对象的某个属性值,但该对象没有此属性名,那么JavaScript会试着从原型对象中去获取属性值。若是那个原型对象也没有改属性,那么再从它的原型中寻找,依此类推,直到最后到达终点Object.prototype

  • 若是想要的属性彻底不存在原型链中,那么结果就是undefined值。这个过程称为委托

  • 原型关系是一种动态关系。若是咱们添加一个新的属性到原型中,该属性会当即对全部基于该原型建立的对象可见。

四、反射 Reflection

  • 检查对象并肯定对象有什么属性是很容易的事情,只要试着去检索该属性并验证取得的值。Typeof 操做符对肯定属性的类型有很大的帮助:

typeof flight.number            //'number'
typeof flight.status            //'string'
typeof flight.arrival           //'object'
typeof flight.manifest          //'undefined'
  • 注意任何原型链中的任何属性都会产生值:

typeof flight.toString           //'function'
typeof flight.constructor        //'function'

有两种方法处理掉这些不须要的属性。第一个是让你的程序作检查并丢弃值为函数的属性。另外一个就是使用 hasOwnProperty 方法,若是对象有独有的属性,它将返回 true
hasOwnProperty方法不会检查原型链。

fligth.hasOwnProperty('number')         //true
flight.hasOwnProperty('constructor')    //false

五、枚举 Enumeration

  • for in 语句可用来遍历一个对象中全部属性名。改枚举过程将会列出因此的属性——包括函数和你可能不关心的原型中的属性——因此不必过滤掉那些你不想要的值。最为经常使用的过滤器是 hasOwnProperty 方法,以及使用 typeof 来排除函数:

var name;
for(name in another_stooge) {
    if(typeof another_stooge[name] !== 'function') {
        document.writeln(name + ':' + another_stooge[name]);
    }
}
  • 属性名出现的顺序是不肯定的,所以要对任何可能出现的顺序有所准备。若是你想要确保属性以特定的顺序出现,最后的办法是彻底避免使用 for in 语句,而是建立一个数组,在其中以正确的顺序包含属性名:

var i;
var propertier = {
    'fiirst-name',
    'middle-name',
    'last-name',
    'profession'
};
for(i = 0; i< properties.length; i += 1) {
    document.writeln(properties[i] + ':' + another_stooge[properties[i]]);
}

经过 for 而不是 for in,能够获得咱们想要的属性,而不用担忧可能发掘出原型链中的属性,而且咱们按正确的顺序取得了它们的值。

六、删除 Delete

  • delete运算符能够用来删除对象的属性。若是对象包含该属性,那么该属性就会被移除。它不会触及原型链中的任何对象。

  • 删除对象的属性可能会让来自原型链中的属性透现出来:

another_stooge.nickname            //'Moe'
delete another_stooge.nickname;
another_stooge.nickname            //'Curly'

七、减小全局变量污染 Global Abatement

  • 全局变量削弱了程序的灵活性,应该避免使用。

  • 最小化使用全局变量的方法之一是为你的应用值建立一个惟一的全局变量:

var MYAPP = {};

该变量此时变成了你的应用的容器:

MYAPP.stooge = {
    "first-name": "joe",
    "last-name": "Howard"
};
MYAPP.flight = {
    airline: "Oceanic",
    departure: {
        IATA: "SYD",
        city: "Sydney"
    }
};
  • 只要把全局性的资源都归入一个名称空间下,你的这个程序与其余应用程序、组件或类库之间发生冲突的可能性就会显著下降。这个程序也会变得更容易阅读,由于很明显,MYAPP.stooge 指向的是顶层结构。还有一种有效减小全局污染的方法,隐藏信息的方法,就是 闭包

函数 Functions

一、函数字面量 Function Literal

  • 函数对象经过函数字面量来建立:

//建立一个名为 add 的变量,并用来把两个数字相加的函数赋值给它
var add = function(a,b) {
    return a + b;
};

函数字面量包括4个部分。

  • 第1个部分是保留字 function

  • 第2个部分是函数名,它能够被省略。函数能够用它的名字递归地调用本身。此名字也可能被调试器和开发工具用来识别函数。若是没有给函数命名,则它被成为匿名函数(anonymous)

  • 第3个部分是包围在圆括号中的一组参数。多个参数用逗号隔开。这些参数的名称被定义为函数中的变量。它们不像普通的变量那样被初始化为 undefined,而是在该函数被调用时初始化为实际提供的参数的值。

  • 第4个部分是包围在花括号中的一组语句。这些语句是函数的主体,它们在函数被调用是执行。

  • 函数字面量能够出如今任何容许表达式出现的地方。一个内部函数除了能够访问本身的参数和变量,同时它也能自由访问把它嵌套在其中的父函数的参数和变量。经过函数字面量建立的函数对象包含一个连到外部上下文的链接。这被称为 闭包(closure)。它是JavaScript强大表现力的来源!

二、调用 Invocation
调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每一个参数还接手两个附加的参数:thisarguments。参数 this 在面向对象编程中很是重要,它的值取决于调用的模式。在JavaScript中一共有4种调用模式:方法调用模式、函数调用模式、构造器调用模式和 apply 调用模式。这些模式在若是初始化关键参数 this 上存在差别。
调用运算符是跟任何产生一个函数值的表达式后的一对圆括号。圆括号中内可包含0个或多个用逗号隔开的表达式。每一个表达式产生一个参数值。每一个参数值被赋予函数声明时定义的形式参数名。当实际参数(arguments)和形式参数(parameters)的个数不匹配时,不会致使运行时的错误。若是实际参数值过多了,超出的参数值会被忽略。若是实际参数值过少,缺失的值被替换为 undefined 。对参数值不会进行类型检查:任何类型的值均可以被传递给任何参数。

  • 方法调用模式 The Method Invocation Pattern
    当一个函数被保存为对象的一个属性是,咱们称它为一个方法。当一个方法被调用时, this 被绑定到该对象。若是调用表达式包含一个提取属性的动做(即包含一个 . 点符号的表达式[subscript]下标表达式),那么它就是被当作一个方法来调用。

var myObject = {
  value :0;
  increment:function(inc){
    this.value += typeof inc ==='number'?inc:1;
  }   / /increment方法接受一个可选的参数,若是参数不是数字,默认使用数字1.  
};  
myObject.increment();
document.writeln(myObject.value);   // 1 

myObject.increment(2);  
document.writeln(myObject.value);   // 3

方法可使用 this 去访问对象,能从对象中修改该对象。this 到对象的每绑定发生在调用的时候,这个超级迟绑定使用函数能够对 this 高度复用。经过 this 可取得它们所属对象的上下文的方法称为公共方法

  • 函数调用模式 The Function Invocation Pattern

当函数并不是对象的属性时,它被看成一个函数来调用:

var sum = add(3, 4);          //sum的值为7

当函数以此模式调用时,this 被绑定到全局对象,这是语言设计上的一个错误。当内部函数被调用时,this 应该绑定到外部函数的 this 变量。解决方案是:若是该方法定义一个变量并给它赋值为 this ,那么内部函数就能够经过那个变量访问到 this,按照约定,命名为 that

myObject.double = function () {   // 给myObject增长一个double方法
  var that = this;             // 解决方法
  var helper = function() {
   that.value = add(that.value, that.value);  
  };
  helper();                     // 以函数的形式调用helper
};  
myObject.double();            // 以方法的形式调用double
document.writeln(myObject.Value());  //6
  • 构造器调用模式 The Constructor Invocation Pattern

JavaScript是基于原型继承的语言,意味着对象能够直接从其它对象继承属性,该语言是无类别的。
若是在一个函数前面带上new来调用,将建立一个隐藏链接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上。new前缀也会改变return语句的行为。

var Quo = function (string){       //建立构造器函数Quo,有status属性的对象
    this.status = string;
};
Quo.prototype.get_status = function() { //提供一个名为get_status的公共方法
    return this.status;  
};  
var myQuo = new Quo("confused");   //构造一个Quo实例
document.wirteln(myQuo.get_status());     //打印显示“confused”
相关文章
相关标签/搜索