当前位置:   article > 正文

《JavaScript高级程序设计》读书笔记 【1~7章】_js高级程序设计读书笔记

js高级程序设计读书笔记

1.Javascript简介

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

1.1. ECMAScript

1.1.1. ECMAScript简介

ECMAScript是JavaScript的基础,它的宿主比如web浏览器可以给它提供实现与扩展,以便于实现针对环境的操作。

ECMAScript规定了语法、类型、语句、关键字、保留字、操作符、对象。

1.1.2. ECMAScript兼容

ECMA-262给出了ECMAScript兼容的定义。要想成为ECMAScript的实现,则该实现必须做到:

  1. 支持ECMA-262描述的所有“类型、值、对象、属性、函数以及程序句法和语义”( ECMA-262
  2. 支持Unicode字符标准。

此外,兼容的实现还可以进行下列扩展:

  1. 添加ECMA-262没有描述的“更多类型、值、对象、属性和函数”
  2. 支持ECMA-262没有定义的“程序和正则表达式语法”。

上述要求为兼容实现的开发人员基于ECMAScript开发一门新语言提供了广阔的空间和极大的灵活性。

1.2. 文档对象类型DOM

1.2.1. DOM简介

文档对象模型(DOM, Document Object Model )是针对XML但经过扩展以用于HTML的应用程序编程接口( API, Application Programming Interface )。

DOM把整个页面映射为一个多层节点结构。HTML或XML页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。例如:

在这里插入图片描述
在这里插入图片描述

1.2.2. DOM级别

DOM1级由两个模块组成: DOM核心( DOM Core)和DOM HTML。其中, DOM核心规定的是如何映射基于XML的文档结构,以便简化对文档中任意部分的访问和操作。DOM HTML模块则在DOM核心的基础上加以扩展,添加了针对HTML的对象和方法。

DOM1级的目标主要是映射文档的结构,而DOM2级在原来的基础上又扩充了鼠标和用户界面事件、范围、遍历(迭代DOM文档的方法)等细分模块,而且通过对象接口增加了对CSS (Cascading Style Sheets,层叠样式表)的支持。DOM1级中的DOM核心模块也经过扩展开始支持XML命名空间。

DOM2级引入了下列新模块,也给出了众多新类型和新接口的定义:

  • DOM视图( DOM Views):定义了跟踪不同文档(例如,应用CSS之前和之后的文档)视图的接口;
  • DOM事件( DOM Events):定义了事件和事件处理的接口;
  • DOM样式( DOM Style):定义了基于CSS为元素应用样式的接口;
  • DOM遍历和范围( DOM Traversal and Range):定义了遍历和操作文档树的接口。

DOM3级则进一步扩展了DOM,引入了以统一方式加载和保存文档的方法。

1.2.3. 其他DOM标准

W3C的推荐标准:基于XML:

  • SVG ( Scalable Vector Graphic,可伸缩矢量图) 1.0;
  • MathML ( Mathematical Markup Language,数学标记语言) 1.0;
  • SMIL ( Synchronized Mutimedia Integration Language,同步多媒体集成语言)。

1.3. 浏览器对象类型BOM

本质上,BOM处理浏览器窗口与框架,而习惯上将所有针对浏览器的JavaScript扩展都算作BOM:

  • 弹出新浏览器窗口的功能;
  • 移动、缩放和关闭浏览器窗口的功能;
  • 提供浏览器详细信息的navigator对象;
  • 提供浏览器所加载页面的详细信息的location对象;
  • 提供用户显示器分辨率详细信息的screen对象;
  • 对cookies的支持;
  • 像XMLHttpRequest和IE的Act iveX0bject这样的自定义对象。

2. HTML中使用JavaScript

HTML4.01为< script >定义了6个属性:

  1. async:针对外部脚本,异步,不影响其他文件的加载
  2. charset:指定字符集
  3. defer:针对外部脚本(IE7及之前可用于嵌入脚本),脚本延迟到文档完全解析与显示后执行
  4. language:已废弃,指定脚本语言
  5. src:指定外部脚本文件
  6. type:表示脚本语言的内容类型(MIME类型),通常默认text/javascript

外部脚本可以不是.js扩展名,但是需要确保服务器能正确返回MIME类型。

当不包含async与defer属性时,< script >元素将被按照先后顺序依次解析。

在head中包含的JS代码被加载、解析与执行完成后,才会呈现body中的页面,所以优化首屏加载速度应当将JS代码放在body后面。

包含defer属性的脚本(立即下载、延迟执行)执行顺序不定(理论上先后,实际中不定),最好只包含一个延迟脚本。包含async属性的异步脚本执行顺序不定,建议不要在加载期间修改DOM。

使用外部文件的优点:方便维护、可缓存、适应未来。

< noscript >标签的使用场景:

  • 浏览器不支持脚本;
  • 浏览器支持脚本,但脚本被禁用。

3. 基本概念

3.1. 语法

区分大小写

标识符,即变量、函数、属性名或函参,需要遵守:首字符为字母、下划线_、美元符号$,其他字符可为此基础上加数字。其中,字母可包含ASCII与Unicode但不推荐。惯用驼峰命名法。不可将关键字、保留字、true/false/null作为标识符。

严格模式:顶部添加“use strict”;将JavaScript引擎切换至严格模式,旨在处理ES3中的不确定行为与不安全操作。未经声明的变量赋值会在严格模式下抛出ReferenceError错误。定义名为eval或argument的变量也会报错。

3.2. 数据类型

typeof是操作符而不是函数,因此其后的圆括号并非必须。function属于object,但是拥有特别的属性,因此有必要使用typeof进行区分。

null与undefined

null表示空对象指针,因此typeof null返回object。

定义变量用于保存对象时应使用null,通过检查null值来判断是否已经保存了对象的引用。(if value != null)

变量声明后未初始化时,值为undefined。而未经声明的变量仅能执行typeof操作,并返回undefined。二者都返回undefined,代表均不可以进行真正的操作。

boolean

Boolean()函数用于转换为boolean值,false、空串“”、0与NaN、null与undefined将被转换为false值

流控制语句(如if语句)中会自动进行Boolean转换。

Number

Number:表示八进制时,首位为0,其余为0~7,若数值超出范围,前导0将被忽略,其后当做十进制解析八进制字面量在严格模式下无效、报错。而十六进制前导0x,其余位中A ~ F可为大小写。计算时,二者都被转化为十进制进行计算。

JavaScript可保存正负零,认定为相等。

小数点后无其他数字或为0时,浮点数值被解析为整数。

科学计数法:e代表10的指数幂。默认小数点后六位都是0则转换为e表示。

超出边界值的数值表示为正负Infinity。通过isFinit函数判断是否越界。
在这里插入图片描述
任何数值除0返回NaN(Not a Number),isNaN函数将判断参数是否可以转变为数值,参数为boolean:true时,true可被转换为1,因此isNaN(true)返回false。

数值转换:

Number() 函数的转换规则如下:

  1. 如果是Boolean值, true和false将分别被转换为1和0。
  2. 如果是数字值,只是简单的传入和返回。
  3. 如果是null值,返回0。
  4. 如果是undefined,返回NaN。
  5. 如果是字符串,遵循下列规则:
  • 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即“1.”会变成1,"123"会变成123,而011会变成11 (注意:前导的零被忽略了); .
  • 如果字符串中包含有效的浮点格式,如1.1 则将其转换为对应的浮点数值(同样,也会忽略前导零);
  • 如果字符串中包含有效的十六进制格式,例如0xf,则将其转换为相同大小的十进制整数值;
  • 如果字符串是空的(不包含任何字符),则将其转换为0;
  • 如果字符串中包含除上述格式之外的字符,则将其转换为NaN。
  • 如果是对象,则调用对象的valueOf ()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN, 则调用对象的tostring ()方法,然后再次依照前面的规则转换返回的字符串值。

parseInt() 函数会找到第一个非空格字符,若非数字或正负号则返回NaN,接着判断其后的字符,转换完成或遇到非数字字符时停止解析:“123blue”返回123,“22.5”返回22。此外,也可识别八进制与十六进制(识别前导0与0x)。ES3识别八进制前导0而ES5不识别,因此为parseInt提供第二个参数,即转换的基数(2,8,10,16)。

parseFloat()忽略前导0,因此十六进制字符串会始终被转换为0;解析到文末或遇到无效字符时终止,因此22.35.48会被转换为22.35。若字符串可被解析为整数则返回整数。

String

String可由单双引号表示。创建后不可变,更改时新建并销毁原串。null和undefined没有toString()方法。toString方法可以传入数值转换基数,以输出二进制等等任意有效进制格式表示的字符串。当不确定是否为null与undefined时,可使用String()方法,当值有toString方法则调用无参数的toString,否则对应返回“null”或“undefined”。

ECMAScript中,不给构造函数传递参数时,圆括号可以省略。

Object

Object的每个实例都具有下列属性和方法:

  • Constructor:保存着用于创建当前对象的函数。
  • hasOwnProperty (propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名( propertyName )必须以字符串形式指定(例如; o.hasOwnProperty (“name”) )。
  • isPrototype0f (object):用于检查传入的对象是否是另一个对象的原型
  • propertyIsEnumerable (propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。作为参数的属性名必须以字符串形式指定。
  • toLocalestring():返回对象的字符串表示,该字符串与执行环境的地区对应。
  • tostring():返回对象的字符串表示。
  • valueOf(): 返回对象的字符串、数值或布尔值表示。通常与tostr ing()方法的返回值相同。

BOM与DOM中的对象为宿主对象,由宿主实现提供与定义,可能不会继承Object。

操作符

前置递增递减在取值之前改变值,后置在取值之后改变值。

负数使用二进制补码存储,计算补码:

  1. 求这个数值绝对值的二进制码(例如,要求-18的二进制补码,先求18的二进制码);
  2. 求二进制反码,即将0替换为1,将1替换为0;
  3. 得到的二进制反码加1。

在对NaN与Infinity运用位操作符时,二者会被当做0处理。

~:NOT:按位非,相当于操作数负值减一。

^:XOR:按位异或:同为0,异为1。

左移<<不影响符号位,补0。对应有符号右移>>,保留符号位。

无符号右移>>>不保留符号位,正负一律补0。

:逻辑非:返回布尔值:对空串、数值0、null、NaN、undefined返回true,其余返回false。可用!!模拟Boolean()函数的行为。

&&:逻辑与:有一个操作数为null、NaN、undefined时返回对应值,未声明的变量会报错。两个操作数中包含对象时:第一个为对象则返回第二个,第二个为对象则当第一个求值结果为true时返回该对象,两个都是对象则返回第二个。

||:逻辑或:有一个操作数为null、NaN、undefined时返回对应值。包含对象的情况:第一个是对象则返回第一个,第一个求值为false返回第二个,两个都是对象则返回第一个。第一个为true而第二个未声明时第二个不会被求值,而第一个为false时第二个未声明会报错。

通常为变量赋予后备值来避免null或undefined:

var x = x1 || x2 ;
  • 1

大小比较:字符串大小比较时比较对应的字符编码值。当一方为数值时,另一方会进行数制转换。任何与NaN比较结果都为false。

相等与不相等:布尔值比较前转化为数值0/1,null 与 undefined 是相等的。任一为NaN则为不相等。**全等与不全等:仅在转换前相等时返回true。**推荐使用全等与不全等。
在这里插入图片描述
逗号操作符:在赋值时,逗号操作符会返回表达式的最后一项:

var num = ( 1, 2, 3); // var值为3
  • 1

3.3. 语句

使用for-in循环来遍历BOM中的window对象的所有属性:

for (var propName in window){
   
	document.write(propName);
}
  • 1
  • 2
  • 3
  • 4

在进行for-in循环之前,建议先检测对象值是否为null 或undefined。

3.4. 函数

ECMAScript中参数使用数组来表示,函数接收这个数组,在函数体内可以通过arguments对象来访问参数数组,通过其length属性来获取传入了多少参数。arguments的长度由输入的参数

因此,传递参数时并不一定需要按照定义的参数来进行。命名的参数只提供便利,而非必须。

命名参数可以与arguments[i]一同使用。当修改arguments[i]时,对应的命名参数也会被改变。二者并不访问相同的内存空间,他们的内存空间是独立的。ES5严格模式下,这种影响是单向的,改变命名参数时,并不会改变arguments中的值;非严格模式下,更改命名参数时arguments会相应更新。

函数可以返回任何值,未指定返回值时返回undefined。

ECMAScript中所有的参数传递的都是值,而非引用。

ECMAScript中的函数没有重载,后定义的会覆盖先定义的。

4. 变量、作用域与内存

4.1. 基本类型与引用类型

基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。

引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。

复制基本类型的值:创建新值、复制到新变量分配的位置上。复制的两个变量完全独立,不会相互影响。

复制引用类型的值:复制值到新空间中,该值实际上是指针,指向存储在堆中的一个对象。两个变量实际上引用同一个对象,改变其中一个,会影响另一个。

在这里插入图片描述
向函数传递基本类型的参数时,值会复制给一个局部变量,即命名参数(或者说是arguments的一个元素)。

而传递引用类型时,实际上是将这个值在内存中的地址复制给局部变量。因此此时,在函数内部的变化会反映在函数外部。

检测某个值是什么类型的对象,往往使用instanceof操作符,判断变量是否是给定引用类型的实例,根据原型链来识别。

所有引用类型都是Object的实例。
instanceof检测基本类型值会始终返回false,因为基本类型不是对象。

4.2. 执行环境

执行环境定义了变量或函数有权访问的其他数据。

每个执行环境对应关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。

全局执行环境是最外围的执行环境。根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样。在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。

某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出,例如关闭网页或浏览器时才会被销毁)。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

当代码在一个环境中执行时,会创建变量对象的一个作用域链( scope chain )。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用城链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象( activation object)作为变量对象。

活动对象在最开始时只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含它的(外部)环境,而再下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

标识符解析是沿着作用城链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直至找到标识符为止(如果找不到标识符,通常会导致错误发生)。

内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部的任何变量和函数。环境间的联系是线性的、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名。搜索标识符时,从作用域链前端开始向上搜索追溯到全局变量。

延长作用域链:try-catch语句的catch块会在作用域链的前端添加新的变量对象,其中包含被抛出的错误对象的声明。

没有块级作用域:if / for 等由花括号封闭的代码块没有自己的作用域,其中定义的变量会添加到其外部的执行环境。

4.3. 垃圾收集

JavaScript具有自动垃圾收集机制。函数中的局部变量在堆/栈上分配空间来存储值,当函数执行结束后释放内存。

标记清除:mark-and-sweep:最常用的垃圾收集方式。当变量进入环境时(比如在函数中声明变量),对变量标记“进入环境”,在离开环境时标记“离开环境”。

引用计数:reference counting:跟踪记录每个值被引用的次数。当一个值赋给变量时,该值的引用次数加一;当值赋给另一个变量时,引用次数 同样加一。相反,当包含该值的对象赋有了新的值,则该值引用次数减一。当一个值的引用次数为0时,则说明无法访问该值,因此可以回收其内存空间。但是,如果两个对象相互调用,则引用次数永远非0,导致占用内存无法回收。即循环引用问题。消除循环引用的方法:赋值null。

性能问题:垃圾收集器是周期运行的,重点在于确定垃圾收集器的收集间隔。

IE的垃圾收集器根据内存分配量运行,256个变量、4096个对象或64KB字符串中达到任何一个临界值都会触发运行。导致问题在于,若一个脚本中包含多变量,可能其生命周期中都一直保有多变量,而垃圾收集器就会频繁运行导致严重性能问题。

IE7发布后,改变为动态修正临界值:若垃圾收集例程回收的内存分配量小于15%,则临界值加倍;若大于85%,则临界值重置为默认值。

管理内存:一旦数据不再有用则赋值为null来释放引用,即解除引用(dereferencing)。

5. 引用类型

5.1. object类型

创建方式有两种,一是new操作符后跟Object构造参数,另一种是使用对象字面量方法:

var object = {
   
	name:"object",
	otherType:"...",
	//属性名可以为字符串、数值,数值会自动转化为字符串
	"size":260,
	5:true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

对象字面量可以作为向函数传递大量参数的方式:

func({
   
	k1:"v1",
	k2:"v2"
});

function func(args){
   ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

访问属性使用person.name或者person["name"],方括号的优势在于可以使用变量访问:

var s="name";
person[s]

  • 1
  • 2
  • 3

或者变量名会导致语法错误时:person["first name"],使用点号会因为空格导致语法错误。

一般使用点号来访问属性。

5.2. Array类型

ECMAScript数组的每一项都可以保存任何类型的数据,且可以自动调整大小根据内容增长

创建数组:使用构造函数new Array()Array(),传递数组的长度或内容:Array(20)Array("red","blue","yellow")。或者使用数组字面量表示法:var color= ["red","blue"];

数组不是只读的,可以向数组末尾移除或添加项:

var color= ["red","blue"];
//add
color.length = 3;
alert(color[2]);//undefined
//delete
color.length = 1;
alert(color[1]);//undefined
//add 
color[color.length] = "black";
//因为数组最后一项索引是length-1
//所以新项添加索引为length
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

检测数组value instanceof Array,但是instanceof假定单一的全局环境,若包含多个框架、存在多个不同的全局执行环境,则数组具有不同的构造函数。因此使用Array.isArray(value)来确定数组。

数组转换为字符串会返回数组中每一个值的字符串以逗号分隔的字符串,使用toLocaleString()toString()ValueOf()方法时,前二者调用每一项的对应方法,而后者调用toString()方法;三者默认都使用逗号分隔。使用join()方法可以使用其他分隔符来构建字符串:


var color= ["red","blue"];
alert(color.join("||"));
//red||blue
  • 1
  • 2
  • 3
  • 4

join()方法传入undefined或不传值时默认使用逗号分隔。

若数组中某一项值为nullundefined,则表示使用空串。

栈方法:使数组表现像栈一样后进先出、在栈顶插入(推入)和移除(弹出),使用数组的push()pop()方法,pop删除并返回数组的最后一项。

var colors=new Array();
colors.push("red","blue");//red,blue
colors.pop();//red
  • 1
  • 2
  • 3

队列方法:队列数据结构先进先出,在列表前端移除、在末端添加,使用push()shift()方法,shift删除并返回数组的第一个项。

var colors=new Array();
colors.push("red","blue");//red,blue
colors.shift();//blue
  • 1
  • 2
  • 3

unshift()方法与shift相反,在数组前端添加任意项并返回数组的长度。通过unshift()pop()方法可以模拟反向队列。

重排序方法:reverse()反转顺序。sort()升序:对每一项的toString()结果进行字符串比较。二者都返回重排序后的数组。此外可以向sort传入比较函数来决定顺序:

//适用于大多数数据类型
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/836901
推荐阅读
相关标签
  

闽ICP备14008679号