代码改变世界

《javascript权威指南》读书笔记(连载)

2015-01-15 22:41  勤劳的插秧哥  阅读(405)  评论(0编辑  收藏  举报

这是一篇很长的博客

  终于把权威指南给买回来了,之前一直犹豫,第一:书太厚,怕买了不能坚持看完。第二:觉得太贵,最少100¥。现在实习也能发点工资了,给自己定了一个志愿:把一个月的工资用于买书。这么一想买本100¥的书也不是太大开销。好!买!为了坚持看完,我会把读书笔记发到博客上,督促自己,挑出知识点,弥补不足,也能加深自己的印象,一举n得,就这么定了。

开始reading:

 

1.

  js中的“ 假值” :false, undefined,null,0,-0,NaN,""(空字符串)  共7个  其余所有值全部为真。

  当js期望使用一个布尔值的时候,会把undefined,null,0,-0,NaN,"" 视为false。

2.

  浏览器在初始化时,全局对象的初始属性有:

  全局属性:undefined, Infinity,NaN

  全局函数:isNaN(), parseInt(), eval()

  构造函数:Date(), RegExp(), String(), Object(), Array()

  全局对象:Math, JSON

 3.

  == 会把undefined,null,0,-0,NaN,"" ,转换为false

  == 会把 字符串,数字,布尔的原始值和其包装类(对象)视为相等。===视为不等

 

4.

什么是动态语言?什么是静态语言?

动态语言:在运行期间才做数据类型检测的语言,也就是说在编译期间不会给变量指定数据类型。所以在写程序时不用声明类型。如:js,ruby,python
静态语言:在编译期间检测数据类型,要求在写程序时就要声明所有变量的数据类型。如:c/c++,java,c#

5.

所有对象继承了两个转换方法:toString(),valueOf()
对象转字符串:优先使用toString(),若没有则使用,valueOf(),还没有则抛出一类型错误异常。
对象转数字 :优先使用用valueOf(),若没有则使用toString(),还没有则抛出一类型错误异常。

6.(重点)

  js无块级作用域,取而代之的是“函数作用域”:变量在声明它的函数体内以及该函数嵌套的任意函数体内始终都是可见的,这也是js的变量声明被提前的原因。

  声明提前:js函数里声明的所有变量(**但不涉及赋值**),都被提前至函数的顶部。 ps:之前知道这回事,但一直理解错误,现在终于真相大白。

  如下代码:

  

var foo = "global"
function test(){
    console.log(foo); //undefined
    var foo = "local"; //不涉及赋值哦,亲
    console.log(foo); //local
}
test();

  上述代码等同于:

var foo = "global"
function test(){
    var foo; //先声明
    console.log(foo); //undefined
    foo = "local"; //后赋值
    console.log(foo); //local
}
test();

7.

  全局变量是全局对象(window)的属性,创建全局变量方式有三:

    1):全局下用 var

    2):全局下用this.变量名

    3):不用var,直接变量名

    除用正规方式在全局下用var声明的全局变量外,后两种方式声明的全局变量都是可以用delete删除 (可删除的变量称为对象的”可配置属性“)。

 

8.

  js查找变量(变量解析)时依照“作用域链” :查找时从链的第一个对象(本作用域)开始查找,有则用,没有则继续沿着链向上一层查找,直到找到全局window,若还是没找到说明该变量没有定义,抛出引用错误。

9.

  2+null 结果为2 (null解析为0,后做加法)

  2+undefined结果为NaN (undefined转换为NaN后做加法)

  1+{} 结果为1[object,object] (对象转换为字符串后再拼接,对象{XX:YY,aa:bb}转换字符串调用toString(),结果都为[object,object])

  true+true 结果为2 (true准换为1后相加)

  NaN == NaN 结果为false

  null == undefined 结果为true

  0 == false  结果为true

  “0” == false  结果为true

  “0” == 0  结果为true

 

10.

  typeof返回的是一个表示操作数类型的字符串

  注意:typeof(任意数字和NaN) 都返回“number”

  typeof(函数) 返回”function“

  typeof(数组) 返回”object“ 

 

 11.

  为什么 typeof(数组) 返回”object“?? 当我看到delete运算符我就明白了:

  因为delete不仅能删除对象(object)的属性,还可以删除数组元素。很明显js把数组也类似为对象一样处理

  但delete删除数组元素只是把元素总数组中”摘掉“,并不会影响数组长度,只是被删除的位置变为undefined。

12.

  void:

    void会忽略计算结果并返回undefined,因此当操作数具有副作用的时候用void让程序更有语义。

 

13.

  函数声明和函数定义表达式的区别:

    函数声明方式的函数具有“提前”特性。而用var的函数定义方式声明的函数只有变量声明提前,函数体(变量的初始化代码)仍然在原来的位置(参考笔记6)。所以函数声明方式创建的函数可以在声明之前调用它,而用var定义的不行,它更像一个表达式,类似于: var 变量=变量值; 最好在函数结尾的花括号后加“ ;” 。格式为var 函数名=function(){ };

14.

  for/in 并不会遍历对象的所有属性,只有“可枚举”的属性才会遍历。js核心定义的内置方法就不是“可枚举”的属性 如:toString()方法。而在代码中定义的所有属性和方法都是可枚举的(ECMA5中可使用特殊方法使可枚举的变为不可枚举的 6.7节会讲到)。对象继承而来的属性也可用for/in枚举。

  

第六章对象

15.(重点)

 

  对象:对象是js的基本数据类型,是一种复合值。也可看做是属性的无序集合,每个属性都是一个  键:值 队,属性名是字符串,所以对象也可看成是字符串到值的映射。除自身属性之外,js对象还可从一个称为原型的对象中继承属性。对象的方法通常是继承而来的属性,这种“原型式继承”是js的核心。

  对象是动态的:其属性可增可删。

  除  字符串,数字,布尔,null,undefined 外,其余js中的值全为对象。

    对象的属性可  创建,设置,查找,删除,检测,枚举。

16.

  原型:每一个js对象(null除外)都和另一个对象相关联,另一个对象就是原型,每个对象都从原型继承属性

  没有原型的对象为数不多,Object.prototype就是其中之一,它不继承任何属性,其他原型对象都是普通对象,普通对象都有原型。所有内置构造函数(以及大部分自定义的构造函数)都具有一个继承自Object.prototype的原型。如Date.prototype的属性继承自Object.prototype,因此有new Date()创建的Date对象的属性同时继承自Date.prototype和Object.prototype,这一系列链接的原型对象就是所谓的“原型链”。

 

17.

  Object.create()  (ECMAscript5 中定义,第一个参数是对象的原型,第二个可选参数是对对象属性进一步描述)

  可通过Object.create(null) 创建一个没有原型的新对象,新对象不会继承任何东西,甚至不包括基础方法如toString().

  创建一个普通的空对象o:

            (1)var o = Object.create(Object.prototype);   //可通过任意原型传建新对象。

            (2)var o = {};

            (3)var o = new Object(); 

  

 

18.

  强类型语言:为所有变量指定数据类型,在编译期间严格的检查变量数据类型。 (强/弱 指类型检查的严格程度)

  弱类型语言:类型检查很弱,只能严格的区分指令和数据。

  无类型语言:不检查数据类型,甚至不区分指令和数据。    

19.

  object.property

  object["property"] (像个数组,但是以字符串作为下标索引,字符串可以动态改变,所以此形式访问对象属性更灵活,这种形式称为:关联数组,散列,映射或字典)     

以字符串作为下标索引,字符串可以动态改变,所以此形式访问对象属性更灵活,如下代码:

var addr = "";
for(i = 0;i < 4; i++)
{
    addr += customer["address" + i] +"\n"
}
// 这段代码读取customer对象的address0,address1,address2,address3的属性,并将它们连接起来。

  用for/in循环遍历关联数组更加便利。

 

20.

  js中的数组:

    1.数组元素可以是任意类型。

    2.初始索引值为0,最大为4294967295(2的32次幂-2),因此数组最多能容纳(2的32次幂-1)个元素。

    3.数组是动态的,按需求增长或缩短,不需声明固定大小。  因此js数组永远不会爆出“数组越界错误”,只会得到undefined。

    4.数组是稀疏的,元素并不一定是连续的。   

 21.

  注意

    可使用负数或非整数来索引数组,这时这些“貌似不合法”的负数值或非整数就转换为字符串,这些被转换的字符串就当作属性名来使用:

a[-1.23] = true; //-1.23转为字符串“-1.23” ,将创建名为“-1.23”的一个属性

 

    可使用非负整数的字符串当作索引值,字符串就转换为数字,转换后的数字当作索引值使用,如:

a["1000"] = 0; //字符串"1000"转换为数字1000,代表索引值为1000的数组元素
a[1.000] // 1.000转换为数字1,代表索引值为1的数组元素

22.

  

23.

  数组的.length属性具有切割(甚至清空)或延长数组的作用:

a = [1,2,3,4,5]; //数组有5个元素
a.length = 3 //用.length属性切割长度为3,此时数组为:a[1,2,3]
a.length = 0 //用.length属性清空数组,此时数组为:a[]
a.length = 5 //用.length属性延长数组,此时数组为长度为5的空数组

ECMAScript5中可用Object.defineProperty()让length属性变为制毒,封住其“权利”:

a = [1,2,3];
Object.defineProperty(a,"length",{writable:false});  //变为只读
a.length = 0; //此时数组a不会改变

 

24.

  提高遍历数组时的性能:

for(var i = 0, len = key.length; i<len; i++)   //一次性检测长度并赋值给len,省的每次都要检测长度

剔除null,undefined 以及不存在的数组元素:

var a = [........];
for(var i = 0, len = a.length; i<len; i++)
{
    if (!a[i])  continue;  
    //循环体
}

同理 剔除undefined 和不存在的元素:

var a = [........];
for(var i = 0, len = a.length; i<len; i++)
{
    if (a[i] === undefined)  continue;  
    //循环体
}

同理 剔除不存在的元素,依然处理undefined元素:

var a = [........];
for(var i = 0, len = a.length; i<len; i++)
{
    if ( !(i in a) )  continue;  
    //循环体
}

25.

  join() 的逆向操作split()  

  join()约等于toString()

  reverse() 数组逆序

  sort()会把undefined放在最后,参见这篇博客  

  concat()数组拼接,注意:拼接时如果数组中的元素是数组:

 2015-03-19 看到第9章了,标记了这么多笔记,还要不要搬到博客上呢?