1

今天是2020年6月28日,再次拿起《javascript高级程序设计》这本红宝书,打算再啃一次。
下面出现的,都是我在啃的过程中,觉得需要注意的,所谓划重点~

第一章 javascript简介

javascript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
  • ECMAScript,由ECMA-262定义,提供核心语言功能;
  • 文档对象模型(DOM),提供访问和操作网页内容的方法和接口;
  • 浏览器对象模型(BOM),提供与浏览器交互的方法和接口。

    javascript的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari和Opera)中都得到了不同程度的支持。

第二章 在HTML中使用Javascript

HTML4.01为<script>元素定义了下列6个属性

  • async:可选。表示应该立即下载脚本。只对外部脚本文件有效。
  • charset:可选。表示通过scr属性指定的代码的字符集。极少用。
  • defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。相当于告诉浏览器立即下载,但延迟执行。只对外部脚本文件有效。
  • language:已废弃。
  • src:可选。表示包含要执行代码的外部文件。
  • type:可选。表示编写代码使用的脚本语言的内容类型。默认为type/javascript。

在使用<script>嵌入javascript代码时,不要在任何地方出现"</script>"字符串。
例如:

<script type="text/javascript">
    function sayScript(){
        alert("</script>");
    }
</script>

当浏览器遇到字符串"</script>"时,就会认为那是结束</script>标签。而通过把这个字符串分割为两部分可以完美的解决

look~

<script type="text/javascript">
    function sayScript(){
        alert("<\/script>");
    }
</script>

无论如何包含代码,只要不存在defer和async属性,浏览器都会按照<script>元素在页面中出现的先后顺序对它们依次进行解析。换句话说,在第一个<script>元素包含的代码解析完成之后,第二个才会被解析,然后第三个第四个......

对于标签的位置,按照惯例,所有的<script>元素都应该放在页面的<head>元素中。
可是呢,这种做法直接导致必须等到全部javascript代码都被下载、解析和执行完成以后,才可以尅是呈现页面的内容。对于那些需要很多javascript代码的页面来说,这无疑会导致浏览器在呈现页面时出现延迟,导致浏览器窗口一片空白。
这样不好不好~!
现代web应用一般都把全部的javascript引用放在<body>元素中页面的内容后面,请往下看:

<!DOCTYPE html>
<html>
  <head>
    <title>demo</title>
  <head>
  <body>
    <--  这里放内容  -->
    <script type="text/javascript" src="demo1.js"></script>
    <script type="text/javascript" src="demo1.js"></script>
  </body>
</html>
  • 使用defer属性可以让脚本在文档完全呈现之后再执行。延迟脚本总是按照指定它们的顺序执行。
  • 使用async属性可以表示当前脚本不必等待其他脚本,也不必阻塞文档呈现。不能保证异步脚本按照它们在页面中出现的顺序执行。

第三章 基本概念

标识符指标量、函数、属性的名字,或者函数的参数。标识符的规则如下:

  • 第一个字符必须是一个字母、下划线或一个美元符号;
  • 其他字符可以是字母、下划线、美元符号或数字。

注意!!!不可以用关键字命名
关键字包括以下:
image
另外还有一组不能用来作为标识符的保留字。尽量保留字在这门语言中还没有任何特定的用途,但它们有可能在将来被用作关键字。
以下是全部的保留字:
image

注意啦!!!let和yield是第五版新增的保留字!!

ECMAScript中有5种基本数据类型:Undefined、Null、Boolean、Number和String。还有一种复杂数据类型--Object。

typeof操作符能检测给定变量的数据类型:

  • "undefined"——如果这个值未定义;
  • "boolean"——如果这个值是布尔值;
  • "string"——如果这个值是字符串;
  • "number"——如果这个值是数值;
  • "object"——如果这个值是对象或null;
  • "function"——如果这个值是函数。
  1. undefined类型:在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。

    但是令人困惑的是,对未初始化的变量执行typeof操作符会返回undefined值,而对未声明的变量执行typeof操作符同样会返回undefined值。

  2. null类型:从逻辑来看,null值表示一个空对象指针,而这正是使用typeof操作符检测null会返回"object"的原因。
var car = null;
alert(typeof car);    // "object"

look!!
alert(null == undefined); //true
这里位于null和undefined之间的相等操作符总是返回true,但它们的用途完全不同。

无论什么情况下都没必要把一个变量的值显式的设置为undefined,可同样的规则对null却不适用。

只要意在保存对象的变量还没有真正保存对象,就应该明确让该变量保存null值,这样做不仅可以提现null作为空对象指针的惯例,还有助于进一步区分null和undefined。

3.boolean类型
boolean类型的字面值为true和false.虽然字面值只有俩,但ECMAScript中所有类型的值都有与这两个boolean值等价的值。
下表是各种数据类型及其对应的转换规则
imageimage

4.number类型
number类型:分为整数和浮点数值;
所谓浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须必须至少有一位数字。
对于极大活极小的数值,可以用e表示法,即科学计数法。
e表示法表示的数值 = e前面的数值 * 10的指数次幂。

var floatNum1 = 3.125e7;           //等于31250000(实际含义就是3.125*10的七次方)
var floatNum2 = 3e-7;               //等于0.0000003

浮点数值的最小精度是17位小数。但是呢,在算术计算时,它的精度远远不如整数。

例如:0.1加0.2的结果就不是0.3,而是0.30000000000000004。
但如果是0.05加0.25,或者是0.15加0.15都不会有问题。
因此,永远不要测试某个特定的浮点数值。

NaN,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况。
NaN与任何值都不相等,包括NaN本身。
针对NaN的这两个特点,ECMAScript定义了isNaN()函数。可以接受一个参数,该参数可以是任何类型。
isNaN()在接收到一个值后,会尝试将这个值转换为数值。某些不是数值的值会直接转换为数值,而任何不能被转换为数值的值都会导致这个函数返回true

alert(isNaN(NaN));             //true
alert(isNaN(10));             //false (10是一个数值)
alert(isNaN(“10”));             //false(可以被转换为数值10)
alert(isNaN(“blue”));             //true (不能转换成数值)
alert(isNaN(true));             //false (可以转换成数值1)
数值转换

数值转换:有三个函数可以把非数值转换为数值:Number() parseInt()和parseFloat()。
Number()函数用于任何数据类型,另两个函数则专门用于吧字符串转换为数值。
Number()函数的规则如下:

  • 如果是Boolean值,true和false将分别被转换为1和0.
  • 如果是数字值,只是简单的传入和返回。
  • 如果是null值,返回0.
  • 如果是undefined,返回NaN。
  • 如果是字符串,遵循下列规则:

    • 如果字符串只包含数字,则将其转换为十进制数值。”1”会变成1,”123”会变成123,而”011”会变成11;
    • 如果字符串中包含有效的浮点格式,如”1.1”,则将其转换为对应的浮点数值;
    • 如果字符串中包含有效的十六进制格式,则将其转换为相同大小的十进制整数值;
    • 如果字符串是空的,则将其转换为0;
    • 如果字符串中包含除上述格式之外的字符,则将其转换为NaN。
  • 如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。

这么多规则,累了累了~看看下面的栗子吧!!!

var num1 = Number(“hello world!”);            //NaN
var num2 = Number(“”);                       //0
var num3 = Number(“000011”);                //11
var num = Number(“true”);                  //1

由于Number()函数在转换字符串时比较复杂,因此在处理整数的时候,更常用的是parseInt()函数。
废话不多说,看下面栗子小姐姐吧!

var num1 = parseInt(“”1234blue);        //1234
var num2 = parseInt(“”);                //NaN
var num3 = parseInt(“0xA”);             //10(十六进制数)
var num4 = parseInt(“22.5”);            //22
var num5 = parseInt(“070”);             //56(八进制数)
var num6 = parseInt(“70”);              //70(十进制数)
var num7 = parseInt(“0xf”);             //15(十六进制数)

为了消除在使用parseInt()函数时的一些不必要的困惑,可以为这个函数提供第二个参数:转换时使用的基数(即多少进制)。
例如:
var num = parseInt(“0xAF”, 16); //175

与parseInt()函数类似,parseFloat()也是从第一个字符开始解析。
字符串中第一个小数点是有效的,第二个小数点就是无效的了。
还是来看可耐的栗子小姐姐吧~~

var num1 = parseFloat(“1234blue”);             //1234(整数)
var num1 = parseFloat(“0xA”);             //0(十六进制的字符串始终会被转换成0)
var num1 = parseFloat(“22.5”);             //22.5
var num1 = parseFloat(“22.34.5”);             //22.34
var num1 = parseFloat(“0908.5”);             //908.5
var num1 = parseFloat(“3.125e7”);             //31250000

5.string类型
string类型即字符串,它的特点是不可变,也就是说字符串一旦创建它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。

要把一个值转换为一个字符串有两种方式,toString()方法和string()方法

数值,布尔值,对象和字符串值都有toString()方法。但是呢,null和undefined值没有这个方法。

在不知道要转换的值是不是null或undefined的情况下么,可以用转型函数String(),它能将任何类型的值转换为字符串,规则如下:

  • 如果值有toString()方法,则调用该方法返回相应的结果;
  • 如果值是null,则返回”null”;
  • 如果值是undefined,则返回”undefined”;

6.object类型
var o = new object();
object的每个实例都具有下列属性和方法。
Constructor:保存着用于创建当前对象的函数。
hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中是否存在。o.hasOwnProperty("name")
isPrototypeOf(object):用于检查传入的对象是否是另一个对象的原型。
propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
toString():返回对象的字符串表示。
valueOf():返回对象的字符串、数值或布尔值表示。

操作符

操作符包含算术操作符、位操作符、关系操作符和相等操作符。

1. 一元操作符

1.1 递增和递减操作符
    var num1 = 2;
    var num2 = 20;
    var num3 = --num1 + num2         //输出21
    var num4 = num1 + num2           //输出21
    var num1 = 2;
    var num2 = 20;
    var num3 = num1-- + num2         //输出22
    var num4 = num1 + num2           //输出21

递增和递减操作符不仅适用于整数,还可以用于字符串、布尔值、浮点数值和对象。规则如下:

  • 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减1的操作。字符串变量变成数值变量。
  • 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN。字符串变量变成数值变量。
  • 在应用于布尔值false时,先将其转换为0再执行加减1的操作。布尔值变量变成数值变量。
  • 在应用于布尔值true时,先将其转换为1再执行加减1的操作。布尔值变量变成数值变量。
  • 在应用于浮点数值时,执行加减1的操作。
  • 在应用于对象时,先调用对象的valueOf()方法,以取得一个可供操作的值。然后对该数值应用前述规则。

还是来看🌰栗子小姐姐~~~

var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
    valueOf: function(){
        return -1;
    }
};
s1++;    //值变成数值3
s2++;    //值变成NaN
b++;     //值变成1
f--;     //值变成0.10000000000000009(由于浮点舍入错误所致)
o--;     //值变成-2

1.2 一元加和减操作符
一元加操作符以一个加号(+)表示,放在数值前面,对数值不产生任何影响。
一元减操作符用于表示负数,例如将1转换成-1

var num = 25;
 num = +num;    //仍然是25
 
 var num = 25;
 num = -num;    //变成了-25

2.位操作符

按位非(NOT)操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。
按位与(AND)操作符由一个和号字符(&)表示,只有在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0。
按位或(OR)操作符由一个竖线符号(|)表示,有一个位是1的情况下就返回1,而只有在两个位都是0的情况下才返回0。
按位异或(XOR)操作符由一个插入符号(^)表示,和按位或不同的是,这个操作在两个数值对应位上只有一个1时才返回1,如果对应的两位都是1或都是0,则返回0。

3.布尔操作符

1.1逻辑非
逻辑非操作符由一个叹号(!)表示,无论这个值是什么数据类型,都会返回一个布尔值,遵循以下规则:

  • 如果操作数是一个对象,返回false;
  • 如果操作数是一个空字符串,返回true;
  • 如果操作数是一个非空字符串,返回false;
  • 如果操作数是数值0,返回true;
  • 如果操作数是任意非0数值,返回false;
  • 如果操作数是null,返回true;
  • 如果操作数是NaN,返回true;
  • 如果操作数是undefined,返回true;
    alert(!false);     //true
    alert(!"blue");     //false
    alert(!0);     //true
    alert(!NaN);     //true
    alert(!"");     //true
    alert(!12345);     //false

1.2逻辑与
逻辑与操作符由两个和号(&&)表示,应用于任何类型的操作数,不仅仅是布尔值。
存在一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值,规则如下:

  • 如果第一个操作数是对象,则返回第二个操作数;
  • 如果第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象;
  • 如果两个操作数都是对象,则返回第二个操作数;
  • 如果有一个操作数是null,则返回null;
  • 如果有一个操作数是NaN,则返回NaN;
  • 如果有一个操作数是undefined,则返回undefined;

image

逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。
对于逻辑与操作而言,如果第一个操作数是false,则无论第二个操作数是什么值,结果都不再可能是true了。

1.3逻辑或
逻辑或操作符由两个竖线符号(||)表示,与逻辑与相似。规则如下
如果第一个操作数是对象,则返回第一个操作数;
如果第一个操作数的求值结果为false,则返回第二个操作数;
如果两个操作数都是对象,则返回第一个操作数;
如果两个操作数都是null,则返回null;
如果两个操作数都是NaN,则返回NaN;
如果两个操作数都是undefined,则返回undefined;
image

4.乘性操作符

ECMAScript定义了三个乘性操作符:乘法、除法和求模。
乘法操作符由一个星号(*)表示,用于计算两个数值的乘积。
除法操作符由一个斜线符号(/)表示,执行第二个操作数除第一个操作数的计算
求模操作符由一个百分号(%)表示,用于返回除得的余数

5.加性操作符

加法操作符(+)执行常规的加法计算

var result1 = 5 + 5       //两个数值相加
alert(result1);           //10
var result2 = 5 + "5"     //一个数值和一个字符串相加
alert(result2);           //55

忽视加法操作中的数据类型是ECMAScript编程中最常见的一个错误。

var num1 = 5;
var num2 = 10;
var message = "the sum of 5 and 10 is" + num1 + num2;
alert(message);      //"the sum of 5 and 10 is 510"

如果想要得到真的算术计算,可以使用圆括号:

var num1 = 5;
var num2 = 10;
var message = "the sum of 5 and 10 is" + (num1 + num2);
alert(message);      //"the sum of 5 and 10 is 15"

减法操作符(-)是另一个极为常用的操作符
直接给大家把栗子🌰端上来~~

var result1 = 5-true;       //4  因为true被转换成了1
var result2 = NaN - 1;      //NaN
var result3 = 5 - 3;        //2
var result4 = 5 - "";       //5,因为""被转换成了0
var result5 = 5 - "2";      //3,因为"2"被转换成了2
var result6 = 5 - null;     //5,因为null被转换成了0

6.关系操作符

小于、大于、小于等于和大于等于这几个关系操作符用于对两个值进行比较,规则和我们数学课所学的一样哟。这几个操作符都返回一个布尔值。
规则总结下来就是:

  • 如果是数值直接比较;
  • 如果都是字符串,就比较字符串的字符编码;
  • 如果一个不是数值,则转换成数值比较;
  • 如果一个是对象,则用对象的valueOf()方法,再比较;
var result1 = "23" < "3";        //true 因为俩都是字符串,比较的是字符编码
var result2 = "23" < 3;         //false 会将"23"转换成数值23,再与3比较
var result3 = "a" < 3;          //false 因为"a"被转换成了NaN  任何操作数与NaN进行关系比较都是false
var result4 = NaN < 3;          //false
var result4 = NaN >= 3;         //false

7.相等操作符

相等和不想等 (==) (!=)
这两个操作符都会先转换操作数(通常称为强制转换),然后再比较它们的相等性。
这两操作符在进行比较式遵循以下规则:
null 和undefined是相等的。
要比较相等性之前,不能将null和undefined转换成其他任何值。
如果有一个操作数是NaN,则相等操作符返回false,不想等操作符返回true。即使两个操作数都是NaN,相等操作符也返回false,因为NaN不等于NaN。
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true,否则返回false。
image

全等和不全等 (===) (!==)
除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不想等操作符没有什么区别。

var result1 = ("55" == 55);           //true,因为转换后相等
var result2 = ("55" === 55);          //false,因为不同的数据类型不想等,因为不用转换直接比较
var result3 = ("55" != 55);           //false,因为转换后相等
var result4 = ("55" !=== 55);         //true,因为不同的数据类型不想等,因为不用转换直接比较
记住:null == undefined会返回true;但null === undefined会返回false

8.条件操作符

var max = (num1 > num2) ? num1 : num2;
max会保存一个最大的值,它的意思是:如果num1大于num2,则将num1的值赋给max;如果num1小于或等于num2,则将num2的值赋给max。

9.赋值操作符

image

10.逗号操作符

var num1 = 1,
    num2 = 2,
    num3 = 3;

语句

1.if语句
image

2.do-while语句
do-while语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件。
换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次!!!

var i = 0;
do{
    i += 2;
} while (i < 10);
alert(i);  //10

3.while语句
while语句属于前测试循环语句,即在循环体内的代码被执行之前,就会对出口条件求值。
因此,循环体内的代码有可能永远不会被执行!!!

var i = 0;
while(i < 10){
    i += 2;
}
alert(i);  //10

4.for语句
for语句也是一种前测试循环语句,但它具有在执行循环之前初始化变量和定义循环后要执行的代码的能力。

var count = 10;
for(var i = 0; i < count ;i++){
    alert(i);
}

如果执行了循环体中的代码,则一定对循环后的表达式(i++)求值,即递增i的值。
这个for循环语句同下面的while语句功能相同:

var count = 10;
var i = 0;
while(i < count){
    alert(i);
    i++;
}

无限循环~~~~

for (;;){
    doSomething();
}

5.for-in语句
for-in用来枚举对象的属性

for (var propName in window) {
    document.write(propName);
}

在上面例子中,for-in循环来显示了BOM中window对象的所有属性,每次循环执行时,都会将window对象中存在的一个属性名赋值给变量propName。存在兼容性~~

6.label语句
配合下面的语句一起举例哈,耐心往下看吧~

7.break和continue语句
break语句会立即退出循环,强制继续执行循环后面的语句。
continue语句虽然也是立即退出循环,但退出循环后会从循环的顶部继续执行,直到结束。

var num = 0;
for(var i = 1; i < 10;i++) {
    if(i % 5 == 0) {
        break;
    }
    num++;
} 
alert(num);      //4 在变量i等于5时,循环总共执行了4次,而break语句的执行,导致循环在num再次递增之前就推出了。
var num = 0;
for(var i = 1; i < 10;i++) {
    if(i % 5 == 0) {
        continue;
    }
    num++;
} 
alert(num);     //8  当变量i等于5时,循环会在num再次递增前退出,但接下来执行的是下一次循环,即i的值等于6的循环,于是循环又继续执行,直到i等于10的时候自然结束。而num最终等于8是因为continue语句导致它少递增了一次。

下面看break和continue语句都可以与label语句联合使用,从而返回代码中的特定位置。

var num = 0;
outermost:
for(var i = 1; i < 10;i++) {
    for(var j = 1; j < 10;j++) {
        if(i == 5 && j == 5) {
            break outermost;
        }
        num++;
    } 
} 
alert(num);    //55

如果每个循环正常执行10次,则num++正常执行100次。num的值应该是100.但内部循环中的break带了一个参数,要返回到的标签。添加的这个标签导致不仅会退出内部for循环,也会退出外部循环。
看下continue的效果:

var num = 0;
outermost:
for(var i = 1; i < 10;i++) {
    for(var j = 1; j < 10;j++) {
        if(i == 5 && j == 5) {
            continue outermost;
        }
        num++;
    } 
} 
alert(num);    //95

在这种情况下,continue语句会退出内部循环,执行外部循环。当j是5时,continue执行,意味这内部循环少执行了5次。

8.with语句
with语句的作用是将代码的作用域设置到一个特定的对象中
with(location){

var qs = search.substring(1);
var hostName = hostname;

}
image

9.switch语句

switch (i) {
 case 25:
  alert(“25”);
  break;
 case 35:
  alert(“35”);
  break;
 case 45:
  alert(“45”);
  break;
 default:
  alert(“other”);
}

函数

函数会在执行完return语句之后停止并立即退出。因此,位于return语句之后的任何代码都永远不会执行。

function sum(num1, num2) {
 return num1 + num2;
 alert(“hello world”);        //永远不会执行
}

另外return语句也可以不带有任何返回值。在这种情况下,函数在停止执行后将返回undefined值。这种用法一般用在需要提前停止函数执行而又不需要返回值的情况下。

严格模式对函数有一些限制:

  • 不能把函数命名为eval或arguments;
  • 不能把参数命名为eval或arguments;
  • 不能出现两个命名参数同名的情况。

容我再啰嗦一下,为大家献上本章最终的小结~~

  • ECMAScript中的基本数据类型包括Undefined,Null,Boolean,Number和String。
  • 与其他语言不同的是,ECMAScript没有为整数和浮点数值分别定义不同的数据类型,Number类型表述所有数值。
  • ECMAScript中也有一种复杂数据类型,即Object类型,是这门语言中所有对象的基本类型。
  • 严格模式为这门语言中容易出错的地儿施加了限制。
  • ECMAScript提供了操作符,包括算术操作符,布尔操作符,关系操作符,想等操作符几赋值操作符等。
  • ECMAScript从其他语言中借鉴了很多流控制语句,例如if语句,for语句和switch语句等。
  • 无须指定函数的返回值,因为任何ECMAScript函数都可以在任何时候返回任何值。
  • ECMAScript中没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式传递的。
  • 可以向ECMAScript函数传递任意数量的参数,并且可以通过arguments对象来访问这些参数。
  • 由于不存在函数签名的特性,ECMAScript函数不能重载。

未完待续、晚安宝宝们~😚


前端小饼干
1 声望4 粉丝