前端之旅:《JS高级编程》1~5章学习笔记

后来想了一下,还是总结一下较好

1. JS简介

第1章主要讲了JS的起源和发展历程,以及JS的基本组成情况

  • 一个完整的JS实现包含三个部分:
    • 核心(ECMAScript)
    • 文档对象模型(DOM)
    • 浏览器对象模型(BOM)
  • Web浏览器只是ES实现可能的宿主环境之一
  • DOM级别
    • DOM1级:由2个模块组成,DOM Core和DOM HTML
    • DOM2级:引入了更多新模块,在原来DOM的基础上又扩充了鼠标和用户界面事件、范围、遍历等。而且通过对象接口增加了对CSS的支持
    • DOM3级:进一步扩展了DOM,引入了以统一方式加载和保存文档的方法
  • BOM只处理浏览器和框架

2. 在HTML中使用JS

  • <script>元素定义了6个属性:
    • src:指定要执行的JS文件位置
    • charset:JS文件的编码
    • async:异步加载脚本,但不依赖引入顺序
    • defer:在文档完全被解析和显示之后才执行脚本(立即下载,延迟执行)
    • language:已废弃
    • type:编写的代码的内容类型,常见<text/javascript>
  • <script>不仅可以放在<head>里面,还可以放在<body>里面(最好是结束标签之前)

  • 文档模式:混杂模式和标准模式

  • <noscript>用在不支持JS的浏览器中显示替换内容

3. 基本概念

  • 标识符:首字符必须是字母、下划线(_)、美元符号($)。其他字符可以是字母、数字、下划线和美元符号
  • 严格模式:"use strict"可以放在脚本的开头对整个脚本开启严格模式,也可以放在函数内部让函数在严格模式下执行
  • JS代码语句不强制使用;结束代码,但是建议不要省略
  • 标识符不能是关键字保留字(测试时发现标识符可以是汉字,但是不建议使用)
  • JS变量是松散类型(弱类型),即可以用来保存任何类型的数据
  • JS声明变量使用var关键字就是局部变量,否则就是全局变量
  • 可以使用一条语句定义多个变量,用逗号隔开即可

3.4 数据类型

  • ES有5种简单数据类型:Undefined、Null、Boolean、Number、String。还有1种复杂数据类型 Object
  • typeof用来检测数据类型,它是一个操作符而不是函数,所以调用时可以用圆括号也可以不用
  • 声明变量未初始化值是”undefined”,对于没有声明的变量只能执行typeof检测数据类型,结果是”undefined”
  • null表示一个空对象引用,所以执行typeof null;结果是”object”
  • undefined值是派生自null值的,因此相等性测试结果是true
  • Boolean类型的true和false是区分大小写的,其他形式的都只是标识符,Boolean()可以将其他值转换为Boolean值
  • 保存浮点数需要的内存空间是保存整数值的2倍
  • 永远不要测试某个特定的浮点数值
  • ES能够保存的最大数值保存在Number.MAX_VALUE中,最小数值是Number.MIN_VALUE
  • 超出JS数值范围的值被自动转换成-Infinite(负无穷)或Infinite(正无穷),isFinite()函数可以用来确定一个数值是不是有穷的(在最大和最小之间)
  • NaN(Not a Number),这个数值用于表示一个本来要返回数值的操作数未返回数值的情况。NaN与任何值都不相等,包括NaN自身。isNaN()函数接收到参数后,会尝试将这个值转换为数值,然后确定这个参数是否“不是数值”
  • Number()parseInt()parseFloat()可以将非数值转换为数值。parseInt第2个参数可以指定转换时使用的基数
  • 数值、布尔值、对象和字符串值都有toString()方法,但null和undefined值没有这个方法
  • String()方法可以将任何类型的值转换为字符串
  • ES中的对象其实是一组数据和功能的集合,Object的每个实例都具有下列属性和方法,由于在ES中Object是所有对象的基础,因此所有对象都具有这些基本的属性和方法
    • constructor
    • hasOwnProperty(name)
    • isPrototypeOf(object)
    • propertyIsEnumerable(propertyName)
    • toLocalString()
    • toString()
    • valueOf()

3.5 操作符

  • 相等(==)和不相等(!=)是先转换再比较,全等(===)和不全等(!==)仅比较不转换,作者推荐使用全等和不全等

3.6 语句

  • label语句可以在代码中添加标签,以便将来使用(比如跳转),通常配合循环语句使用
  • with语句的作用是将代码的作用域设置到一个特定的对象中(严格模式不允许使用,且with语句导致性能下降,也不建议使用)

3.7 函数

  • ES函数不介意传递进来多少个参数,也不在乎传递进来的参数是什么数据类型,在函数内部可以通过访问arguments对象来访问这个参数数组
  • 如果在ES中定义了2个同名函数,则该名字只属于后定义的函数

4. 变量、作用域和内存问题

  • 基本类型和引用类型的值
    • 基本类型占据固定大小的空间,保存在栈内存中;引用类型的值是对象,保存在堆内存中。
    • ES中所有参数都是按值传递的
    • instanceOf操作符用于识别该变量是否是某个对象的实例
  • 执行环境及作用域

    • 每个执行环境都有一个与之关联的变量对象
    • 全局执行环境被认为是window对象
    • 标识符解析是沿着作用域链一级一级搜索标识符的过程。搜索的过程始终从作用域链的前端开始,然后逐级向后回溯,直到找到标识符为止,如果找到全局执行环境的变量对象还没有找到标识符,就会发生错误。
  • 执行环境的类型只有2种——全局和局部(函数)

  • catch和with语句可以延长作用域链
  • JS没有块级作用域
  • 垃圾收集通常有2个策略:标记清除和引用计数

5. 引用类型

  1. Object类型
    • 字面量语法用花括号包围{},各属性之间用逗号分隔
    • 一般用点表示法访问对象属性,也可以使用方括号表示法来访问,作者建议除非必须否则用点表示法
  2. Array类型

    • 字面量语法用方括号包围[]
    • 每一项可以保存任意类型的值
    • 数组大小可动态调整
    • 使用Array构造函数是,可以省略new操作符
    • length属性不是只读的,所以可以使用它调整数组大小
    • Array.isArray()方法用来检查一个参数是否是数组(ES5)
    • join()方法用传入的分隔符参数连接字符串
    • push()pop()向数组末尾添加和删除元素,类似对栈的操作
    • shift()unshift()在数组开始的位置删除和插入元素
    • sort()方法对数组进行排序,传入的参数是比较函数
    • concat()方法可以将当前数组和传入的数组参数连接起来创建一个新的数组
    • slice()从当前数组提取一或连续多项创建一个新数组
    • splice()向数组中插入项,利用参数的组合则可以完成数组的删除替换插入项
    • indexOf()lastIndexOf()返回要查找的项在数组中的位置,没找到则返回-1。这两个方法的不同在于一个是顺序查找,一个是逆序查找
    • every()filter()forEach()map()some()都是用来迭代数组的方法
    • reduce()reduceRight()是用来归并数组的方法
  3. Date类型

    • Date.parse()返回日期字符串参数的毫秒数
    • Date.UTC()也返回表示日期的毫秒数,但是和parse参数不同
    • Date.now()返回当前时间的毫秒数
    • Date类型还有一些专门用于将日期格式化为字符串的方法:toDateString()toTimeString()toLocaleDateString()toLocaleTimeString()toUTCString,更多的日期时间方法可以看书
  4. RegExp类型

    • 正则表达式的字面量语法:
      var express = /pattern/flags;
      flags有3个值,可配合使用:

      • g: 表示全局模式
      • i: 表示不区分大小写
      • m: 表示多行模式
    • RegExp每个实例都有下列属性:

      • global:表示是否设置了g标志
      • ignoreCase:表示是否设置了i标志
      • lastIndex:表示开始搜索下一个匹配项的字符位置,从0算起:
      • multiline:表示是否设置了m标志
      • source:正则表达式的字符串
    • RegExp实例方法
      • test()方法测试参数字符串是否匹配正则表达式
      • exec()方法接受一个字符串参数,返回第一个匹配项信息的数组,但包含两个额外的属性:index和input,index表示匹配项在字符串中的位置,input表示应用正则表达式的字符串
    • RegExp构造函数属性:input、lastMatch、lastParen、leftContext、rightContext、multiline
  5. Function类型

    • 函数实际上是对象
    • 函数没有重载,因为函数名称只是一个变量,函数同名就像变量同名会被覆盖一样。
    • 函数可以作为值来使用,所以也可以用作函数参数,也可以将函数当作结果返回
    • 函数内部有两个特殊对象:arguments和this,arguments对象中还有一个名叫callee的属性,它是一个指针,指向拥有这个arguments对象的函数。ES5还有另一个函数对象的属性:caller,它保存着调用当前函数的函数的引用
    • 每个函数都包含两个属性:length和prototype,length表示函数希望接收的命名参数的个数,prototype是保存它们所在实例方法的真正所在
      每个函数都包含两个非继承而来的方法:apply()call(),这两个方法都是在指定的作用域中调用函数,实际上等于设置函数体内this对象的值。
      ES5还定义了一个方法bind(),这个方法会创建一个函数实例,其this值会被绑定到传给bind()的参数
  6. 基本包装类型
    ES还定义了3个特殊的引用类型:Boolean、Number和String,它们是基本类型值的基本包装类型对象。不建议显示创建基本包装类型的对象

    • String类型
      • 字符方法:charAt()charCodeAt()用来访问特定字符
      • 字符串操作方法:concat()+可以实现连接字符串。slice()substr()substring()都是提取子字符串创建新字符串的方法
      • 字符串位置方法:indexOf()lastIndexOf()可以从字符串中查找子字符串的位置
      • 去除前后空格:trim()会创建一个字符串的副本,删除前后空格并返回。
      • 大小写转换:toLowerCase()toUpperCase()toLocaleLowerCase()toLocaleUpperCase()
      • 模式匹配:
        match()接收正则表达式为参数,本质上和调用RegExp的exec方法差不多。
        search()返回字符串中第一个匹配项的索引。
        replace()方法用于替换字符串匹配项。
        split()基于特定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。
        localeCompare()用于比较字符串。
        fromCharCode()是一个静态方法,它接收一个或多个字符编码,并将它转换成一个字符串
  7. 单体内置对象
    定义:由ES实现提供的,不依赖于宿主环境的对象,这些对象在ES程序执行之前就已经存在了

    • Global对象:不属于任何其他对象的属性和方法,最终都是它的属性和方法。所有全局作用域中定义的属性和函数,都是Global对象的属性。

      • URI编解码方法:encodeURI()encodeURIComponent()可以对URI进行编码。decodeURI()decodeURIComponent()是对应的解码方法。
      • eval()将传入字符串当做实际JS语句来解析
      • 。。。还有其他Global对象的属性。。。
      • window对象,Web浏览器都是讲Global对象作为window对象的一部分加以实现的
    • Math对象:它提供的计算功能比我们自己编写的计算功能执行起来要快得多

      • 包含的属性都是数学计算中常用的特殊值
      • min()max()方法用于确定一组数值中的最大值和最小值
      • 舍入方法:ceil()floor()round()
      • random()方法返回0~1之间的随机数
      • 还有很多完成简单或复杂计算的方法:pow()sqrt()

6.面向对象

属性

ES中有两种属性:数据属性和访问器属性

  • 数据属性有4个描述其行为的特性:
    • Configurable
    • Enumerable
    • Writable
    • Value
  • 访问器属性也有4个特性:
    • Configurable
    • Enumberable
    • Get
    • Set

ES5提供了Object.defineProperty()方法来修改属性默认的特性,Object.defineProperties()方法可以通过描述符一次定义多个属性,Object.getOwnPropertyDescriptor()方法可以获取给定属性的描述符。

创建对象

  • 工厂模式:在函数里面创建对象并初始化属性和方法,然后返回对象,创建对象直接调用函数即可。
  • 构造函数模式:将利用函数是对象的本质,在函数内直接对this进行初始化。缺点是对象的方法没有达到复用的目的
  • 原型模式:为了达到复用的目的,将对象属性和方法放进对象原型(object.prototype)中,这样每个对象就共享了属性和方法,而且每个实例可以定义自己专属的属性和方法,且会覆盖原型中的同名属性和方法。注意使用对象字面量语法会重写object.prototype,相当于是使用新对象覆盖了原型对象,导致某些引用关系丢失。这种模式的缺点是对原型对象中的引用类型的操作会共享给所有实例。
    利用原型对象可以为原生对象添加新方法或重写
  • 组合构造函数模式和原型模式:对不需要共享的属性或方法用构造函数来定义,需要共享的属性或方法写进原型对象(推荐)
  • 动态原型模式:和组合模式类似,只是它把所有信息封装在构造函数中,也在构造函数初始化原型(经检查有必要时)
  • 寄生构造函数模式:和工厂模式类似,只是在创建对象时不是直接调用函数,而是使用new关键字
  • 稳妥构造函数模式:和寄生模式类似,区别在:一是没有公共属性, 新创建对象的实例方法不引用this,二是不使用new操作符调用构造函数(这一点又和工厂模式类似)

一些有关的方法:

  • isPrototype()方法可以确定一个对象实例的原型,Object.getPrototypeOf()返回一个对象的原型
  • delete 操作符可以删除实例中定义的属性和方法。
  • in 操作符用来确认是否能够访问指定对象的指定属性
  • ES5中的Object.keys()可以获取对象上所有可枚举的实例属性,而Object.getOwnPropertyNames()方法可以获取所有实例属性,无论它是否可枚举

继承

  • 原型链:使用要继承自的父类型的实例覆盖子类型的原型。所有函数的默认原型都是Object的实例。该种继承方法的缺点:一是父类型的实例属性顺理成章的成了现在对象的原型属性;二是在创建子类型实例时,不能向父类型构造函数传递参数
  • 借用构造函数:方法是在子类型的构造函数内部调用父类型构造函数(用apply或call方法),这下可以传递参数了,但没有解决函数复用的问题,而且父类型的原型对象中的方法对子类型不可见。
  • 组合继承:将原型链和借用构造函数的技术组合到一块,其背后的思想是使用原型链实现对原型属性和方法的继承。其缺点是在构造函数中和用实例覆盖子类型的原型对象的过程中,调用了2次父类型的构造函数,导致父类型的实例属性有2份,1份在子类型原型对象中,1份在子类型实例中。
  • 原型式继承:它的实现思路是在函数内借助给定的参数(对象)覆盖函数中一个全新的对象的原型,然后返回这个全新的对象,利用该函数实现了继承,每个实例都可以对自己的属性和方法进行自定义。这个技术和原型继承的思路差不多,用对象实例去重写子类型的原型,只是它把步骤放到了函数里面,并且是返回了一个被更改过原型的空白对象。
    ES5的Object.create()方法规范化了原型式继承,它用来创建并返回一个继承后的子对象。
  • 寄生式继承:是和原型式继承紧密相关的一种方式,但是原型式继承返回的子类型没有任何自定义的属性和方法,所以寄生式继承是完成了二次封装,用来完善子类型的属性和方法。思路是创建一个函数,在函数中调用原型式继承中封装的步骤,然后定义子类型中应有的属性和方法。但是也没有解决方法复用的问题,相当于每个实例中都有一份自己的方法
  • 寄生组合式继承:通过借用构造函数继承来继承属性,通过原型链的混成形式来继承方法。基本思路是:不必为了指定子类型的原型而调用父类型的构造函数,我们需要的只是父类型的原型对象的一个副本而已。只是利用一个中间对象的实例覆盖了子类型的原型对象,而在子类型的构造函数中又调用父类型构造函数以达到继承属性的目的。(最常用最常用)

有关方法:

  • instanceof 操作符可以测试实例与原型链中出现过的构造函数。isPrototypeOf()测试调用该方法的原型是否是这个实例(参数)的原型
avatar

神无

舍悟离迷,六尘不改。