《JavaScript高级程序设计(第3版)》学习笔记(一)

* 文中部分内容为《JavaScript高级程序设计》一书中的内容


第一章 JavaScript简介

JavaScript诞生于1995年,最开始仅用于处理输入验证操作,之后发展成为一门功能全面的编程语言。

JavaScript有三个重要组成部分:

1. ECMAScript —— 核心:对实现该标准规定的各个方面内容的语言描述,ECMAScript是标准,JavaScript是对ECMAScript的实现。本书基于ES5(ECMAScript5)进行讲解,即于2009年12月3日发布的版本。

2. DOM —— 文档对象模型:其将整个页面映射为一个多层结点的结构,提供访问和操作页面内容的方法和接口。DOM1(映射结构)、DOM2(视图、事件、样式,遍历和范围)、DOM3级(扩展:统一方式加载和保存文档、文档验证、对DOM核心进行扩展)。

3. BOM —— 浏览器对象模型:提供与浏览器交互的方法和接口。


第二章 在HTML中使用JavaScript

通过<script>标签进行JavaScript代码的插入

标签位置一般放在页面最后,即</body>前

<noscript>标签:早期浏览器有些不支持script标签,用此标签来平稳退化

重要属性:

1. src:外部文件路径

2. defer: 延迟脚本,立即下载,延迟执行,当文档完全被解析和显示之后再执行,仅对外部文件有效,总是按照插入顺序执行。

3. async: 异步脚本,立即下载该脚本,但不妨碍页面的其他操作,仅对外部文件有效,不保证执行顺序

两种使用方法:

1. 直接在页面中嵌入JavaScript代码,并用<script>包裹

2. 使用src,将外部JavaScript文件引入


第三章 基本概念

大小写敏感,语句末尾;号,可省略但不建议,建议始终在控制语句中使用代码块

松散类型变量,变量可存储任何类型的数据

未初始化的变量,值为undefined,未声明的变量也保存undefined

标识符:即变量、函数、属性名字、函数参数

命名规范:字母、数字、下划线、$符号,其中不能以数字开头,ES标准采用驼峰大小写格式

注释:

// 单行注释

/*

* 多行注释

*/

关键字&保留字:

不能作为标识符

var用于声明变量,不使用var则声明了一个全局变量

数据类型:

1. Undefined: 其值为undefined,派生自null,因此undefined == null返回true

2. Null: 其值为null,表示一个空对象指针

3. Boolean:其值有true和false,大小写敏感,因为JS大小写敏感,JS中所有类型的值都有其对应的Boolean值;“”、0、undefined、null、NaN——false;非空字符串、非零数字、任何对象——true

4. Number:十进制为最基本数字字面量格式,浮点数值、整数值、NaN

5. String:"&' 都可以,但必须成对出现,length属性,字符串由0或多个Unicode字符组成

6. Object: 数据和功能的集合,Object是所有它的实例的基础,是所有对象的基础

前五个为简单数据类型,也称为基本数据类型;最后一个为复杂数据类型

typeof操作符,不是函数,用于判断变量的数据类型,其中 typeof null == Object

typeof 一个函数 == function

Number:

NaN非数值,其与任何值都不相等,包括它自己;任何涉及NaN的操作,都会返回NaN,isNaN()函数,该函数接收到参数时,会尝试将参数转为数值,同Number()函数

数值转换:Number(), null=>0、undefined=>NaN、"123hhhh"=>NaN

parseInt(), 在处理字符串时,若第一个字符不是数字或符号,则返回NaN,其他如: “123hhh”=>123

parseFloat(),仅解析十进制,且始终忽略前导零

String:

字符串转换:toString()方法,其中undefined和null没有此方法

String()转型函数,若存在toString()方法,则调用toString(),若为null=>"null"、undefined=>"undefined"

Object:

每个Object都有如下属性和实例:constructor、hasOwnProperty()、isPrototypeOf()、propertyIsEnumerable()、toLocalString()、toString()、valueOf()

操作符:

一元操作符 

递增/递减:++、--,分前置和后置,前置则表示先执行++/--,再执行当先所在表达式,后置相反

一元加/减:+、- ,其中一元加,可用于将变量转为数值,同Number()

位操作符:

布尔操作符:

非:!,此操作符始终返回一个布尔值,同时使用!!可获得当前变量对应的Boolean值,同Boolean()函数

与:&& 短路操作

或:|| 短路操作、可用于赋值时,提供备用值,避免出现变量赋值为null/undefined

乘性操作符:* / % 乘 除 模

加性操作符: + -,其中加法可用于字符串拼接

关系操作符:> < >= <= 均返回一个布尔值,优先数值比较,即当一个操作数为数值,则将另一个操作数转为数值再进行比较;若一个操作数是布尔值,也将其先转化为数值;两个字符串的比较,实际上是比较字符串的编码值。

相等操作符: == != 相等&不相等,先转换再比较 === !== 全等&不全等,仅比较

转换时优先数值比较,但是null和undefined做比较前,不会被转换为数值。

null == undefined =>true

null == 0  =>false undefined == 0 =>false

条件操作符:variable = boolean_expression ? true_value : false_value

赋值操作符:= 右边赋值给左边

语句:

if...else...

do-while

for: 其中通过var在for语句中定义的变量,在外部也可以访问

for-in: 可以用来枚举对象中的属性,ES对象中的属性没有顺序,因此该语句循环出的属性顺序是不可预测的

break & continue 跳出循环 :跳出当前循环,进入下一循环

switch语句: 语句中比较使用的是===全等,所以不会发生类型转换

函数:

1. 函数在任何时候都可以通过return返回想要返回的值,仅返回return,则函数会停止执行后返回undefined

2. ES中不介意传入多少参数,同时,命名的参数只提供便利并非必须。且在函数内部可以使用arguments对象访问参数,arguments对象与数组类似但不是Array的实例。使用length属性可以确定传入参数的个数。

3. 函数没有重载,后声明的覆盖前面的同名函数,因为ES函数不存在函数签名的特性


第四章 变量、作用域和内存问题

ES存在两种数据类型的值:基本类型值 & 引用类型值

1. 基本类型值: Undefined、Null、Number、Boolean、String,按值访问,保存在栈内存

2. 引用类型值: Object、Array、Date 、RegExp 、Function 等,内存中的对象,按引用访问,保存在堆内存

两种类型的值复制变量的过程如下图:

基本类型值
引用类型值

ES中所有函数的参数都是按值传递的,参数是函数的局部变量。

检测类型:

两个操作符:

1. typeof

2. instanceof 返回true或false

作用域链:保证对执行环境有权访问的所有变量或者函数的有序访问,全局执行环境的变量对象始终是作用域链中的最外层,即兜底。

内部可往外部访问查找想要的标识符,外部不能下钻查找。

ES5中使用var声明变量,是不存在块级作用域的。如:if语句中声明的变量,在外部依然能访问。

使用var声明的变量会被自动加到最接近的环境中。

JS有自动垃圾收集机制


第五章 引用类型

描述的是一类对象所具有的属性和方法,对象是某个引用类型的实例

1. Object 类型: ES中使用最多的一个类型 person = new Object() person={x:123,y:123} 构造函数&字面量,属性的访问支持. 或者 [ ],当要访问的属性名为变量时使用方括号

2. Array 类型:new Array() 当传给构造函数的参数为数值,则为数组长度; arr = [1,2,]这样则会创建一个长度为2或3的数组 Array.length 不是只读的,可以通过设置其值来改变数组长度

数组检测:Array.isArray(value) 

Array.toString()返回以逗号分隔的字符串

Array.join() 可传参,参数即为分隔符,不传则默认是逗号分隔

push()末尾添加,返回修改后的数组长度

pop()末尾删除,返回删除项的值

shift()头部移除,返回删除项的值

unshift()投不添加,返回修改后数组长度

reverse(),反转数据项顺序

sort()排序,其原理是先调用toString()再排序,再比较字符串,可向其传递一个比较函数,若第一个数要在第二个数之前,则返回负数。

concat()数组拼接,原数组不变,生成一个新数组

slice()数组截取,既是截取,因此原数组不变,单拎出截取片段而已。接收两个参数,截取一头一尾不包含尾巴。若传入数值为负,则加上数组长度再截取。若头大于尾,返回空数组。

splice()拼接方法,在原数组基础上变化,接收三个参数,分别代表,要操作起始位置,要删除的项数,要插入的具体值,始终返回从原始数组删除的项的值。

indexOf() lastIndexOf() 位置方法,找对应值的索引,接收两个参数,分别为,要查找的值、开始查找的索引

every() 每个值都满足给定函数则返回true

filter() 返使函数返回true的项所组成的数组

forEach() 对数组中每一项执行函数,该方法没有返回值

map() 对数组中每一项执行函数,并返回函数执行后组成的数组

some() 任意一个值满足给定函数则返回true

以上五个迭代函数都接受两个参数,1️⃣要运行的函数,其中此函数有三个参数,分别是当前item,index,array本身;2️⃣函数的作用域对象。

reduce() reduceRight(): 归并方法,接受两个参数:1️⃣要执行的函数,该接受四个参数,前一个值,当前值,项的索引,数组对象;2️⃣可选,最为归并基础的初始值

两个函数遍历方向相反!

3. Date 类型:var date = new Date()不传参,则自动获取当前时间

常用方法:Date.now() 获取当前时间戳 也可使用 +new Date()

getFullYear() 获得年份 getMonth()获得月份,0:1月 11:12月

getDate() 获得日期月份中的天数(1-31) getDay()获得星期几 0:周日 6:周六

4. RegExp 类型: 见JS正则基础

5. Function 类型: JS中函数即使对象,都有其属性和方法。同时,函数名则仅仅是一个指向函数对象的指针。

函数声明(变量提升) & 函数表达式

使用不带圆括号的函数名仅仅是访问函数指针,并没有调用函数

函数没有重载,函数可作为值来传递,也可从一个函数中返回另一个函数

函数内部属性:arguments对象 & this函数执行环境的对象 & caller属性(调用该函数的函数的引用),其中arguments对象中有一个callee的属性,该属性指向拥有该arguments对象的函数。

函数的属性和方法:每个函数都包含的两个属性length & prototype,分别表示:函数希望接收到的命名参数的个数 & 对于ES中的引用类型而言,prototype保存了他们的所有实例方法(ES5中prototype属性本身是不可枚举的,因此使用for-in发现不了)

同时,每个函数还包含两个非继承而来的方法apply(在其中运行函数的作用域, [参数数组]) & call(在其中运行函数的作用域, 参数)

bind()方法,该方法会创建一个函数实例,则函数执行的this值会绑定到传给bind方法的值。

基本包装类型:Boolean、Number、String,与引用类型最大的区别就是对象的生命周期。自动创建的基本包装类型的对象,只存在于一行代码的执行瞬间,之后立即被销毁。

Number类型常用方法:toFixed(),按照指定的小数位,返回数值的字符串表示

toExponential(),按照指定的小数位,返回指数表示法的字符串

String类型的常用方法:

length属性:返回字符串长度

charAt(),返回给定位置上的字符 charCodeAt(),返回指定位置的字符编码

concat()字符串拼接,得到拼接后的新字符串,不过更常用+

三个基于子字符串创建新字符串的方法:slice()、subStr()、subString()

slice():一或两个参数、一头一尾不包含尾,截取字符串,若传入负数则加上字符长度再截取,若头大于尾,返回空字符串;若不传第二个参数,则截取到末尾

subString():一或两个参数、一头一尾不包含尾,截取字符串。若传入参数为负,则转为0.

subStr():一或两个参数,头和截取长度,不传长度则截到末尾。若传入参数为负,第一个加长度,第二个转为0.

indexOf(): 返回指定字符的索引,一个或两个参数:指定的字符,开始查找的位置

lastIndexOf():查找方向相反,其余同上

trim():创建字符串副本,去掉字符串前置及后缀所有空格

trimLeft()、trimRight()同方法字面意思

字符大小写转换方法:toLowerCase() toLocaleLowerCase() toUpperCase() toLocaleUpperCase()

match(),字符串匹配方法,仅接受一个参数,RegExp对象 || 正则表达式

search(),参数同上,若找到则返回第一个匹配索引,若没找到,则返回-1

replace(a,b):将字符串中a替换为b,a可为字符串或RegExp对象,b可为字符串或者一个函数

split(),将字符串以指定的参数切割为多个字符串,返回数组,还可以接受第二个参数,用来指定返回数组的长度。

单体内置对象:Global & Math

Global对象:

encodeURI() & encodeURIComponent() : 对URI进行编码,对URI中无效的字符进行编码

encodeURI() 针对整个URI,不会对本身属于URI的特殊字符进行编码,如# ?等

encodeURIComponent() 针对URI中某一段,对任何非标准字符串进行编码。

decodeURI() & decodeURIComponent()

eval(), ES中最强大的一个方法,仅接受一个参数,即要执行的ES字符串

当中创建的变量不会被提升。*恶意用户输入威胁站点的或应用程序安全的代码,即为代码注入。

虽然没有直接访问Global的方式,但是Global对象作为window对象的一部分,因此在全局作用于声明的变量和函数,都成为了window的属性,都可以通过window对象访问。

Math 对象:

常用方法 max() min() random() floor() ceil()

Math.max.apply(Math,[1,2,3,2,5]) 返回5

random():返回一个[0,1)之间的整数

随机生成一个范围内的数:Math.floor(Math.random() * 可能的值的总数 + 第一个可能的值)


第六章 面向对象的程序设计

ECMA-262把对象定义为:无序属性的集合、其属性可包含基本值、对象或者函数

属性类型:数据熟悉 & 访问器属性

属性有其内部特性,其中数据属性有如下特性:[[Configurable]] [[Enumerable]] [[Writable]] [[Value]] 直接在对象上定义的属性前三个特征默认值均为true,Value则默认undefined。

若要修改属性内部特性,使用object.defineProperty(属性所在对象,属性名字、描述符对象)

*若一个属性一旦被定义为不可配置,则不能再将其变为可配置

访问器属性:不包含数据值、包含一对getter & setter 函数,不过这两个函数都不是必需的。

访问器属性有如下特性:[[Configurable]] [[Enumerable]] [[Get]] [[Set]] 直接在对象上定义的属性前两个特征默认值均为true,后两个为undefined

访问器属性不能直接定义,必须通过object.defineProperty()定义

同时定义多个属性可用object.defineProperties()

访问属性特性:object.getOwnPropertyDescriptor(所在对象,要读取其描述的符的属性名称)

创建对象

1. 工厂模式:在一个函数里面创建对象、定义属性和方法、返回对象

存在的问题:虽然创建了对象,但是不能确定该对象是一个什么类型

2. 构造函数模式:没有显示创建对象、属性和方法直接赋给this对象,没有return。

构造函数函数名首字母大写,通过new操作符创建新实例。eg: var p = new Person("shu","24","teacher")

这种方式内部步骤如下:1️⃣创建一个新对象,2️⃣将构造函数的作用域指定给该对象、3️⃣执行构造函数中的代码给该对象定义属性和方法,4️⃣返回该对象

这样创建出来的实例都有一个constructor属性,是一个指向函数prototype属性所在函数的指针

,可以使用constructor属性来表示对象类型,但一般都用instanceof操作符

存在的问题:每个方法都要在每个实例上创建一遍,不同实例上的同名函数是不相等的。因此可以通过把函数定义到构造函数外部这个方式来解决这个问题。但是,如果一个对象要定义很多方法,则该方式就很不实用了。

3. 原型模式:不用在构造函数中定义对象实例的信息,将这些信息直接添加到原型对象中

每个函数都有一个prototype属性,该属性是一个指针,指向一个对象(原型对象),该对象包含了特定类型的所有实例对象共享的属性和方法。

无论什么时候,只要创建了一个函数,就回为函数创建一个prototype属性,该属性指向函数的原型对象。默认情况下,原型对象都会自动获得一个constructor属性,该属性是一个指向prototype属性所在函数的指针。

当调用构造函数创建一个实例之后,该实例内部包含一个指向构造函数原型对象的指针[[prototype]],针对该指针,在脚本中没有标准的访问方式,但部分浏览器在每个对象上都支持一个属性__proto__ 

虽然在所有实现中都无法访问[[prototype]],但可以使用isPrototypeOf()方法来确定实例和构造函数原型对象之间的关系

ES5中增加了一个获得指定实例原型对象的方法getPrototypeOf(),可以通过对象实例访问保存在原型中的值,但是却不能通过对象实例重写原型中的值。

当为对象添加一个属性时,这个属性会屏蔽原型对象中保存的同名属性,但不会修改原型对象中的属性。

hasOwnProperty(),用来检测某一属性是存在于实例中还是原型中,存在实例中时,返回true

in:单独使用时,不论是实例中还是原型中的属性都会返回true

for-in:则返回所有所有能够通过对象访问的、可枚举的属性,既包括实例中、也包括原型中。

object.key(),返回对象上所有可枚举的实例属性。

通过字面量方法一次性定义属性和方法,实际上是重写了prototype,因此constructor属性也就变成了新对象的constructor属性,指向object,不再指向原来的构造函数。

原型模式的问题:方法虽然共享了,但是属性也共享了,若是存在引用类型的属性,则不同实例间会互相影响。

4. 综上——组合使用构造函数模式和原型模式

在构造函数中定义属性,在原型对象上添加方法。此方法数目前ES中使用最广、认同度最高的一种创建自定义类型的方法。

5. 动态原型模式:把所有信息都封装在构造函数中,并在需要的情况下,在构造函数中初始化原型

动态原型模式中,不能使用字面量来重写原型,因为在已经创建了实例之后,再重写原型,会切断实例和原型间的联系!!!

继承

ES仅支持实现继承

所有函数的默认原型都是Object的实例

1. 原型链继承

给原型添加方法的代码一定要在替换原型的语句之后,因为替换原型本质是重写原型,重写原型会导致原型和实例间的联系被切断。同理,通过原型链实现继承的时候,也不能使用字面量创建原型方法。

存在的问题:由于存在原型变成另一个类型的实例的现象,因此会导致实例属性变成原型属性。当原先的实例属性包含引用类型时,则会相互影响。

2. 借用构造函数继承(伪造对象或经典继承)

在子类型的构造函数中调用超类型的构造函数(个人理解就是把构造函数集中起来创建独立的实例属性)

优势:可以在子类型调用超类型构造函数的时候,向超类型构造函数传递参数

存在的问题:同构造函数模式一样,函数复用不能实现

3.  综上——组合继承(原型链实现对方法的继承,借用构造函数实现对实例属性的继承)

存在的问题:无论什么情况下,都会调用两次超类型的构造函数,分别是1️⃣创建子类型原型的时候2️⃣在子类型构造函数内部。在第一部时子类型已经包含了超类型的对象的全部实例属性、为了防止实力类型中的引用类型共用的问题,在第二步的时候重写了实例属性,阻止我们访问超类型的实例属性。

4. 原型式继承

5. 寄生式继承

6. 寄生组合式继承

寄生组合式继承是引用类型最理想的继承范式


第七章 函数表达式

函数的两种定义方式:1️⃣函数声明,函数会被提升 2️⃣函数表达式,该方法不会被提升

function后面若是没有标识符,则创建出的函数就是匿名函数(拉姆达函数)

闭包:指有权访问另一个函数作用域中的变量的函数

闭包只能取得包含函数中任何变量的最后一个值

this对象:该对象是在运行时基于函数的执行环境绑定的

在全局函数中,this是window;当函数被某个对象调用时,this是那个对象;匿名函数的执行环境具有全局性,因此this对象通常指向window

将函数声明包含在一对圆括号中,实际上表示的是一个函数表达式。之所以要用圆括号包起来实现立即执行,是因为JS会将function关键字当做一个函数声明的开始,而函数声明后面不能直接i跟有圆括号来表示立即执行。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容