分类
精读JS高级程序设计

第五章引用类型

引用类型

Object类型

创建Object实例的方式:

  1. 使用new操作符后跟Object构造函数。
  2. 使用对象字面量。
    let person={
        name:'daiwf',
        age:27
    }
    

    在上面代码中,左边的花括号({)表示对象字面量的开始,因为它出现在了表达式上下文中(表达式上下文指该上下文期待一个值,赋值操作符表示后面是一个值)。如果花括号({)出现在一个语句上下文中,如if语句条件的后面,则表示一个语句块的开始。

Array类型

创建Array实例的方式:

  1. 使用Array构造函数。
    let arr=new Array(1,2,3) // [1,2,3]
    let arr1=Array(1,2,3) // [1,2,3]
    let arr2=new Array(3) // [,,] 如果传数值,传小数(小数点后非零的数)或负数会报错
    let arr3=new Array('3') // ['3'] 如果传其它类型的参数
    let arr4=Array.of(3) // [3] 可解决上面的不统一情况
    
  2. 使用数组字面量。
    let arr=[1,2,3]
    

通过设置数组的length属性,可以从数组的末尾移除或向数组中添加新项。

使用Array.isArray()可以很好的检测数组。

Date类型

ES5添加了Date.now()方法获得当前日期与时间的毫秒数(使用+操作符也可获取Date对象的时间戳)

const start=+new Date();

RegExp类型

创建正则表达式的方式:

  1. var expression=/pattern/flags;
    flags:

    • g:表示全局模式,即模式将应用于所有字符串,而非在发现第一个匹配项时立即停止。
    • i:表示不区分大小写模式。
    • m:表示多行模式。
    • u:unicode,匹配多字节字符。
    • s:dotAll,.可以匹配任意字符包括换行符。
    • y:仅从正则表达式lastIndex属性表示的索引处为目标字符串匹配。
  2. var expression=new RegExp(“pattern”,”flags”)

在ES3中使用正则表达式字面量和RegExp构造函数创建的正则表达式不一样,字面量始终共享同一个实例(在循环中使用,lastIndex不回重置),而构造函数始终创建一个新实例。

在ES5及之后两者都始终会创建一个新实例。

// es3下
var re=null,i;
for( i =0 ;i<10 ;i++){
    re=/cat/g;
    re.test("catastrophe") // 除第一次循环匹配后,后面的将不能匹配,因为是同一个实例lastIndex没有重置
}

Function类型

创建函数的方式:

  1. 函数声明 function sum (a,b){ return a+ b}

  2. 函数表达式 var sum =function(a,b){return a+ b}

  3. Function构造函数 var sum = new Function("a","b","return a + b ")不推荐

函数声明和函数表达式的区别:

解析器会率先读取函数声明,并使其在执行任何代码之前可以访问(函数声明提升),而函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

分类
精读JS高级程序设计

第四章变量、作用域

变量、作用域

检测类型

  • typeof是确定一个变量是字符串、数值、布尔值还是undefined的最佳工具。
  • instanceof根据原型链来判断一个变量是否是给定的应用类型。它的问题在于,如果一个页面存在多个窗体则会存在多个Object,Array等构造函数,造成跨窗体的对象检测存在问题。
  • Array.isArray()可以解决上面instanceof的问题,但只能检测数组。
  • Object.prototype.toString.call(obj)可以比较好的判断类型,返回”[object type]”type是对应的类型。

执行环境与作用域

执行环境定义过了变量和函数有权访问的其它数据,决定了他们各自的行为,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象上面。

某个执行环境重的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数也一并销毁(全局执行环境直到应用程序退出时才会被销毁)

当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问,作用域的前端始终是当前执行代码所在的环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象,活动对象在最开始只包含一个变量,即arguments对象。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象则来自下一个包含环境,这样,一直持续到全局执行环境。

标识符解析是沿着作用域链一级一级地搜索标识符的过程。

块级作用域

letconst关键字可以将变量绑定到所在的任意作用域中(通常是{…}内部),换句话说letconst为其声明的变量隐式地劫持了所在的快作用域。

分类
精读JS高级程序设计

第三章基本概念

基本概念

语法

  • 区分大小写。
  • 标识符:就是指变量、函数、属性的名字。
    • 第一个字符必须是一个字母、下划线(_)或者一个美元符号($)
    • 其他字符可以是字母、下划线、美元符号或数字
    • 不能把关键字、保留字、true、false和null用作标识符
  • 注释
    • 单行注释://
    • 块级注释:/* xxx */
  • 严格模式:ES5引入了严格模式,严格模式是为JS定义了一种不同的解析与执行模型。
    • 要在整个脚本启用严格模式,可以在顶部添加如下代码:"use strict"
    • 在函数内部的上方包含这条语句,也可以指定函数在严格模式下执行:
    function doSome(){
      "use strict"
      // 函数体
    }
    
  • 语句
    • 语句以一个分号结尾;如果省略分号,则由解析器确定其结尾。
    • 代码块以左花括号({)开头,以右花括号(})结尾。

关键字和保留字

(以下是严格模式下的)

  • 关键字:breakdoinstanceoftypeofcaseelsenewvarcatchfinallyreturnvoidwhilecontinueforswitchdebuggerfunctionthiswithdefaultifthrowdeleteintryexportextendimportsuperclassconstletstaticyieldasyncawait
  • 保留字:interfacepackageprivateimplementsprotectedpublicenum
  • 其他:evalarguments

变量

ES的变量是松散类型的,可以用来保存任何类型的数据,定义变量要使用var、let或const,省略关键字会定义全局变量,在严格模式下会导致抛出referenceError错误。

“`javascript
function test(){
message = "h1";//全局变量
}
“`

数据类型

ES有7种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol和BigInt,还有一种复杂数据类型:Object。Object本质上是有一组无序的名值对组成的。

  • typeof 操作符
    • “undefined”——如果这个值未定义
    • “boolean”——如果这个值是布尔值
    • “string”——如果这个值是字符串
    • “number”——如果这个值是数值
    • “object”——如果这个值是对象或null
    • “function”——如果这个值是函数
    • “bigint”——如果这个值是BigInt类型值
    • “symbol”——如果这个值是Symbol类型值
  • Null 类型

    在 JS 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 “object”。

  • Boolean 类型

    ES中所有类型的值都有与两个Boolean值(true、false)等价的值。要将一个值转换为对应的Boolean值,可以使用转型函数Boolean()。转换为false值的各类型值分别是:空字符串''、0和NaN、null、undefined。

  • Number 类型

    • 浮点数值的最高精度是17位小数,进行算术运算时会有舍入误差,例如:0.1+0.2的结果不是0.3,而是0.300000000000000004,所以不要测试某个特定的浮点数值。
    • NaN:任何涉及NaN的操作都会返回NaN;NaN与任何值都不相等,包括自身。isNaN()在接收到一个值时,会尝试将这个值转换为数值。不能转换为数值的值都会导致这个函数返回true。
    • 数值转换:Number()、parseInt()、parseFloat。
    • Number()函数转换规则:
      1. 如果是Boolean值,true->1 false->0
      2. 如果是数值,只是简单的传入和返回。
      3. 如果是null->0。
      4. 如果是undefined->NaN。
      5. 如果是字符串:'0011'->11'1.1'->1.1'0xf'->15''->0'以上其它'->NaN
      6. 如果是对象,则调用对象的valueOf()方法,然后根据前面的规则转换返回的值,如果转换的结果是NaN,则调用对象的toString()方法,然后再依照前面的规则转换返回的值。
      var obj={
        valueOf(){
          return '22'
        },
        toString(){
          return '33'
        }
      }
      Number('hello') // NaN
      Number('') // 0
      Number('000011') // 11
      Number('true') // 1
      Number(obj) // 22
      obj.valueOf=function(){
        return []
      }
      Number(obj) // 33
      
    • parseInt()函数转换规则:

      由于Number()转换字符串时比较复杂而且不够合理,所以在处理整数的时候更常用的是parseInt()函数,parseInt()在转换字符串时,会看其是否符合数值模式,它会忽略字符串前面的空格,直到找到第一个非空格字符,如果第一个字符不是数值字符或者正负号,parseInst()会返回NaN。

      parseInt('1234blue') // 1234
      parseInt('') // NaN
      parseInt('0xf') // 15
      parseInt('22.5') // 22
      parseInt('070') // 70 ES5后不会在认为是8进制  
      

      parseInt()可以传入第二个参数,转换使用的基数(即多少进制),传入[-Infinity,-1] U [37,Infinity] U [1,2)直接返回NaN,传入(-1,1)将按照10进制转换,传入[2,37)返回对应进制相等的十进制数。(开闭区间来表示的😂)

      tips:为什么只到37呢?数一下键盘数值和字母有多少个就知道了,我在Chrome和Safari上测试了是这样的。

      parseInt('11',-0.3) // 11
      parseInt('11',0.3) // 11
      parseInt('11',-1) // NaN
      parseInt('11',37) // NaN
      parseInt('z',36.2) // 35
      

      !注意一道面试题

      [0,1,2,3].map(parseInt) // [0, NaN, NaN, NaN]
      
    • parseFloat()函数转换规则:

      只解析十进制数,因此没有第二个参数,如果字符串包含的是一个可解析为整数的数,那会返回整数。

  • String类型

    • 字符串中包含双字节支付,那么length属性可能不会精确返回字符串中的字符数目。
    • Object.create(null)、null、undefined没有toString方法,其他都有。
  • Object类型

    Object的每个实例中都存在系列属性和方法:

    • constructor:保存着用于创建当前对象的函数。
    • hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在对象原型中)是否存在。
    • isPrototypeOf(object):用于检查传入的对象是否是当前对象的原型。
    • propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句。
    • toString():返回对象的字符串表示。
    • valueOf():返回对象的字符串、数值或者布尔值表示,通常与toString()方法的返回值相同。
    • toLocalString():返回对象的字符串表示,该字符串与执行环境的地区对应。

操作符

  • 位操作符

    ES中的所有数值都是以IEEE-754 64位存储的,但位操作符并不直接操作数值,而是现将64位的值转换成32位的整数,然后执行操作,最后再将结果转回64位。
    对于有符号的整数,32位中前31位用于表示整数的值,第32位用于表示数值的符号,0表示正数1表示负数。
    负数同样以二进制码存储,但使用的格式是二进制补码。计算一个数值的二进制补码,需要经过下列3个步骤:

    1. 求这个数值绝对值的二进制码。
    2. 求二进制码的反码,即将0替换为1,1替换为0。
    3. 得到的反码加1。
  • 逻辑操作符
    • 逻辑与的规则:
    1. 如果第一个操作数是对象,则返回第二个操作数;
    2. 如果第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象;
    3. 如果两个操作数都是对象,则返回第二个操作数;
    4. 如果第一个操作数是null,则返回null;
    5. 如果第一个操作数是NaN,则返回NaN;
    6. 如果第一个操作数是undefined,则返回undefined;

    逻辑与操作符要始终记住是一个短路操作符

    • 逻辑或的规则:
    1. 如果第一个操作数是对象,则返回第一个操作数;
    2. 如果第一个操作数的求值结果为false,则返回第二个操作数;
    3. 如果两个操作数都是对象,这返回第一个操作数;
    4. 如果两个操作数都是null,则返回null;
    5. 如果两个操作数都是NaN,则返回NaN;
    6. 如果两个操作数都是undefined,则返回undefined;

    逻辑或操作符始终记住是一个短路操作符

  • 加性操作符
    • 数值+数值:直接相加

    • 字符串+其它:

    1. 其它如果是基本类型就调用toString()方法(null,undefined使用String()
    2. 如果是对象那调用valueOf()方法返回的是基本类型则应用前面1的规则,如果是对象,则再调用toString()方法。
    • 非字符串非数值+数值:
    1. 如果是null,则null转为0,如果为undefined,则结果为NaN。
    2. 如果是对象,则先调用valueOf(),如果返回的是字符串,则应用字符串+数值规则。如果返回Boolean,则true转为1,false转为0,如果是null或undefined则应用规则1,如果返回是对象,则再调用toString()方法。
    • 对象+对象:

    先调用valueOf()方法,返回是否返回基本类型,如果不是则调用toString(),是基本类型则应用前面的规则。

  • 相等操作符

    相等和不相等(==,!=):先转换再比较
    全等和不全等(===,!==):仅比较不转换

    • 相等何不相等的基本规则:
    1. 如果有一个操作数是布尔值,则在比较前先转换为数值——false转为0,true转为1。
    2. 如果一个操作数是字符串,则在比较前先将字符串转为数值。
    3. 如果一个操作数是对象,另一个不是,则先调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较。
    • 比较时遵循下列规则:
    1. null和undefined相等;
    2. NaN和所有的都不相等;
    3. 如果两个都是对象,如果两个都指向同一个对象,则相等,否则不等。

for-in语句

只遍历可枚举属性,包括原型上的属性。

函数

函数的length属性可获得函数接受几个命名参数,函数内的arguments对象的length可获得有多少个参数传给了函数。

在非严格模式下,arguments对象中的值永远与命名参数的值保持同步。

分类
精读JS高级程序设计

第二章在HTML中使用JS

<Script>元素

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

  • async:可选,表示立即下载脚本,但不应该妨碍页面的其他操作,比如下载其他资源或等待加载其他脚本(浏览器将立即下载文件,下载好后立即执行,所以async的脚本不保证按照制定它们的先后顺序执行,async脚本一定是在页面的load事件前执行,但可能会在DOMContentLoaded事件触发之前或之后执行)。只对外部文件有效。建议async脚本不要在加载期间修改DOM,并确保两个异步脚本互不依赖。
  • defer:可选,表示脚本可以延迟到文档完全被解析和显示之后再执行(浏览器将立即下载文件,但脚本会被延迟到整个页面都解析完毕后再运行,并保证脚本按照它们出现的先后顺序执行,defer脚本一定在DOMContentLoaded事件之前执行)。只对外部脚本有效。
  • charset:可选,表示通过src属性指定的代码的字符集,由于大多数浏览器会忽略他的值,因此这个属性很少人用。
  • src:可选,表示包含要执行代码的外部文件。
  • type:可选,表示编写代码使用的脚本语言的内容类型(也称为MIME类型)。
  • language:已废弃。

脚本阻塞

包含在<Script>元素内部的JS代码将被从上至下依次解释,在解释器对<Script>元素内部代码求值完毕之前,页面中的其余内容都不会被浏览器加载和显示。与解析嵌入式代码一样,在解析外部JS文件(包括下载该文件)时,页面的处理也会展示停止。

跨域

<Script>与<img>的src属性可以指向当前HTML页面所在域之外的某个域中的完整URL。(jsonp实现的基本)

标签的位置

按照传统的做法,所有<Script>元素应该放在页面的<head>元素中,这种做法意味着必须等到全部JS代码都被下载、解析、执行后,才能开始呈现页面的内容,对于那些需要很多JS代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,延迟期间的浏览器窗口将是一片空白。为了避免这个问题,现代web应用程序一般把JS引用放在<body>元素中页面内容的后面。

分类
精读JS高级程序设计

第一章JS简介

JavaScript 实现

  • ECMAScript

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

    • ES3新增了正则表达式、新控制语句、try-catch异常处理的支持。

    • ES5新增了JSON对象(用于解析和序列化JSON数据)、继承的方法和高级属性定义、严格模式。

    • ES6新增let和const、箭头函数、字符串模版、扩展运算符、默认参数、解构、数组方法(Array.from()Array.of()copyWithin()find()findIndex()fill()includes())、class、Set、Map、字符串扩展(padEndpadStartendsWidthstartsWithincludestrimrepeat

    • ES7新增数组的includes()、指数运算符**

    • ES8新增async/awaitObject.values()Object.entries()、函数参数列表结尾允许逗号、Object.getOwnPropertyDescriptors()ShareArrayBufferAtomics对象,用于从共享内存位置读取和写入

    • ES9新增引入异步迭代器、Promise.finally()、为对象解构提供了和数组一样的Rest参数()和展开操作符、正则表达式命名捕获组(/(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/)、正则表达式反向断言、正则表达式dotAll模式、正则表达式 Unicode 转义、非转义序列的模板字符串

    • ES10新增行分隔符(U + 2028)和段分隔符(U + 2029)符号现在允许在字符串文字中,与JSON匹配、更加友好的 JSON.stringify、Array.prototype.flat()Array.prototype.flatMap()、String的trimStart()方法和trimEnd()方法、Object.fromEntries()Symbol.prototype.descriptionString.prototype.matchAllFunction.prototype.toString()现在返回精确字符,包括空格和注释、修改catch绑定、新的基本数据类型BigInt

  • DOM

    • 文档对象模型是针对XML但经过扩展用于HTML的应用程序编程接口,DOM把整个页面映射成为一个多层级节点结构。

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

    • DOM2级扩充了鼠标和用户界面事件、范围、遍历等细分模块(DOM视图、DOM事件、DOM样式、DOM遍历和范围),通过对象接口增加了对CSS的支持。

    • DOM3级引入以同一方式加载和保存文档的方法、新增了验证文档的方法。

    • 其他DOM标准:SVG、MathML、SMIL。

  • BOM

    • BOM只处理浏览器窗口和框架,但人们习惯上也把所有针对浏览器JavaScript扩展算作BOM的一部分:
    1. 弹出新浏览器窗口的功能;
    2. 移动、缩放和关闭浏览器窗口的功能;
    3. 提供浏览器详细信息的navigator对象;
    4. 提供浏览器所加载页面的详细信息的location对象;
    5. 提供用户显示器分辨率详细信息的screen对西那个;
    6. 对cookie的支持;
    7. 像XMLHttpRequest和IE的ActiveXObject这样的自定义对象;