JavaScript高三上

前言

《JavaScript高级程序设计(第三版)》是js语言里面的圣经。去年8月份,我匆匆看过一遍。里面讲的知识点挺全的。最近几周又重读它,对一些基础知识体会更深了。自己终将会把这本书里面所有的知识点记在脑子里面。防止以后再忘记,方便以后回忆起来js的重点。所以有必要记录一下书中,自认为的重点。

JavaScript的组成

JavaScript是由三部分组成的。

  • ECMAScript: 这是js的语法。ECMA是一个指定标准的组织。JavaScript的语法具体是通过 ECMA-262 标准来指定的。网址为:http://ecma-international.org/publications/standards/Ecma-262-arch.htm
    现在比较流行的是ES6。
  • DOM:文档对象模型。我理解的就是w3组织留给各种语言的api。只不过JavaScript一直在用这些api,其他编程语言基本上不用。所以导致大家认为DOM是JavaScript里面的一部分。其实就是ECMA和w3 这俩大组织之间的py交易。为了方便交流。
  • BOM:浏览器对象模型。和DOM差不多,只不过变成了各个浏览器厂商和ECMA之间的py交易。浏览器厂商根据w3组织约定好的规范,给JavaScript留下的接口。有意思的是w3组织里面,管事的人,有很大的一部分就是浏览器厂商。所以基本上他们之间的关系也很明显了。

    JavaScript的数据类型

    什么是数据类型呢?在计算机当中,归根结底是0和1之间的较量。所有的数据最终都会被CPU解析成0和1.从0和1,到汇编,到各种编程语言,最终都是为了方便人类与计算机的交流。人类最开始用0和1与计算机进行交流,后来通过一些简单的英文字母(汇编)进行交流,再后来通过稍微复杂的英文字母(编程语言,比如js)进行交流。数据类型 就是一些稍微复杂的英文字母中的一部分。计算机会根据数据类型的不同字母,将这些数据放到不同的内存中(比如栈内存,堆内存)等。因为把相似的数据放到一块,计算机计算起来也会很省力。不同的编程语言会根据自己的“哲学”体系会定义不同的数据类型。不同的语言也会相互借鉴,形成了一种百家齐鸣的现象。对我来说,我看好反应式编程语言,也就是lisp体系。

在ES5中,有 5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number
和 String。还有 1种复杂数据类型——Object,Object 本质上是由一组无序的名值对组成的。ECMAScript不支持任何创建自定义类型的机制,而所有值最终都将是上述 6 种数据类型之一。
这里的知识点比较多,我只记录我认为自己容易忘记和工作中常用的几个点:

  • 无论在什么情况下都没有必要把一个变量的值显式地设置为 undefined;而对于null来说,如果某个变量想要保存对象,那么就要显示赋值为 null 值 ,这样可以体现 null 作为空对象指针的惯例,
  • 各种数据类型如何转换为Boolean
  • NaN和isNaN()函数,Number()、parseInt()和 parseFloat()三个函数是如何转换的。
  • Object类型,其实一个类。实例就是将类具体化。类比 人类(类) 和 张三(实例) 这个人。在es5语法中,function 一般用来定义一个类,例如function Person(),比较有意思的是,Person不仅仅是一个“类”,同时也是一个“实例”(是Object的实例)。比如 var p1 = new Person(),当Person作为“类”使用的时候,那么p1是Person的实例;当Person作为“实例”的时候,那么Person是Object的实例。然后它们三个直接通过一个叫做proto__的属性指向自己的类。就形成这样的链 p1.__proto ==> Person; Person.proto ==> Object 这就是原型链。
    其实上面的表述还不是很正确。每个实例指向的其实是,自己类里面的一个叫做 prototype属性。那么真正的原型链是这样的 p1.proto ==> Person.prototype; Person.proto ==> Object.prototype .
    这个 prototype 是一个对象,叫做 原型对象。所有的原型对象都会自动获取一个叫做constructor属性,这个属性是一个函数(也就是类),这个属性包含一个指向 prototype 属性所在类的指针。为啥要这么做呢?因为通过这个构造函数,还可以继续为原型对象(也就是“类”里面的 prototype属性)添加其他属性和方法。

有关操作符

这部分内容,经常有人搞混布尔操作符和一些比较性操作符。比如:

1
2
console.log(true == 'true') //false
console.log(false == 'false') // false

这里都会返回false。这里有人看到true和false就会认为 ‘true’和’false’都是非空字符串,会转换为true,那么true == ture 应该返回true。然而 == 操作符是比较类型的操作符,和大于,小于,大于等于,小于等等于是一样的。这时候应该 == 操作符俩边的操作数应该向Number类型转换,因此逻辑是这样的。Number(ture) == Number(‘ture’) ==> 1 == NAN ,所以返回的false。
还有一部分就是 + 操作符在字符串中是当做连字符使用的。
还有就是

1
var num = (5, 1, 4, 8, 0); // num 的值为 0 

逗号操作符多用于声明多个变量;但除此之外,逗号操作符还可以用于赋值。在用于赋值时,逗号
操作符总会返回表达式中的最后一项

语句控制流程相关

语句中,我现在是习惯用
variable = boolean_expression ? true_value : false_value
能这样写就这样写,不用if else语句了。
然后for-in的使用,经常用来迭代数组,对象的属性等等。

函数相关

重点就是有关 arguments的介绍了。在创建函数的时候,例如function fun1(a1,a2){};
当我们调用 fun1.length() ,返回的是2,是形成的个数。当我们调用fun1(1,2,3){console.log( arguments.length() )}的时候,返回的是3,是实参的个数。

  • 然后就是函数没有重载,因为 arguments 可以在函数内部实行重载的功能。同时函数其实也是一个对象,一种变量,所以只会覆盖,不会重载。

作用域和内存问题

  • ECMAScript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。有不少开发人员在这一点上可能会感到困惑,因为访问变量有按值和按引用两种方式,而参数只能按值传递

上面的话,理解起来会很难受。可事实就是那样的。没学过c++的人,可能会很难理解引用是什么鬼。引用就是字面上的“引用”,就是不去真正的把它拿过来,只是通过“引用”,比如通过你的室友勾搭你,通过你的老师勾搭你,这种中间隔了一层就是“引用”。

  • 如何判断变量类型,理论说分为俩种
    1、typeof 操作符是确定一个变量是字符串、数值、布尔值,还是 undefined 的最佳工具
    2、result = variable instanceof constructor 判断null和对象的。

  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境; 变量的执行环境有助于确定应该何时释放内存。

  • JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。

    引用类型

    引用类型包含了Object、Array、Date、RegExp、Function、包装类型(Boolean,Number,String)、单体内置类型(Global、Math)。
    这一章的内容比较多,这里的多是需要记忆的比较多。无论哪种类型,都需要记忆一部分API。虽然自己基本上都记住了,但还是怕遗忘。之后还是需要特意写一篇文章,或者xmind进行总结。

这一章的包装类型(Boolean,Number,String)对应这基本类型的(Boolean,Number,String)。这让我想起之前去转转面试的一道题目。

1
2
3
var str = 'aa'; str.replace();
面试官问我,str.replace()是怎么执行的。
我当时又困又懵逼。加上半年不用js。诚实的回答了。我不知道。

其实这道题就能体现你对js面向对象的理解。str 本身是基本类型。不可能会有方法的。其中的奥秘就是包装类型。《高三》上面是这么说的,str.replace()执行的时候,会先建立一个对象 var str = new String(‘aa’), 然后执行str的replace()方法,最后将结果值返回给str。str还是基本类型。js引擎会将对象的内存释放。

还有一个关于正则里面的知识点:

  • 对于 exec()方法而言,即使在模式中设置了全局标志(g),它每次也只会返回一个匹配项。在不
    设置全局标志的情况下,在同一个字符串上多次调用 exec()将始终返回第一个匹配项的信息。而在设
    置全局标志的情况下,每次调用 exec()则都会在字符串中继续查找新匹配项,

    结尾

    后面还有面向对象和函数表达式,DOM,事件等等重要的内容。虽然我也看了好几天了。但是感觉还有好几个点没有理解。所以放到 下篇博客。