精华内容
下载资源
问答
  • JavaScript权威指南、JavaScript 高清完整版、有目录 可编辑。
  • JavaScript权威指南

    千次阅读 2006-12-12 10:54:00
    JavaScript权威指南 第一章 JavaScript概述 1.1 对JavaScript的误解 1.2 JavaScript的版本 1.3 客户端JavaScript 1.4 其他环境中的JavaScirpt 1.5 客户端的JavaScript:网页中的可执行内容 1.6 客户端...

    JavaScript权威指南

    第一章 JavaScript概述

    1.1 对JavaScript的误解
    1.2 JavaScript的版本
    1.3 客户端JavaScript
    1.4 其他环境中的JavaScirpt
    1.5 客户端的JavaScript:网页中的可执行内容
    1.6 客户端JavaScript的特性
    1.7 JavaScript的安全性
    1.8 例子:用JavaScipt计算借贷支出
    1.9 如何使用本书其余的部分
    1.10 JavaScript探秘

    第一部分 JavaScript的核心

    第二章 语法结构

    2.1 字符集
    2.2 大小写敏感性
    2.3 空白符和换行符
    2.4 可选的分号
    2.5 注释
    2.6 直接量
    2.7 标示符
    2.8 保留字

    第三章 数据类型和值

    3.1 数字
    3.2 字符串
    3.3 布尔值
    3.4 函数
    3.5 对象
    3.6 数组
    3.7 null
    3.8 undefined
    3.9 Data对象
    3.10 正则表达式
    3.11 Error对象
    3.12 基本数据类型的包装对象

    第四章 变量

    4.1 变量的类型
    4.2 变量的声明
    4.3 变量的作用域
    4.4 基本类型和引用类型
    4.5 无用存储单元的收集
    4.6 作为属性的变量
    4.7 深入理解变量的作用域

    第五章 表达式和运算符

    5.1 表达式
    5.2 运算符概述
    5.3 算术运算符
    5.4 相等运算符
    5.5 关系运算符
    5.6 字符串运算符
    5.7 逻辑运算符
    5.8 逐位运算符
    5.9 赋值运算符
    5.10 其他运算符

    第六章 语句

    6.1 表达式语句
    6.2 复合语句
    6.3 if
    6.4 else if
    6.5 switch
    6.6 while
    6.7 do/while
    6.8 for
    6.9 for/in
    6.10 标签语句
    6.11 break
    6.12 continue
    6.13 var
    6.14 function
    6.15 return
    6.16 throw
    6.17 tyr/catch/finally
    6.18 with
    6.19 空语句
    6.20 JavaScript语句小结

     第七章 函数

    7.1 函数的定义和调用
    7.2 作为数据的函数
    7.3 函数的作用域:调用对象
    7.4 函数的实际参数:Arguments对象
    7.5 函数的属性和方法

    第八章 对象

    8.1 对象和属性
    8.2 构造函数
    8.3 方法
    8.4 原型对象和继承
    8.5 面向对象的JavaScript
    8.6 作为关联数组的对象  (****************************166**********)
    8.7 对象的属性和方法

    第九章 数组

    9.1 数组和数组元素
    9.2 数组的方法

    第十章 使用正则表达式的模式匹配

    10.1 正则表达式的定义
    10.2 用于模式匹配的String方法
    10.3 RegExp对象

    第十一章 JavaScript的更多主题

    11.1 数据类型转换
    11.2 使用值和使用引用
    11.3 无用存储单元收集
    11.4 词法作用域和嵌套函数
    11.5 Function()构造函数和函数直接量
    11.6 Netscape公司的JavaScript 1.2的不兼容性

    第二部分 客户端JavaScript

    第十二章 Web浏览器中的JavaScript

    12.1 Web浏览器环境
    12.2 在HTML中嵌入JavaScript
    12.3 JavaScript程序的执行

    第十三章 窗口和框架

    13.1  Window对象概述
    13.2  简单的对话框
    13.3  状态栏
    13.4  超时设定和时间间隔
    13.5  错误处理
    13.6  Navigalor对象
    13.7  Screen对象
    13.8  Window对象的控制方法
    13.9  Location对象
    13.10 History对象
    13.11 多窗口和多框架

    第十四章 Document对象

    *********************291*******1

    14.1  Document对象概述
    14.2  动态生成的文档
    14.3  Document对象的颜色属性
    14.4  Document对象的信息属性
    14.5  表单
    14.6  图象
    14.7  链接
    14.8  锚
    14.9  小程序
    14.10 嵌入式数据

    第十五章 表单和表单元素

    15.1 Form对象
    15.2 定义表单元素
    15.3 脚本化表单元素
    15.4 表单验证示例

    第十六章 脚本化cookie

    16.1 cookie概览
    16.2 cookie的存储
    16.3 cookie的读取
    16.4 cookie示例

    第十七章 文档对象模型

    17.1 DOM概览 
    17.2 使用DOM的核心API
    17.3 DOM与Internet Explorer 4的兼容性
    17.4 DOM与Netscape 4的兼容性
    ****357*** 17.5 简便方法:Traversal和Range API

    第十八章 级联样式表和动态HTML

    18.1 CSS的样式和样式表
    18.2 用CSS进行元素定位
    18.3 脚本样式
    18.4 第四代浏览器中DHTML
    18.5 关于样式和样式表的其他DOM API

    第十九章 事件和事件处理

    19.1 基本事件处理
    19.2 2级DOM中的高级事件处理
    19.3 Internet Explorer事件模型
    19.4 Netscape 4事件模型

    第二十章 兼容性

    20.1 平台和浏览器的兼容性
    20.2 语言版本的兼容性
    20.3 非JavaScript浏览器的兼容性

    第二十一章 JavaScript的安全性

    21.1 JavaScript与安全性
    21.2 受限制的特性
    21.3 同源策略
    21.4 安全区和签名脚本

    第二十二章 在JavaScript中使用Java

    22.1 脚本化Java小程序
    22.1 在Java中使用JavaScript
    22.3 直接使用Java类
    22.4 LiveConnect数据类型
    22.5 LiveConnect数据转换
    22.6 JavaObject对象在JavaScript中的转换
    22.7 从Java到JavaScript的数据转换

    第三部分 JavaScript核心参考手册

    第三部分 JavaScript核心参考手册

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    JavaScript:采用Unicode字符集编写

    ECMAScript v3允许标示符中有Unicode转义序列,字符/u后接4个十六进制的数字,用来指定一个16位的字符编码

    JavaScript中的对象有两重:①一种对象表示的是已命名的值的无序集合
                              ②表示的是有编号的值的有序集合,称为数组array
                              JavaScript还定义了一种特殊的对象:函数function

    不区别整型数值和浮点型数值,JavaScript中所有的数字都是浮点型的,采
                               用IEEE 754标准定义的64位浮点格式表示数字
                               最大值+/-1.7976931348623157*10的303次方,
                               最小是+/-5*10的负324次方

    JavaScript的数字格式允许精确地表示:-9007199254740992(-2的53次方)
                                        和9007199254740992(2的53次方)之
                                        间的所有整数,包括两边端点数

    中的某些整数运算是对32位的整数执行的,尤其逐位运算,他们的范围从
                               -2147483648(-2的31次方)到2147483647(2的31次方-1)

     

    能识别十六进制的直接量 以“0X”或“0x”开头 如:0xff911

    JavaScript的浮点格式能精确表示出来的是有限个的:18437736874454810627个


    方法toString()可以用它的参数指定的基数或底数(底数必须在2和36之间)把数字转换成字符串。
                      如:将一个数字转换为二进制数字:
                          x.toString(2);


    Infinity                   无穷大的特殊值
    NaN                        特殊的非数字值
    Number.MAX_VALUE           可表示的最大数字
    Number.MIN_VALUE           可表示的最小数字(与零最接近的数字)
    Number.NaN                 特殊的非数字值
    Number.POSITIVE_INFINITY   正无穷大的特殊值
    Number.NEGATIVE_INFINITY   负无穷大的特殊值


    无char这样的字符数据类型,要表示单个字符,必须使用长度为1的字符串

    /n   是一个转义序列(escape sequence)
    /u   表示由四位十六进制数指定的任意Unicode字符,如/u03c0表示π
    /0   NULL字符(/u0000)
    /b   退格符(/u0008)
    /t   水平制表符(/u0009)
    /n   换行(/u000A)
    /v   垂直制表符(/u000B)
    /f   换页   (/u00CC) 
    /r   回车符 (/u00CD)
    /"   双引号 (/u0022)
    /'          (/u0027)
    //          (/uC05C)  
    /xXX    由两为十六进制数值XX指定的Latin-1字符
    /uXXXX  有四位十六进制数XXXX指定的Unicode字符
    /XXX    由一到三位八进制数(1到377)指定的Latin-1字符。
     


    RegExp对象,正则表达式

    基本数据类型的包装对象 包装(wrapper)

    隐式声明的变量总是被创建为全局变量  作用域(scope) 全局(global)
    函数体内,局部变量的优先级高于同名的全局变量
    无块级作用域 局部变量在整个函数体中都是有定义的,但
         在执行var语句前是不会初始化的
           var scope="global";
           fuction f() {
               alert(scope);            //显示"undefined",而不是"global";
               var scope="local";       //变量在此处初始化,但到处都有定义
               alert(scope);            //显示"local"
           }

     


    基本类型与引用类型,基本是值、引用只是引用。
                字符串好象与基本类型的实现一样,传递的是值
               
    garbage collection


    当JavaScript的解释器开始运行时,它首先,在执行任何JavaScript代码之
                   前,创建一个全局对象(global object)。这个对象的属性
                   就是JavaScript程序的全局变量.当声明一个JavaScript的全局
                   变量时,实际上所做的是定义了那个全局对象的一个属性
                   在顶层代码中可以使用this来引用这个全局对象。
                   客户端JavaScript中,Window对象代表浏览器窗口,它是包
                   含在该窗口中的所有JavaScript代码的全局对象。Window对象
                   定义了全局的核心属性,此外它还定义了全局的客户端属性,如
                   navigator和screen


    JavaScript的实现允许有多哥全局执行环境,每个执行环境有不同的全局对象
                   (在此情况下,每个全局对象就不完全是全局的了)
                    一个框架中的代码可以用parent.frames[1]来引用另一个框架
                    中的JavaScript代码,在第二个框架中的代码可以使用
                    parent.frames[0].x来引用第一个框架中的全局变量x


    值NaN永远不会与任何其他值等同,包括自身。检测其用全局函数isNaN()


    相等运算符(==)等同运算符(===)
    _____________________________________________________________________________________
    1 比较数字,字符串和布尔值时使用的都是量值,当且仅当这两个变量存放的值相等时返回true;
    2 比较对象,数组和函数时使用的则是引用,只有两个变量引用的是同一个对象时才返回true;
    比较两个值的等同性必须遵循的规则
    * 如果两个值具有相同的类型,就比较这两个值看是否相等
    - 如果两个值都是字符串,而且在串中同一位置上的字符相同,他们就相等
    - 如果两个值都是数字,那么他们相等,但是如果一个时NaN,或两个都是NaN他们不等
    - 如果两个都是布尔值true或都是false,则相等
    - 如果两个值引用的是同一对象,数组,或函数,那么他们相等,如果引用的是不同的对象,即使是可转
    化成相同的原始值也不等
    - 如果两个值都是null,另一个是未定义的,他们相等
    * 如果两个值的类型不同,应把他们转换成相同的类型以使用上述的规则比较
    - 如果一个值是数字,而另一个是字符串,那么字符串被转换成数字比较
    - 如果有一个值为true,那么他被转换成1,然后比较,false被转换成0
    - 如果一个值是对象,而另一个值是数字或字符串,那么将对象转换成一个原始类型的值,然后比较,
    javascript先尝试valueOf()转换,再尝试toString()转换。
    _____________________________________________________________________________________

    instanceof运算符:左边对象,右边构造函数名.左边对象是右边对象的一个实例,则返回true


    JavaScript中所有的数字都是浮点型的,但逐位运算符却要求它的数字运算数是整型的

    << :左移一位乘2,左移两位乘四,以次类推
    >> :带符号右移:右移一位相当于用2除(丢弃余数),右移两位相当于用4除。正为0,负为1
    >>>:用零补足的右移运算:左边来的总为0

    typeof返回字符串,说明了运算数的类型。
                      数字、字符串、布尔值,返回:number,string,boolean
                      对象、数组、null,返回:object
                      函数,返回:function
                      未定义的,返回:underfined

    delete,删除对象的属性、数组元素或变量,成功返回true,不能被删除也返回false
           某些内部的核心属性和客户端属性不能删除
           var语句声明的变量也不能删除
           delete只能影响属性值,并不能影响被这些属性引用的对象

    void 舍弃运算数的值,返回undefined
         <a href="javascript:void window.open();">Open New Windows</a> 打开一个新的浏览器页面,但超链接还存在
         <a href="javascript:window.open();">Open New Windows</a>      打开一个新的浏览器页面,超链接不存在,出现:[object]


    if(expression){ //expression为true,或者可以转换为true则执行statement语句
      statement;
      }

    case(){    //匹配case表达式用===等同运算符,而不是==相等运算符

      }


    迭代(iteration)

    标签语句:identifier:statement.如果标签名和某个变量名或者函数名相同,不必担心命名冲突

    with语句:用变量的作用域和作用域链(即一个按顺序检索的对象列表)来进行变量名解析。with语句
          用于暂时修改作用域链
          with(frames[1].document.form[0]){
              name.value="";
              address.value="";
              email.value="";
          }
             使用了with语句的JavaScript代码很难优化,速度慢


    在调用函数时,先要计算括号之间指定的所有表达式,然后把他们的结果作为
                    函数的参数

     

    JavaScript是一种无类型语言,所以不能给函数的参数指定一个数据类型,且不会检
                       查传递的数据是不是那个函数所要求的类型。
                       如果参数类型很重要,可以用typeof进行检测。


    创建函数的三种方式:
    function f(x) {return x*x;}              //function语句       //所有JavaScript版本中都有效
    var f=new Fuction("x","return x*x;");    //Function()构造函数 //只在JavaScript 1.1及以后有效
    var f=function(x) {return x*x;};         //函数直接量         //只在1.2及以后有效
                        函数直接量只被解析和编译一次,而作为
                        字符串传递给Function()构造函数的JavaScript代码则在每次调用
                        构造函数时只需要被解析和编译一次。

    函数体内:arguments用来引用Arguments对象,可以按照数字获取传递给函数的参数
              arguments[],arguments.length
              虽然称做“arguments数组”,但arguments并非真正的数组,它是一个Arguments对象。
    Arguments对象还定义了callee属性,用来引用当前正在执行的函数-->未命名函数调用自身


    Function对象的length属性确切地说明了一个函数声明的形式参数的个数,在函数体内外都有效。

    方法apply()和call()           

             _________
    原型对象,存放方法和其他常量的理想场所.JavaScript中的所有函数都有prototype属性
     属性的继承只发生在“读”上,而“写”属性值时不发生
     如果读时,自己没有则去原型对象里找
     如果写时,自己没有则将写的属性作为自己新的属性Circle.prototype.pi=3.1415


    JavaScript函数是对象,所以我们可以创建函数的属性,就像创建对象的属性一样

    类方法,类方法与类关联在一起的方法,而不是和类的实例关联在一起的
     调用类方法,就必须用类本身,而不能用该类的特定方法

     

    作为关联数组的对象:采用“.”运算符存取一个对象的属性,属性名用标示符表示的,标示符不是一个数据类型
    ------
    Array.join()<--->String.split()
    Array.reverse() 反转
    Array.sort()    排序
    Array.concat()  ==不能递归地展开一个元素为数组的数组
    Array.slice(start,[end]) 返回子数组 如果end为负数则从最后一个元素算起:-1最后一个,-2倒数第二个
    Array.splice()  从一个数组中移除一个或多个元素,如果必要,在所移除元素的位置上插入新元素,返回所移除的元素
    push(),pop()  (都是对数组的最后一个元素操作,push()返回新的长度,pop()返回删除的值)
     联合使用就可以用JavaScript数组实现一个先进后出(FILO)栈
    unshift(),shift()   在数组的头部操作   unshift()插入到头返回新长度
               shift()删除头并返回之后数组的第一个元素 
    toString() 的返回值和无参数调用join()时返回的字符串相同
    toSource()
    ------------------------
    /b :匹配一词语的边界,位于字符/w和/W之间的位置.而[/b]匹配的是退格符.

    正则表达式的属性:位于第二个斜杠之后。
     i:大小写不敏感的匹配
     g:执行全局匹配。即找到所有的匹配。
    RegExp.multiline = ture;---->模式匹配将以多行的模式进行.

    单行或多行模式匹配,用属性s和m来选择。
    具有最小匹配的复制,由一个问号加上要复制的字符来声明,如:*?声明的是0个或多个复制,但匹
     配的是尽可能少的字符,而不是尽可能多的字符。

    (?=[A-Z])匹配的是恰好位于一个大写字符前的位置。
    (?|[A-Z])匹配的是不在一个大写字母之前的位置。
    用于分组而不是引用的括号。一个后面为?:的左括号将用于分组,而不是创建对要匹配的文本的一个引用。
    ------------------------
    用于模式匹配的String方法:
    search():以正则表达式为参数,返回的是一个与之匹配的子串的开始字符的位置,如果没有任何匹配,则返回-1.
      search()不支持全局搜索,它忽略了正则表达式参数的属性g.
    replace():
     var quote=/"([^"]*)"/g;
     text.replace(quote,"{$1}");
    match():唯一参数就是一正则表达式,返回的是一个包含匹配结果的数组
     如果正则表达式没有属性g,match()进行的就不是全局检索.在这
     种情况下,数组的第一个元素就是匹配的字符串,而余下的元素
     则是正则表达式中用括号括起来的子表达式。
    split():
    ------------------------
      RegExp对象.
    new RegExp(exp1,exp2);
    exp2:参数:i,g
    当使用字符串将一个正则表达式传递给RegExp()时,必须用//替换掉所有的/字符.
    每个RegExp对象都有一个compile()方法。当改变一个RegExp对象的内容,而不抛弃此
    对象,可以用这一方法。compile()的参数和构造函数RegExp()的相同.
    如:zipcode.compile("//d{s}(-//d{4})?","g");
    --------
    用于模式匹配的RegExp方法:
    test(): var pattern=/java/i;
     pattern.text("JavaScript"); //返回true;
    exec():是一个具有字符串参数的RegExp方法,而不是一个具有RegExp参数的String方法(match()).
     当一个全局的RegExp对象使用exec()时,它将把该对象的lastIndex属性设置成紧接着匹配
     子串的那个字符。当同一个RegExp对象第二次调用exec()时,它将从lastIndex属性所指示
     的字符串开始检索。如果exec()没有发现任何匹配,它会将lastIndex属性重置为0。这一特
     殊的行为使得可以反复调用exec()来遍历一个字符串中所有的正则表达式.
    只有全局正则表达式才有lastIndex这样的特殊行为。如果RegExp对象没有属性g,exec()和test()将忽略
    它的lastIndex属性.
    --------
    每个RegExp对象都有四个属性:
     source是一个只读字符串,它包含得失正则表达式的文本.
     global只读布尔值,说明正则表达式是否具有属性g.
     ignoreCase只读布尔值,是否具有i属性.
     lastIndex只写整数,对一个全局模式来说,这个属性存储了在字符串中下一次检索开始的位置.
    --------
    RegExp的类属性(静态属性)
    作为静态属性,这些值都是全局性的,因此它们是临时性的,其他任何正则表达式操作都会将它们覆盖掉。
     leftContext   位于最新匹配左侧的文本
     rightContext  位于最新匹配右侧的文本
     lastmatch     被匹配的最新文本
     lastParen     与最新匹配的上一个带括号的子表达式匹配的文本
     $1,$2,...$9 
     input         如果没有传递给exec()和test()字符串,那么它就是要检索的字符串
     multiline     布尔值,指定了将检索的字符串作为单行模式来处理还是多行模式
    如果将multiline设为true,那么^和$符号匹配的就是没一行的开头和结尾,而不是一个字符
     串的开头和结尾.默认在客户端JavaScript中,这个属性是被设为true的.
    --------
    RegExp属性的动态作用域
    JavaScript使用的是静态作用域:即,JavaScript的函数是在定义它们的作用域中执行的,而不是在
     执行它们的作用域中执行。(如果框架A里的代码调用了框架B中定义的函数,而这个函数
     使用了全局变量,那么就在和框架B关联在一起的全局对象中查找这个全局变量的值)。
    但RegExp对象的静态属性的作用域是动态的。
    ------------------------------------------------------------------------------------------------
      第十一章
    没有一种JavaScript的语法、方法或属性使得可以改变一个字符串中的字符。由于字符串是不可变的,所
    以根本就没有一种方法可以辨别字符串是使用值传递还是使用引用。
    尽管JavaScript为效率起见,在复制和传递字符串时使用的是引用,但是在比较它们时使用的却是值。
    -----
    词法作用域规则:函数在定义它的作用域中执行.
    为了使词法作用域与嵌套函数协同使用,JavaScript实现还使用了“闭包”,可以将它看作定义函数时有
    效的作用域链和函数定义的组合.
    -----
    函数定义的三种方法:
     1.使用基本的function语句.
     2.使用构造函数Function()来定义函数.
     3.使用函数直接量来构造函数.
    比较Funtion()构造函数和函数直接量:
    1.构造函数Function()允许在运行时动态地创建和编译JavaScript代码,但
        函数直接量却是程序结构的一个静态部分,就像function语句一样.
    2.每次调用构造函数Function()时都会解析函数体并且创建一个新的函数对象。(循环、经常调用中的效率问题)
        而函数直接量并不是每次都重新编译,也不是每次创建一个新的函数对象.
    3.Function()创建的函数不使用词法作用域,它们总是被当作顶级函数来编译.如:

    var y="global";
    function constructFunction(){
        var y="local";
        return new Function("return y");  //不捕捉局部作用域.
    }
    //这行代码将显示"global".因为Function()构造函数.
    //返回的函数并不使用局部作用域
    //假如使用一个函数直接量,这行代码则可能显示"local".
    alert(constructFunction());   //显示"global"
    ------------------------------------------------------------------------------------------------
       客户端JavaScript
      第十二章 Web浏览器中的JavaScript

    作为全局对象的Window对象和客户端JavaScript代码的全局执行环境.
    客户端对象的层次和构成它的一部分的文档对象模型.
    事件驱动的程序设计模型.
    在客户端JavaScript中,表示HTML文档的是Document对象,Window对象代表显示该文档的窗口(或框架)
    -----
    HTML文档包含嵌入式GUI.

    <script>
    f1.document.write("<script>");
    f1.document.write("document.write('<H2>This is the quoted script</H2>')");
    f1.document.write("</"+"script>");   //用+防止解析停止,或者用转义符“/”:f1.document.write("<//script>");
    </script>
    因为HTML的解析器不能识别带引号的字符串
    -----
    defer性质:暗示浏览器继续解析HTML文档,推迟执行脚本,直到遇到了不能推迟执行的脚本.
    <script defer>

    </script>
    -----
    在多框架时,各个框架的onload识见处理程序的调用顺序不能确定,只是父框架的处理程序在
    所有子框架的处理程序之后调用。
    onUnload()
    -----
    只要浏览器的顶级窗口存在,那么代表它的window对象就会一直存在,无论这个窗口装载和卸载
    了多少页面,对它的Window对象的引用都有效。当关闭顶级窗口,这个Window对象也不会被撤消,
    如果在其它窗口中任旧存在对这个window对象的引用,那么这个对象就不会被作为无用存储单元
    回收。
    ------------------------------------------------------------------------------------------------
                                        第十三章 窗口和框架

    alert()                        .在某些浏览器中不产生阻塞(尤其Unix平台上的Netscape3和4)
    confirm()                      .会产生阻塞
    prompt() 要求用户输入一个字符串.会产生阻塞。
    -----
    状态栏(status line)的内容是由Window对象的两个属性控制的:status,defaultStatus.
    例:onMouseOver事件--必须返回为true,否则将执行浏览器自己的默认动作即显示链接的URL.
    -----
    onerror:传递给错误处理程序的参数有三个:
     第一个是描述错误的消息,如:“missing operator in expression”,“self is read-only”,“myname is not defined”
     第二个是一个字符串,存放引发错误的JavaScript代码所在的文档的URL
     第三个参数是文档发生错误的行代码。
    -----
    Navigator对象(Navigator对象实在Netscape Navigator之后命名的,IE支持,IE还支持:clientInformation是navigator的同义词)
    如:
    var browser="BROWSER INFORMATION:/n";
    for(var propname in navigator){
     browser += propname + ":" +navigator[propname] + "/n"
    }
    alert(browser);
    ----------
    open()打开一个新的窗口,有四个可选参数:
     1.URL,如果省略(可为null,或为空字符串),则打开的窗口将是空的。
     2.窗口的名字。这个名字可以做为<a>标记或<form>标记的target属性的值.如果是已经存在的窗口的名字,则open使用那个已经存在的窗口,而不再新打开一个。
     3.特性列表.窗口大小、GUI装饰等
     4.该参数只有在第二个参数命名的是一个已经存在的窗口时才有用。它是一个布尔值,
       声明了由有第一个参数指定的URL是应该替换掉旧窗口浏览历史的当前项(true),
       还是应该在窗口浏览历史中创建一个新的项(false),默认后者。
    ----------
    moveTo()移动窗口的左上角到指定坐标
    moveBy()移动指定数量的像素
    resizeTo()
    resizeBy()
    ----------
    location对象(如:protocol,host,pathname,search)
     search属性:包含的是问号之后的那部分URL.
        方法:reload()会从Web服务器上再次装入当前显示的页面
       replace()会装载并显示指定的URL.
     调用replace()时,指定的URL就会替换浏览器历史列表中的当前URL,而不是在历史列表中创建一个新条目.
     则调用replace()时,Back按钮就不能返回历史文档,而通过将一个URL赋给窗口的Loction属性来装载则可以.
        Window对象的location属性  :引用一个Location对象,
        Document对象的location属性:只是一个只读字符串,并不具有Location对象的任何特性.
        大多数情况下,document.location和location.href是相同的,但是,当存在服务器重定向时,document.location包
        含的是已经装载的URL,而location.href包含的则是原始请求的文档的URL.
    ----------
    History对象
     Window对象的history属性引用的是该窗口的History对象.
     但脚本不能真正访问History对象的数组元素。History对象的length属性可以被访问,但不提供任何有用信息.
     三个方法:back(),forward(),go()(有一整数参数,可以在历史列表中向前或向后跳过多少个页)。
    ----------
    每个window对象都有一个frames[]数组,该数组包含了对该窗口中每一个框架的引用.
    ------------------------------------------------------------------------------------------------
                                        第十四章 Document对象
    ----------
    Document对象的属性:
    1.alinkColor,linkColor,vlinkColor
    2.anchors[]锚
    3.bgColor,fgColor文档的背景色和前景色
    4.domain  该属性使处于同一Internet域中的相互信任的Web服务器在网页间交互时能协同地放松某项安全性限制
    5.lastModified 一个字符串,包含文档的修改日期
    6.links[]  文档中超文本链接的Link对象
    7.referrer 文档的RUL,包含把浏览器带到当前文档的链接
    8.title
    9.URL
    ----------
    动态生成的文档:
    注意:只能在当前文档正在解析时使用write()方法向其输出HTML代码.即,只能在标记<script>中调用方法document.write(),
    因为这些脚本的执行是文档解析过程的一部分。如果是从一个事件处理程序中调用document.write(),而且一旦文档被解析
    该处理程序被调用,那么结果将会覆盖当前文档(包括它的事件处理程序),而不是将文本添加到其中。
    ----------
    要创建新文档,首先需要调用Document对象的open()方法,然后多次调用write(),最后调用Document对象的方法close()以说
    明创建过程结束了.与必需的close()调用不同,open()方法的调用则是可选的.如果调用了一个已经关闭了的文档的write()
    方法,JavaScript会隐式地打开一个新的HTML文档.
    ---
    write()方法可以具有多个参数.多个参数将被依次写入文档,就像它们已经连接在一起一样.
    ---
    Document对象支持writeln()方法,由于HTML忽略换行,但杂一非HTML文档中有用.
    ----------
    open()
    HTML的MIME类型是text/html
    纯文本的MIME类型是text/plain
    ----------
    Document对象的颜色属性
     :gbColor,fgColor,linkColor,alinkColor,vlinkColor,只能在解析<body>标记之前设置它们,
     可以在文档的<head>部分使用JavaScript代码对它们进行动态设置,也可以将她们作为标
     记<body>的性质进行静态设置.
    ----------
    Document对象的信息属性:
     lastModified
     title
     URL
     referrer:存放了使用户链接到当前文档的文档的URL
    ----------
    图象:Document对象的images[]属性是一个Image元素的数组,每个元素代表文档中喊有的一个内联图象
    ---
    Image对象的事件处理程序:
     onload 
     onerror 图象装载过程中出现了错误时调用
     onabort 用户在图象装载完之前就取消时调用
    任何图象都可以调用这三个事件处理程序中的一个,而且只能是一个.
    complete属性:当图象正在装载状态时为false,当图象装载完毕或停止装载则为true.
    ----------
    链接
     Document对象的links[]数组包含的是代表文档中的超文本链接的Link对象
     标签<a>的属性href设置,在JavaScript和其以后的版本中,属于客户端的图象映射的标签<area>也
     可以在Document对象的links[]数组中创建Link对象
    Link对象的属性:href,hostname存放对应的那个URL中的主机部分.
    Link对象的属性href和URL都是可读可写的.
    ----------
    锚:
    Document对象的数组anchors[]包含了代表HTML文档中已命名位置的Anchor对象
    ----------
    小程序
    applets[]数组表示由标记<applet>或<object>嵌入在文档中的小程序对象.
    ----------
    嵌入式数据,数组:embeds[]代表由标记<embed>或<object>嵌入文档的数据(除了小程序)的对象.
     被嵌入的数据可以是任何形式的(音频数据,视频数据,表,等等).
    ------------------------------------------------------------------------------------------------
                                        第十五章 表单和表单元素
    ----------
    JavaScript的Form对象代表了一个HTML表单。通过Document对象的属性forms[]数组的元素可以找到Form对象.
    Form对象的elements[]数组.
    按文档中出现的顺序存放.
    只有真正点击Submit按钮才会出发onsubmit事件处理程序,调用表单的submit()方法则不会出发它.
    同样只有真正点击Reset按钮才会出发onreset事件处理程序,调用表单的reset()方法则不会出发它。
    ----------
    表单元素的属性:
     type,form(对包含该元素的Form对象的只读引用),name,value,onclik,onchange,onfocus,onblur.
    Select元素,Option元素
    <select>标记有multiple性质则为多选项
     单选的Select元素下,可读可写的属性selectedIndex用数字指定了当前被选中的选项.
     对多选的型的Select元素,要确定哪个被选中了,须遍历options[]数组的所有元素,检查
     每个Option对象的selected属性的值。
    Option元素还有text属性.
     options.length设置为0可以删除所有Option对象.
     把options[]数组的某个元素设置为null,则删除Select元素中的Option对象,后面的自动前移.
    Option元素定义了构造函数:Option(),可以动态地创建新的Option元素.把它们附加早options[]数组的尾
     部可以给Select元素增加新选项.
    ----------
    Hidden元素没有可视化外观,所以无事件处理程序.
    ------------------------------------------------------------------------------------------------
                                        第十六章 脚本化cookie
    ----------
    cookie有四个可选的性质,分别控制它的生存期、可见性、安全性.
     expires,指定cookie的生存期(默认cookie是暂时存在的)
     path:默认cookie和创建它的网页以及与这个网页处于同一目录下的网页和处于该目录子目录下的网页关联在一起.
     domain:默认为创建cookie的网页所在的服务器的主机名(不能将一个cookie的域设置成服务器所在的域之外的域).
     secure:    
    ----------
    name/value,cookie值不能含有分号、逗号或空白符,故之前许用escape()对之编码,然后读时用unescape();
    date采用的日期规范应该是方法Date.toGMTString()编写的格式.
    要改变一个cookie的值:使用一个名字和新的值再设置一次cookie值即可。
    要删除:则用同一个名字和一个任意的值已经一个已经超过了的终止日期再设置一次即可.
    Web浏览器保存的cookie总数不超过300个,为每个Web服务器保存的cookie数不超过20个(整个服务器而言),而
    且每个cookie保存的数据不能超过4千个字节.

    ------------------------------------------------------------------------------------------------
                                        第十七章 文档对象模型
    ----------
    文档对象模型(Document Object Model,DOM)是表示文档(如HTML文档)和访问、操作构成文档的各种元素(如HTML标记和
    文本串)的应用程序接口(API)。
    启用JavaScript的Web浏览器都定义了文档对象模型。
    ----------
    把文档表示为树
    Node接口为遍历和操作树定义了属性和方法。Node对象的childNodes属性将返回子节点的列表,
     firstChild,lastChild,nextSibling,previousSibling,parentNode属性提供了遍历树的方
     法.appendChild(),removeChild(),replaceChild,insertBefore()方法提供给文档添加节
     点或从文档树中删除节点。
    ----------
    文档树中不同类型的节点由特定的Node子接口表示。每个Node对象都有nodeType属性指定节点的类型.
    ---
    用Element接口的getAttribute()方法,setAttribute()方法和removeAttribute()方法可以查询、设
     置并删除一个元素的性质.
    另一种使用性质的方式调用getAttributeNode(),返回表示性质和值的Attr对象
    Attr对象不出现在元素的childNodes[]数组中,不像Element和Text节点那样是文档树的一部分
    ----------
    Document对象的implementation属性引用一个DOMImplementation对象,它定义了名为hasFeature()的
    方法,用这个方法(如果存在)可以检查一个实现是否支持特定的DOM特性或模块.
    如:if(document.implementation &&
           document.implementation.hasFeature &&
           document.implementation.hasFeature("html","1.0"){
     //该浏览器支持1级Core和HTML接口
    }
    ----------
    遍历文档(的节点)的方法
    ----------
    getElementsByTagName("*") 返回文档中所有元素的列表
    ----------
    如果给appendChild()传递的节点已经是文档的一部分,那么首先它将删除该节点.
    ----------
    使用Document段
    DOM核心API定义了DocumentFragment对象,作为使用Document节点组的快捷方法.DocumentFragment是一种特殊类型的节
    点,它自身不出现在文档中,只作为连续节点集合的临时容器,并允许将这些节点作为一个对象来操作.当把一个DocumentFragment
    插入文档时,插入的不是DocumentFragment自身,而是它的所有子节点.
    在把DocumentFragment插入文档时,段的子节点将从段中移动到文档中。进行插入操作后,段是空的,除非首次给它添加
    新的子节点,否则不能再利用它。
    ----------
    Traversal API由两个关键对象构成:每个对象提供了不同的文档筛选视图.
    NodeIterator和TreeWalker.
    NodeIterator对象的nextNode()方法和previousNode()方法
    (NodeIterator不需要递归就可以遍历文档中被选种的部分)
    NodeIterator对象提供了文档节点被展平的顺序视图,并支持筛选。
    TreeWalker也提供了文档被筛选后的视图,但不能展平文档树。
    当想遍历被筛选过的树,而不是调用nextNode()方法来遍历时,或者想对某些子树执行更复杂的遍历操作时,可用TreeWalker替代NodeIterator
    ---
    Document对象为创建NodeIterator和TreeWalker对象定义了方法:createNodeIterator、createTreeWalker():
    4个参数:第一个参数是开始遍历的节点
      第二个参数是数字,说明了NodeIterator和TreeWalker应该返回的节点类型
      第三个参数是一个可选的函数,用于指定更复杂的筛选.
      第四个参数是布尔值,指定了在遍历过程中是否扩展文档中的实体引用节点.
    ----------
    DOM Range API,由一个接口构成:Range.
    Range对象表示文档内容的一个连续范围,包括指定的开始位置和结束位置。
    Range对象提供了定义范围的开始位置和结束位置的方法,复制和删除范围内容的方法以及在范围的开始位置
    插入节点的方法。

    ------------------------------------------------------------------------------------------------
                                        第十八章 级联样式表和动态HTML
    http://www.w3.org/Style/CSS
    级联样式表(Cascading Style Sheet,CSS)
    ----------
    优先规则:
     用户样式表覆盖默认的浏览器样式表,作者样式表覆盖用户样式表,内联样式表覆盖所有样式表.
     特例:值包括!important修饰符的用户样式性质覆盖作者样式。
    ----------
    对于DHTML内容开发者来说,最重要的CSS特性是能用普通的CSS样式性质设置文档元素的可见性、大小和精确位置.
    ----------
    position  设置元素应用的定位类型
     static   (要对文档元素使用DHTML定位技术,必须把它的position性质设置为其它三个值之一)
     absolute 绝对
     fixed
     relative
    ----------
    如果同时设置了left,right,width性质,则:width性质将覆盖right性质。
    height优先级高于bottom。
    em:当前字体的行高度单位.
    ----------
    命名规范:JavaScript中的CSS性质:
     JavaScript中的连字符被解释为减号,所以删除连字符,且在连字符后的字母改为大写:如:border-left-width-->borderLeftWidth
     CSS的float性质为:cssFloat(float是JavaScript的关键字).
    ----------
    使用CSS2Properties对象的样式属性时:所有值必须是字符串.
                                 要用JavaScript时,必须使用引号括起所有值.
            要把属性(如left)设置为计算值,要确保算式末尾有单位.
    ----------
    文档中的每个HTMLElement元素都有style属性,该属性表示那个元素的内联样式性质.style属性引用的是一个
    CSS2Properties对象,它为CSS2标准定义的每个CSS样式性质都定义了一个JavaScript属性。
    CSS2Properties接口是CSSStyleDeclaration的子接口.因此每个文档元素的style属性还实现了CSSStyleDeclaration的属
    性和方法。包括:setProperty(),getPropertyValue(),removeProperty()(删除指定的样式)
      cssText属性返回表示所有样式性质和它们值的文本表示.
    ----------
    文档元素的style属性只表示那个元素的style性质,不包含影响元素的其他样式的信息(来自样式表)。要确定应用到元素的
    完整样式集合,要使用Window对象的getComputerStyle()方法(该方法由AbstractView接口定义),返回值
    是一个CSSStyleDeclaratrion对象,且只读。
    ----------
    document.styleSheets[],可以访问包含到文档或链接到文档的样式表.
    这个数组的元素是StyleSheet对象。
    ----------
    DOM CSS API还定义了一些特殊对象类,用来表示性质值:
     RGBColor对象表示颜色,Rect对象表示矩形值,Counter对象表示CSS2计数器。
    ----------
    ------------------------------------------------------------------------------------------------
                                        第十九章 事件和事件处理
    ----------
    四种完全不同的、不兼容的事件模型:
     原始事件模型:通常看作0级DOM API的一部分非正式内容,所有启用JavaScript的浏览器都支持->可移植性,特性有限。
     标准事件模型:强大的具有完整特性的事件模型,2级DOM标准对它进行了标准化.
     Internet Explorer事件模型:
     Netscape 4事件模型:
    ----------
    在原始事件模型中,事件是浏览器内部提取的,JavaScript代码不能直接操作事件.
    原始事件(raw event)或输入事件(input envent):用户移动鼠标、点击鼠标或敲击键盘时生成的。
    语义事件(semantic enevt).
    不支持通用的鼠标事件处理程序属性的标记包括:<applet> <bdo> <br> <font> <frame> <frameset> <head>
             <html> <iframe> <isindex> <meta> <style>
    ----------
    事件处理程序的返回值:
     返回true执行默认的动作:onsubmit,onclick,onkeydown,onkeypress,onmousedown,onmouseup,onreset
     例外:onmouseover事件处理程序返回true,则阻止(当把鼠标移动到一超链接或图片上,默认动作是在状态栏上显示链接的URL)
    ----------
    无论是用HTML性质定义事件处理程序,还是用JavaScript属性定义事件处理程序,都是把一个函数赋予文档元素的一个属性。
    ----------
    JavaScript中的函数运行在词法作用域中:函数是在定义它们的作用域链中执行,而不是在调用它们的作用域中执行。
    在把一个HTML性质的值设置为JavaScript代码串,以便定义事件处理程序时,隐式地定义了一个函数(在检测JavaScript中相应的事
    件处理程序属性的类型时,可以看到这一点)。
    ----------
    2级DOM中的高级事件处理
    在0级DOM事件模型中,浏览器把事件分派给发生事件的文档元素,如果那个对象具有适合的事件处理程序,就运行这个事件处理程序。
    ----------
    事件传播分三个阶段:
     一,捕捉(capturing)阶段,事件从Document对象沿着文档数向下传播给目标节点。
         如果目标的任何一个祖先(不是目标本身)专门注册了捕捉事件的处理程序,则传播过程中,就会运行这些处理程序。
     二,发生在目标节点自身,直接注册在目标上的适合的事件处理程序将运行。此与0级事件模型提供的事件处理方法相似。
     三,起泡(bubbling)阶段,事件将从目标元素向上传播回或起泡回Document对象的文档层次.虽然所有事件都受事件传播
         的捕捉阶段的支配,但并非所有类型的事件都起泡。
    在事件传播过程中,任何事件处理程序都可以调用表示那个事件的Event对象的stopPropagation()方法,停止事件进一步传播。
    Event对象的preventDefault()方法方法阻止默认动作发生。
    ----------
    事件处理程序的注册:
    0级API中,通过在HTML中设置性质或在JavaScript代码中设置对象的属性,来注册时间处理程序。
    2级事件模型中,调用对象的addEventListener(),三个参数:
     第一个:注册处理程序的事件类型名
     第二个:处理函数(或监听者),调用此函数时,传递给它的唯一参数是Event对象。
     第三个:布尔值。为true,则指定的事件处理程序将在事件传播的捕捉阶段用于捕捉事件
       为false,则事件处理程序就是常规的,当事件直接发生在对象上,或发生在元素的子女上,又向上
       起泡到该元素时,该处理程序将被触发。

    用addEventListener()方法注册的事件处理程序在定义它们的作用域中执行,不是由定义为HTML性质的事件处理程序使用的作用域链调用。
    如果在同一个元素上多次注册了同一个处理函数,那么第一注册后的所有注册都将被忽略。

    removeEventListener()方法:从对象中删除事件处理程序。
    addEventListener()和removeEventListener()都由EventTarget接口定义.在支持2级DOM Event API的Web浏览器中,所有Document节点都实现了这个接口.
    Event对象的属性:currentTarget引用一个对象,该对象注册了当前的事件处理程序,而且是以可移植的方式注册的.
    ----------
    Event:
    HTMLEvent模块定义的事件模型使用Event接口
     type:发生事件的类型
     target:发生事件的节点
     currentTarget:当前正在处理事件的节点
     eventPhase:数字,指定了当前所处的事件传播过程的阶段
     timeStamp:Date对象,声明了事件何时发生
     bubbles:布尔值,该事件是否在文档数中起泡
     cancelable:布尔值,声明事件是否具有能用preventDefault()方法取消默认动作
     stopPropagation():阻值事件从当前正处理节点传播
     preventDefault():阻止浏览器执行与事件相关的默认动作
    UIEvent:
    UIEvent接口是Event接口的子接口.它定义的事件对象类型要传递给DOMFocusIn,DOMFocusOut,DOMActivate类型的事件
               是MouseEvent接口的父接口.
     view属性:发生事件的Window对象
     detail:一个数字,提供事件的额外信息.对于click事件、mousedown事件,代表点击次数.
    MouseEvent:
    MouseEvent接口继承Event接口和UIEvent接口
     button:数字,声明了哪个鼠标键改变了状态
     altKey、crtlKey、metaKey、shiftKey:
     clientX、clientY
     screenX、screenY
     relatedTarget
    MutationEvent:
    MutationEvent接口是Event接口的子接口。 
    ----------
    生成合成事件的三个步骤:
     创建一个合适的事件对象:Document对象的createEvent()方法创建,该方法一个参数:应该创建的事件对象的事件模块名
     初始化这个事件对象的域:
     把事件对象分派给想得到它的文档元素。
    -----------------------
    Internet Explorer事件模型
    IE事件模型包括Event对象,该对象提供发生的事件的详细信息。但Event对象不是传递给
    事件处理函数,而是作为Window对象的属性。window.event

    window.event.cancelBubble=true;阻止事件起泡或制止它在包容层次中进一步传播,只适用于当前事件,当新事件
    生成时,将赋予window.event新的Event对象,cancelBubble属性将被还原为它的默认值false.

    attachEvent()注册的函数将被作为全局函数调用,关键字this引用的是Window对象,而不是事件的目标元素。
    detachEvent()
    -----------------------
    Netscape 4事件模型
    Netscape 4的事件模型与原始的0级事件模型相似,只是它在传递给处理函数的Event对象中提供事件的详细信息.它
    还支持启用事件捕捉的专用方法。
    Netscape 4事件模型不支持事件起泡,但它支持形式有限的事件捕捉(事实上,DOM标准的事件传播模型是Netscape捕
    捉模型和IE起泡模型的组合)
    -----------------------

    -----------------------
    ------------------------------------------------------------------------------------------------
                                        第二十章 兼容性
    -----------------------
    兼容性问题重要分两大类:
     一、和平台有关的、浏览器有关的和版本有关的特性.
     二、另一类是bug和语言级别产生的不兼容性,其中包括JavaScript程序和非JavaScript浏览器之间的不兼
         容性问题。
    -----
    一:
    最小公分母法:
    防御性编码:
    特性检查:好处->:它生成的代码不受特定的浏览器厂商或浏览器版本号的限制。
    平台检查:
    通过服务器端的脚本达到兼容性:HTTP请求头的User-Agent字段.
    忽略问题:
    适度停止运行:
    -----
    二:
    language性质:不能用language性质指定标准的版本.
    显式的版本测试:
    避免与版本相关的错误:
    为兼容性装载一个新页面:
    ------
    非JavaScript浏览器的兼容性:两件事需做:1.确保JavaScript代码不会当作HTML文本显示出来,
                                           2.显示一条消息以通知访问者他他的浏览器不能正确处理这个页面。

    对老式浏览器隐藏脚本:<!--
                           ...
                          -->
    <noscript></noscript>:括起了一个任意的HTML文本块,不支持则显示.(是由Netscape公司发布Netscape3时引入HTML的)。
    -----------------------

    ------------------------------------------------------------------------------------------------
                                        第二十一章 JavaScript的安全性
    -----------------------
    同源策略(Same-Origin Policy),Document对象的属性:domain,使用的字符串必须具有有效的域前缀。
    -----------------------
    ------------------------------------------------------------------------------------------------
                                        第二十二章 在JavaScript中使用Java
    -----------------------
    嵌入Web页的Java小程序都属于Document.applets[]数组.
    -----------------------
    Java代码中控制JavaScript代码,通过类:netscape.javascript.JSObject实现,表示Java程序中的一个JavaScript对象。
    由于所有JavaScript对象都出现在当前浏览器窗口的跟对象层次中,所以JSObject对象也必须出现在一个层次中.一
    个Java小程序要与所有JavaScript对象交互,必须首先含有一个表示浏览器窗口(或框架)的JSObject对象,小程序
    就显示在这个窗口(或框架)中.由于JSObeject类没有定义构造函数,所以不能只创建一个JSObject对象。必须调用
    静态方法getWindow(),当传递给它一个对小程序的引用时,它就会返回一个JSObject对象,这个对象就表示含有那
    个小程序的浏览器窗口。
    ---
    在HTML文件的小程序标记<applet>中添加一个新性质:mayscript,则小程序可以使用JSObject类.
    -----------------------
    数据类型转换.
    LiveConnect,JavaObject对象,JavaArray对象,JavaClass对象
    ------------------------------------------------------------------------------------------------

     

    展开全文
  • JavaScript权威指南_第6版 中文版,pdf格式扫描清晰,附带了配套的源码例子
  • JavaScript权威指南(第6版)》要讲述的内容涵盖JavaScript语言本身,以及web浏览器所实现的JavaScript API。本书第6版涵盖了 html5 和 ecmascript 5,很多章节完全重写,增加了当今 web 开发的最佳实践的内容,新增...
  • JavaScript权威指南(第6版)(中文版)高清
  • javascript 权威指南(第6版) 高清,带目录,值得阅读学习
  • 章2 词法结构 1.什么是字面量,标识符,保留字? 字面量即程序中的数据的值;标识符指数据的名字(字母、下划线_或美元符号$开头,为了和数值区分开,标识符不能用数字开头,);保留字是JS保留的某些可以使用的...

    章2 词法结构

    1.什么是字面量,标识符,保留字?

    字面量即程序中的数据的值;标识符指数据的名字(字母、下划线_或美元符号$开头,为了和数值区分开,标识符不能用数字开头,);保留字是JS保留的某些可以使用的标识符,用来给自身使用,如null,if等。

    2.什么是Unicode?(补充:什么是ASCII码 ?是一套电脑编码统,可以用来表示大小写英文字母、数字和一些符号,到目前为止共定义了128个字符。)

    Unicode是一个编码规范,目前实际实现的unicode编码只要有三种:UTF-8,UCS-2和UTF-16。

    JS使用Unicode字符集编写,注:不支持表情符号

    Unicode的转义序列是使用ASCII字符来代表任意16位 Unicode 内码,这些 Unicode 转义序列均以 \u 为前缀,其后跟随4个十六进制数(例如 \u4e00),以便于某些支持使用老技术的系统可以处理Unicode字符集。

     章3 类型,值和变量

    1.JS中,只有null和undefined是不能调用方法的值,这两个值是特殊值。

    2.常用的Math、Number对象属性:

    Math.pow() .floor() .ceil() .abs() .max() .min() .random() 

    Number.MAX_VALUE .MIN_VALUE .parseInt() .parseFloat() .isNaN() .isFinite()

    注:NaN=>"非数值",不等于任何值甚至自己,所以x===NaN不能得出x是否为not a number,需用Number.isNaN(x)或x !== x

    3.所有二进制编程语言都无法精确表示哪怕0.1的数,所以二进制浮点数之间不能比较其相等性(相加减之后比较,数值的精确度不一样)

    4.字符串

    字符串使用for/of循环或...操作符的迭代,迭代的是字符!

    字符串不可修改,toUpperCase()等方法均返回新字符串!

    字符串可被当作只读数组,用方括号而非charAt()方法可访问个别字符:

    let s = "hello" 

    s[0] //"h"

    位于${ 和对应的}之间的内容会被当作JS表达式来解释:

    let name = "BILL";

    let ee = "Hello ${name}" ;// ee==Hello BILL

    5.布尔值

    布尔值只有一个有用的方法:toString(),用于将自己转换为字符串true或false。[拓:除null和undefined外,所有值都有toString()方法]

    假性值六个(转布尔值时均为false):undefined,null,0,-0,NaN,""(空字符串)!!!其他均为真性值。JS的所有值均可转为boolean。例子:

    假设变量o要么保存一个对象,要么是null:

    1)if(o !=== null)...  只要不是null就执行。当需要严格区分null、0、" "时使用

    2)if(o)...  只要不是false或其他任何假性值就执行。

    6.null和undefined区别?

    null(关键字):值不存在,typeof null ;返回字符串 "object" ,所以它是一种特殊对象,表示”没有对象“。

    undefined(全局常量):更深层次的值不存在,变量的值未初始化时为undefined,查询不存在的对象属性或数组得undefined。

    注:相等操作符==认为他们相等。

    两者没有属性或方法,so用.或[ ]访问这两个值的属性或方法均导致TypeError。(对应章3.1)

    7.对象(引用类型)

    按引用进行比较,

    对象值就是引用,

    分为赋值引用(浅拷贝)和创建对象新副本(深拷贝,需要显示复制对象的属性或数组的元素)

    8.类型转换

    JS将+看作算术运算符而不是一元运算符,so有字符串时,JS采用字符串加法运算符(+操作符计算中有一个操作数是字符串时,则另一个操作数也会被转为字符串,即优先字符串拼接):

    1 + 1 + 1 + 1 + "" ;//"4"               10 + "  objects" ;// "10  objects",将10转为字符串后计算

    但是JS其他时候更期待数值,所以除上面特殊的情况,其他都选择将字符串转换为数值、将==操作符中的操作数转为数值:

    1 + 1 + 1 + 2 * "" ;// 3,将""转为数字0后计算

    1 == "1" ; //true,字符串转为数值

    1 == "a" ; //false,字符串“a”转数值为NaN

    "0" == false ; //true,两者均转为0

    "true" == true ; //false,"true"转为NaN,true转为1

    null == undefined ;//true ,这里特殊,不要试图通过转换为数据类型来解释这个结论,因为Number(null);为0,Number(undefined);为NaN。而ECMAScript 规范认为,既然 null 和  undefined 的行为很相似,并且都表示 一个无效的值,那么它们所表示的内容也具有相似性

    { }(任何对象)转布尔值为true,[ ](空数组)转布尔值为true(对应章3.5)!!

    9.所有对象都继承两个在对象到原始值转换时使用的方法:toString()和valueOf()。对象到数值的转换先使用偏数值算法将对象转为一个原始值,得到的原始值转为数值,偏数值算法先尝试valueOf(),将toString()作为备用。String\Number\Boolean 这样的包装类定义的valueOf()方法也只是简单地返回被包装的原始值,Array、Function和RegExp简单地继承默认方法。Array类继承默认的valueOf()方法,该方法不返回原始值,so数组转数值时,最终会调用toString()方法。如:

    Number([ ]) ; //0 ,空数组先转为空字符串,空字符串转为数值0

    Number([99]) ; //99,先转为字符串“99”,再转为数值99

    注:多数对象没有valueOf()方法,因此会用toString()方法转换,如 Date对象p71

    1 + { }  // "1[object object] ",对象转换为字符串(使用toString()方法)后再拼接

    2 + null //2 ,null转换为0(使用valueOf()方法)后计算加法

    2 + undefined //NaN,undefined转为NaN后计算加法

    p51 let const var

    10.什么是解构赋值?p55

    右侧值中提取(解构)出一个或多个值,保存到左侧变量中:

    let [x,y] = [1,2];//相当于let x=1,y=2

    章4 表达式与操作符

    1.属性访问表达式中有两种访问属性的语法:

    1)表达式(指定对象)后跟一个句点和一个标识符(指定属性名)

    2)表达式后跟另一个位于方括号中的表达式(指定属性名或数组元素的索引)注:位于.或[前面的表达式都会先求值。若求值结果为null或undefined,抛出TypeError,cause他们是JS中不能有属性值的两个值。但若是指定名字的属性不存在,则属性访问表达式的值是undefined。

    避免报错方法:用?.或?.[ ]语法防止报错。

    同样,函数和方法调用也可用?.() 而不是()来防止报错:

    o.m() ; //常规调用

    o ?. m() ; //条件式属性访问,常规调用

    o.m?.() ; //此处o必须不是null或undefined才不会报错

    2.幂、一元、赋值、三元条件操作符具有右结合性:

    w=(x=(y=z)); 等价于 w=x=y=z;

    3. in操作符,instanceof操作符,typeof操作符 ,delete操作符p78

    4.逻辑与(&&):只有左操作数为真值时才会对右侧求值

    if(a === b) stop(); //只有a===b时才调用stop()

    等价于

    (a === b) && stop(); //返回stop()的结果

    5.先定义操作符??p87

    只要左操作数不是null或undefined就返回该值,否则返回右操作数的值(也是和上面一样避免报错)

    章5 语句

    1. for/of 循环专门用于可迭代对象(数组,字符串,映射Map、集合Set),对象默认是不可迭代的

    2.Object.keys()返回一个对象可枚举自有属性名的数组,Object.values()迭代对象属性中每个键对应的值,

    Object.entries()是个取对象属性名和值放于并返回一个数组的数组。当遍历不可迭代对象时,使用以上三个方法和for/of可迭代其属性。p103、131

    3.for/in 循环可遍历任意对象(区别于for/of取数组值,它取数组的索引)

    for/in只遍历可枚举属性(自有或继承)

    不枚举名字为符号的属性

    新定义一个属性在循环体中,可能不会被枚举;但循环体中删除则不再被枚举

    因此最好基于Object.keys()使用for/of循环,而不是for/in

    4. try/catch/finally语句——JS中的异常处理机制

    try块中发生异常调用catch,catch子句后面是finally块(清理代码,该块一定会执行)

    catch和finally块都是可选的,但只要有try,就必须有其中一个

    5.“use strict” p115

    章6 对象

    1.对象的属性有一个名字和一个值,每个属性有3个属性特性:writable(可写),enumerable(可枚举),configurable(可配置),默认情况下,我们创建的对象三者都可,但很多内置对象拥有只读,不可枚举或不可配置的属性。

    2.对象的创建:通过对象字面量,new关键字,Object.create()函数创建

    3.对象字面量是一个表达式,每次求值都会创建并初始化一个新的,不一样的对象。(循环体中或被重复调用的函数体内,会创建很多新对象)

    4.对象属性值的获取有两种:关联数组(使用方括号和字符串,像访问数组): object["property"] 等价于 object.property(点表示法)

    5.关联数组和点表示法有什么区别?

    关联数组中的字符串是一种JS数组类型,so可以在程序运行期间修改和创建(字符串是动态的,可以运行时修改),而标识符是静态的,必须硬编码到程序中。如:当方法中的参数是对象的属性时,即需要在运行时才输入内容,则无法用点表示法。p125

    6.对象属性在原型对象上的继承:属性赋值原型链上已有的非只读属性时,只会在当前对象上覆盖原先的属性值,而原型链上原本的被继承的对象对应的值是不会被修改的。p126

    7.防止查询的对象是null或undefined时报错(null和undefined没有属性)

    if(book) {

            if(book.author) {

                    surname = book.author.surname;
            }

    }

    等价于

    surname = book && book.author && book.author.surname;(章3.5)

    上面可以直接通过?.条件式属性访问:let surname = book?.author?.surname;(章4.1)

    8.delete操作符只删除自有属性,不删除继承属性(需从定义属性的原型对象上删除),delete不删除configurable特性为false的属性。

    9.如何检查对象是否有一个给定名字的属性?

    1)in操作符:(自有属性、继承属性均可测)

    let o = { x : 1 } ;

    "x"(属性) in o(对象) ; //true

    o.hasOwnProperty("toString")

    2)hasOwnProperty():继承属性返回false

    3)propertyIsEnumerable():(继承、不可枚举返回false)自有属性且该属性的enumerable特性为true才返回true

    4)!== undefined可以确保属性不是未定义的,但是:

    let o = { x : undefined} ;

    o.x !== undefined; //false,存在,但值为undefined

    o.y !== undefined; //false ,不存在

    而使用in可以区分不存在的属性和值为undefined的属性:

    “x” in o;//true,属性x存在

    "y" in p;//false,不存在

    10.序列化对象:把对象的状态转换为字符串的过程JSON.stringify()序列化和JSON.parse()恢复对象

    11.拓展操作符...p137、p144

    章7 数组

    1.扩展操作符:

    1)将可迭代的对象转换为数组或参数

    eg.   

    let a = {x:0,y:0};

    let b = {width:100,height:75};

    let rect = {...a,...b};

    rect.x + rect.y +rect.width +rect.height; //175

    2)将已有对象的属性复制到新对象

    它是创建数组副本的一种便捷方式:`

    let a = [1,2,3];

    let copy = [...a];

    copy[0] = 0;//修改copy不会影响a的值

    a[0] ; //1

    3)适用于任何可迭代对象,把任意字符串(可迭代对象)转换为单个字符的数组

    eg.将字符串中重复字符删去

    let letters = [..."w ooorld"]; //先将字符串转为了数组

    [...new Set(letters)]; //["w"," ","o","r","l","d"]再将数组转换为集合,并用拓展操作符将它转回数组

    2. Array.from()  方法期待一个可迭代对象或类数组对象作为其第一个参数,和拓展操作符一样,也是创建数组副本的一种简单方式

    3.什么是稀疏数组?

    数组中有些索引是没有元素的(元素不存在),其length属性的值比元素个数大。

    创建稀疏数组的方法:用Array()构造函数创建 或 直接给数组的索引赋值eg. a[1000]=0;//增加了一个元素,但length变成了1001 或 用delete操作符(delete操作符不会修改length属性) 

    注:forEach会自动跳过其undefined元素,而delete,for/of,for不会跳过,会输出undefined

    4.当将length属性设置为一个小于当前值的非负整数n,任何索引大于或等于n的数组元素都会从数组中被删除

    5.一些数组方法:p152-166

    forEach()[数组用于自身迭代的函数式方法],

    map(),filter(),every(),some(),find(),findIndex(),reduce(),reduceRight(),flat(),flatMap(),concat(),push(),pop(),shift(),unshift(),slice(),splice(),fill(),copyWithin(),indexOf(),includes(),lastIndexOf(),sort(),reverse(),join(),split()

    章8 函数

    1.函数赋值给对象的属性,称其为该对象的方法。

    2.this

    每个调用除了实参还有另一个值,即调用上下文,即this关键字的值。(任何用作方法的函数实际都会隐式收到调用它的对象,就是this的值)eg.函数是在一个对象上被调用或者通过一个对象被调用,则该对象就是函数的调用上下文或this的值。

    对象中方法的方法,其this值是全局对象(非严格模式)或undefined(严格模式)。(箭头函数则直接继承对象的this)

    3.在语句块中定义的函数只在该块中有定义,对块的外部不可见。

    4.箭头函数:用“箭头”分隔函数的参数和函数体,是表达式而不是语句。没有自己的this,arguments,没有prototype属性,so不能用作构造函数。总是继承自身定义所在环境的this值

    如果箭头函数的函数体是一个return语句,但要返回的表达式是对象字面量,则必须把该对象字面量放在一对圆括号内,避免解释器分不清花括号到底是函数体还是对象字面量的花括号:

    const f = x => { return { value:x }; };//f()返回一个对象

    const g = x => ({ value:x });//g()返回一个对象

    const h = x => { value : x };//错误,什么都不返回

    const i = x => { v:x, w:x };//错误,语法错误

    5.call()、apply()、bind()指定调用的this值(对箭头函数不起作用,第一个参数会被忽略)

    call():方法使用自己的参数列表作为函数的参数,f.call(o,1,2);

    apply():方法期待数组值作为参数,     f.apply(o,[1,2]);

    eg.要把函数f()作为对象o的方法进行调用(不传参数):f.call(o); f.apply(o);

    bind():方法返回一个新函数。除了把函数绑定到对象,还可以柯里化(8.11)p195例子

    6.JS函数定义不会指定函数形参的类型,函数调用也不对传入的实参进行任何类型检查

    if(a===undefinded) a=[]

    等价于

    a = a || [ ];

    7.ES6中可在函数形参列表中直接为每个参数定义默认值。并且可以使用前面参数的值来定义后面参数的默认值。eg. const r = (width, height=width*2) => ({width, height});

    8.剩余形参:在调用时传入比形参多任意数量的实参的函数,剩余形参前面有3个点,且必须是函数声明中最后一个参数。如果一个函数的最后一个形参是以 … 为前缀的,则在函数被调用时,该形参会成为一个数组,数组中的元素都是传递给该函数的多出来的实参的值。

    与7.1的区别:

    扩展运算符会“展开”数组变成多个元素,剩余操作符会收集多个元素和“压缩”成一个单一的元素。

    9.Arguments对象:剩余形参是ES6引入JS的,ES6之前,变长函数是基于Arguments对象实现的。任何函数体内,标识符arguments引用该次调用的Arguments对象。该对象是一个类数组对象,允许通过数值而非名字取得传给函数的参数值。可以将其替换为...args剩余形参。

    10.闭包

    11.什么是柯里化?

    把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    // 普通的add函数
    function add(x, y) {
        return x + y
    }
    
    // Currying后
    function curryingAdd(x) {
        return function (y) {
            return x + y
        }
    }
    
    add(1, 2)           // 3
    curryingAdd(1)(2)   // 3

    12.高阶函数:操作函数的函数,接收一个或多个函数作为参数并返回一个新函数(参数为函数,返回值也为函数)

    章9 类

    1.类的使用是基于原型的继承。如果两个对象从同一个原型继承属性,则说这些对象是同一个类的实例。类意味着一组对象从同一个原型对象继承属性。(创建一个对象,然后创建继承自它的对象,则继承的对象均是该类的成员)

    2.定义一个原型对象,然后使用Object.create()创建一个继承它的对象,则就定义了一个JS类。

    3.构造函数用来初始化新对象函数,构造函数调用的关键在于构造函数的prototype属性将被用作新对象的原型。只有函数对象才有prototype属性。使用同一个构造函数创建的所有对象都继承同一个对象,因而是同一个类的成员。

    4.类名一般以大写字母开头。(构造函数也是首字母大写)

    5.原型对象是类标识的基本:当且仅当两个对象继承同一个原型对象时,它们才是同一个类的实例。而构造函数充当类的公共标识(外在表现)

    6.可以使用instanceof操作符测试类的成员关系:r instanceof Range(构造函数是其右操作数);//true

    当没有使用构造函数时,想判断某个对象原型链中是否包含指定原型,可使用isPrototypeOf()方法。

    7.关于prototype:任何普通的JS函数(不包括箭头函数、生成器函数和异步函数)都可用作构造函数,而构造函数调用时需要一个prototype属性,so每个普通JS函数自动拥有一个prototype属性。该属性的值是一个对象,有一个不可枚举的constructor属性,这个constructor属性的值就是该函数对象。因为构造函数充当类的公共标识,so该constructor属性返回对象的类。p208

    eg.

    1)let o = new F();

    o.constructor === F; //true:constructor属性指定类

    2)let F = function() {};//一个函数对象

    let p = F.prototype;//一个与F关联的原型对象

    let c = p.constructor;//与原型关联的函数

    c === F;//true,对任何F,F.prototype.constructor === F

    8.使用了class关键字(可看作基础类定义机制的“语法糖”),但得到的对象是一个构造函数。

    章10 模块

    13. import.meta引用一个对象,该对象包含当前执行模块的元数据

    import.meta.url的主要使用场景是引用与模块位于同一(或相对)目录下的图片、数据文件或其他资源。用URL()构造函数能方便地相对于import.meta.url的绝对URL来解析相对URL。

    章11 JavaScript标准库

    1.集合与映射(ES6新增了Set和Map类)

    11.1.1 Set类:集合,是一组值。集合没有索引或顺序,也不允许重复(唯一,添加已存在的值没有效果,按照严格相等来判断)。Set()构造函数的参数不一定是数组,但必须是一个可迭代对象

    let unique = new Set("Mississippi");//4个元素:“M","i",”s“,“p”

    方法有:Set.add(),delete(),size(),has(),clear()

    add()接收一个参数,如果传入的是一个数组,则会把整个数组而非数组元素添加到集合中。

    has()检查某个值是不是集合的成员

    includes()

    2.Set对象是可迭代的,so可使用扩展操作符...把集合转换为数组或参数(章7.1)

    3.JS集合是无索引的,所以不能按照索引取值,但它会记住元素的插入顺序,始终按照该顺序迭代集合。

    11.1.2 Map类:该对象表示一组被称为键的值,每个键都关联(或映射到)另一个值(类似数组,允许用任何值作为”索引“)

    11.1.3

    WeakMap(弱映射):保持着对它们键值的“弱”引用,它的存在不妨碍其键值被回收,是不可迭代对象,所以其键是不可访问的,是“弱”。

    WeakSet(弱集合):实现了一组对象,不会妨碍这些对象被作为垃圾收集。也不可迭代。

    11.2 定型数组:定型数组的元素在创建时始终都会被初始化为0,全部都是数值,创建定型数组时必须指定长度(该长度不能再改变)。

    11.3 正则表达式:是一种描述文本模式的对象,正则表达式字面量就是包含在一对斜杠(/)字符之间的字符

    ************正则表达式字符类

    [...]方括号中的任意一个字符

    [^...]不在方括号中的任意一个字符

    \w 任意ASCII单词字符

    \W 任意非ASCII单词字符

    \s 任意Unicode空白字符

    \S 任意非Unicode空白字符 (析:空白字符指 “ ”(空格符)、\r(回车符)、\n(换行符)、\t(制表符)和\f(换页符))

    \d 任意ASCII数字字符。等价于[0-9]

    \D 任意非ASCII数字字符

    [\b] 退格字符字面值

    ************正则表达式重复字符

    {n,m} 匹配前项至少n次,但不超过m次

    {n,} 匹配前项n或更多次

    {n} 匹配前项恰好n次

    ? 匹配前项零或一次,即前项是可选的。等价于{0,1}

    + 匹配前项一或多次。等价于{1,}

    * 匹配前项零或多次。等价于{0,}

    ************正则表达式锚点字符

    ^ 匹配字符串开头

    $ 匹配字符串末尾

    \b 匹配单词边界

    \B 匹配非单词边界的位置

    11.4 日期与时间:

    new Date();//当前时间,若传入一个数值参数,该构造函数会被解释为自1970年至今经过的毫秒数,若传入一个或多个整数参数,会被解释为本地时区的年月日时分秒和毫秒。

    Date API 中,每年第一个月对应数值0,每月第一天对应数值1,若省略时间字段,Date()构造函数默认它们都为0,将时间设置为半夜12点。

    ****时间戳:时间戳是以毫秒为单位的,静态的Date.now()方法返回当前时间的时间戳。

    Date类定义的valueOf()方法返回的是日期的时间戳。

    11.5 Error类:JS的throw和catch语句可以抛出和捕获任何JS值,包括原始值。在创建Error对象时,该对象可以捕获JS的栈状态,如果异常未捕获,则会显示包含错误消息的栈跟踪信息。(有子类,以便触发ES定义的一些特殊类型的错误p277)

    Error对象有两个属性:message和name(值始终是Error)还有一个toString()方法

    11.6 JSON序列化与解析

    当程序要保存数据或需要通过网络连接另一个程序传输数据时,必须将内存中的数据结构转换为字节或字符的序列才可以被传输或保存。将数据结构转换为字节或字符流的方式被称为序列化。

    序列化数据最简单的方式是使用JSON的序列化格式。

    JSON.stringify()【返回一个字符串值】和JSON.parse()【重建原始数据结构】支持JSON序列化和反序列化。

    11.7 URL API:使用new URL()构造函数创建URL对象时,要传一个绝对URL作为参数。也可以将一个相对URL作为第一个参数,将其相对的绝对URL作为第二个参数。p290

    11.8 计时器:setTimeout()函数:只会被调用一次。setInterval()函数:重复调用,每隔指定时间(是个近似的毫秒值)就调用一次指定函数。两者都返回一个值,该值的唯一作用:若该值保存在变量中,可以将其传给clearTimeout()或clearInterval()取消调用。

    章12 迭代器与生成器

    1.迭代器原理:

    三个不同的类型:

    1)可迭代对象:任何具有专用迭代器方法且该方法返回迭代器对象的对象

    2)迭代器对象:任何具有next()方法且该方法返回迭代结果对象的对象

    3)迭代结果对象:具有属性value和done的对象

    2.要迭代一个可迭代对象,首先要调用其迭代器方法获得一个迭代器对象,然后重复调用该迭代器对象的next()方法,直至返回done属性为true的迭代结果对象。

    3.迭代器方法用符号Symbol.iterator作为名字p296

    4.生成器:是一种用新ES6语法定义的迭代器,适合要迭代的值不是某个数据结构的元素,而是计算结果的场景。

    5.创建生成器首先必须定义一个生成器函数function*(简写可以直接一个*)

    //调用该函数不会运行下面的代码,而只会返回一个生成器对象。调用该对象的next()会开始运行,直至一个yield语句为next()方法提供返回值。
    function* one(){
        yield 2;
        yield 3;
        yield 5;
        yield 7;
    }
    //调用生成器函数得到一个生成器。
    let primes = one();
    
    //生成器是个迭代器对象可迭代回送的值
    primes.next().value; //2
    primes.next().value; //3
    ...
    primes.next().done; //true
    
    //生成器有一个Symbol.iterator方法,因此也是可迭代对象
    primes[Symbol.iterator]();//primes
    
    //可像使用其他可迭代对象一样使用生成器
    [...one];//2,3,5,7    扩展操作符
    let sum = 0;
    for(let prime of one()){
    sum += prime;
    sum; //17
    }

    注:不能使用箭头函数语法定义生成器函数。

    yield*关键字迭代可迭代对象并回送得到的每个值(yield*和yield都只能在生成器中使用,yield是一个表达式,可以有值)

    6.生成器的基本特性是可以暂停计算,回送中间结果,然后在某个时刻再恢复计算。

    7.迭代器和生成器中的return()方法是用来提前退出而不是返回值。

    章13 异步JavaScript

    1.ES6新增的期约(Promise)是一种对象,代表某个异步操作暂不可用的结果。(一次异步计算的未来结果,每个通过then()方法注册的函数都只会被调用一次)

    2.关键字async和await是ES2017中引入的,为简化异步编程提供了新语法,允许开发者将基于期约的异步代码写成同步的形式。

    3.异步迭代器和for/await循环是ES2018引入的,允许在看起来同步的简单循环中操作异步事件流。

    4.JS异步编程是使用回调实现的,回调就是函数,可以传给其他函数。

    5.异步网络请求:p309

    6.期约对象是在异步请求结果待定期间返回的,该期约对象有个实例方法then(),回调函数直接传给了then(),当HTTP响应到达时,响应体会被解析为JSON格式,解析后的值会被传给作为then()的参数的函数。

    7.期约对象在响应体未到达前就必须返回(比异步计算早),即计算是在返回期约对象之后执行的,so没办法让该计算像以往那样返回一个值,或抛出一个可以捕获的异常。

    8.期约术语:

    “兑现fulfill”,then()方法调用时返回一个新期约对象,该新期约对象在传给then()的函数执行结束才兑现。

    “拒绝reject”,

    “待定pending”,

    “落定settle”

    //期约2在任务2结束时兑现,期约3在期约2兑现时才被调用
    fetch(theURL)//向URL发送请求并返回期约1,设该请求为任务1
        .then(callback1)//调用期约1的then方法,传入callback1函数,,在期约1兑现时被调用。任务2,返回期约2,任务2在callback1被调用时(返回期约1兑现后的值)开始
        .then(callback2);//任务3,返回期约3,在期约2兑现时被调用
    

    解析:fetch发送一个异步请求,这时该请求设为任务1,请求一发送就会立马返回一个期约1。当该任务1完成,则会兑现期约1,该期约1是第一个then()中的callback1回调函数返回的值,也就是该值一得到,第一个then就会被当成任务2开始执行,执行完就兑现一个期约2,期约2是第二个then的参数callback2的值,该值得到就会触发第二个then的执行,称为任务3。任务3完成时(正常结束的话),期约3也被兑现,到这里已经不再需要给期约3注册回调了,so它落定时啥也不发生,异步计算链结束。

    9.期约链:以线性then()方法调用链的形式表达一连串异步操作。

    10.async和await关键字(相当于.then().catch()):接收基于期约的高效代码并隐藏期约。await关键字接收一个期约并将其转换为一个返回值或抛出一个异常。只能在以async关键字声明的函数内部使用await关键字

    章14 元编程

    1.常规编程是写代码去操作数据,元编程是写代码去操作其他代码

    2.JS的每个属性都有3个关联的特性

    可写(writable):指定是否可以修改属性的值

    可枚举(enumerable):指定是否可以通过for/in循环和Object.keys()方法枚举属性

    可配置(configurable):指定是否可删除、修改属性

    章15 浏览器中的JavaScript

    15.2  

    1.什么是事件?

    事件是文档和浏览器窗口中发生的特定的交互瞬间。与浏览器中web页面进行某些类型的交互时,事件就发生了。浏览器会在文档、浏览器或者某些元素或与之关联的对象发生某些值得关注的事情时生成事件

    什么是事件处理程序?

    响应某个事件的函数就叫做事件处理程序(别名:事件侦听器)。 事件处理程序的名字是以"on"开头,所以像click的事件处理程序就是"onclick"。 load的事件处理程序就是onload。

    2.注册事件处理程序的两种方式:1)设置作为事件目标的对象或文档元素的一个属性;2)把处理程序传给该对象或元素的addEventListener()方法

    3.事件处理程序属性的名字都由“on”和事件名称组成,eg.onclick,onload等必须全部小写,该方式假设事件目标对每种事件最多只有一个处理程序

    4.addEventListener()方法不会重写之前注册的处理程序,任何可以作为事件目标的对象(Window、Document对象和所有文档元素)都有该方法,有三个参数(第三个参数,可传入一个对象p387,该对象的capture属性为true时或者参数直接为true时函数会被注册为捕获事件处理程序,在删除事件时也需要为true,否则为事件冒泡)p386

    5.目标事件是Document或其他文档元素,大多会沿DOM树向上“冒泡”,目标父元素的事件处理程序会被调用,然后注册在目标祖父元素上的事件处理程序会被调用,so只需要在它们的公共祖先元素上注册一个事件处理程序,然后在其中处理事件,eg.<form>元素上注册个“change”事件处理程序,就不用在表单每个元素上注册。 

    6.事件传播三阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应。

    7.事件取消的两种方式:

    浏览器对很多用户事件都会做出反应,像触屏滑动时浏览器就滚动等,若为这些事件注册了事件处理程序,就可阻止浏览器执行其默认动作,为此需调用事件对象的preventDefault()方法(第三个参数中的passive属性为true的话会导致该方法无效),或调用事件对象的stopPropagation()方法取消事件传播。

    8.派发自定义事件:

    一个有addEventListener()方法的对象是一个“事件目标”,则该对象也会有dispatchEvent()方法,用CustomEvent()构造函数可创建自定义事件对象,再传给dispatchEvent() p391

    9.操作DOM

    1)每个Window对象都有一个document属性,引用一个document对象(窗口的内容)

    2)DOM中的选择符(selector)用来描述文档中元素或元素的集合,querySelector()[返回文档中第一个匹配的元素,没有则返回null]和querySelectorAll()[返回文档中所有匹配元素]方法用来找文档中与指定选择符匹配的元素。

    3)元素的选择方法p394

    https://www.cnblogs.com/haoqirui/p/10550007.html

    4)文档的结构与遍历:Node属性,这套API对于文档中文本的变化很敏感,换行符也会被当成Text节点

    5)HTML元素由标签名和一组称为属性的名/值对构成,Element类定义了通用的getAttribute()、setAttribute()、hasAttribute()和removeAttribute()方法,用于查询、设置、检测、删除元素的属性

    6)把HTML属性转换为JS属性,需要全部小写,(连字符分隔(在JS中是减号)的属性将映射为驼峰式属性名)。若多个单词组成,则第二个单词开始每个单词首字母大写。但事件处理程序属性要全部小写,如onclick

    7)不能用delete操作符删除HTML属性,要用removeAttribute()方法

    8)classList属性将class属性作为一个列表来操作,像个类名的集合,且定义了add(),remove(),contains()【判断类名是否存在】和toggle()方法p400

    9)dataset属性:“数据集”属性

    10)textContent属性:可以取得元素的纯文本内容(Text节点),插入修改纯文本

    而innerText属性有一些少见和复杂的行为,如试图阻止表格格式化。(尽量不用)

    ``innerHTML:获得或插入一个元素内部的所有内容,包括标签、文本代码

    11)创建、插入、删除节点

    createElement()创建新元素,

    append()把参数添加到孩子列表的末尾,prepend()把参数添加到孩子列表的开头,after(),before()分别可以在包含元素的孩子列表中间插入。什么区别呢?看下:

    ***append()

    let a = document.getElementById("e");

    a.append(" world");

    console.log(a);

    ***after()

     let a = document.getElementById("e");

            a.after(" world");

            console.log(a);

    解释:通过上面两个,可看出append()是在节点里面的内容末尾插入内容,而after()是在整个节点后面换行并插入内容,且控制台无法查看到该内容。另外两个方法类似。

    12)JS中设置HTML中的style属性,只针对自己的行内样式,样式必须加引号,有单位的必须加单位,如px表示像素,pt表示点。(要将CSS属性设置计算值时,需在计算表达式后面加上单位)

    10.操作CSS

    1)CSS动画和事件

    2)文档元素的位置以CSS像素度量,x像右,y向下增大

    “视口”:浏览器窗口中实际显示文档内容的区域(坐标随窗口滚动而变化)

    “文档”:文档大小(滚动之后,和视口的坐标系就不同了。)

    3)CSS像素(px,js中的像素,缩放会改变大小),设备像素比dpr=物理像素(设备、硬件像素)/CSS(软件)像素【看成一个css像素=dpr个物理像素】p413

    dpr=2,代表每个软件像素实际上是一个2*2硬件像素的网格(两个硬件像素填充一个CSS像素)

    4)getBoundingClientRect()用于获取某个元素相对于视口的位置及元素的大小集合。返回的对象中有top, right, bottom, left,height,width等属性。无参数。

    返回值类型:
    rectObject.top:元素上边到视窗上边的距离;

    rectObject.right:元素右边到视窗左边的距离;

    rectObject.bottom:元素下边到视窗上边的距离;

    rectObject.left:元素左边到视窗左边的距离;

     5)

    document对象表示整个HTML页面,同时它也是window对象的一个属性,nodeType为9,一个页面有且只有一个。而Element对象的nodeType为1,它表示页面中的那些标签元素,比如你用getElementById('myId')获取的元素。document的chlidNodes包含Element,但Element不包含document。Window对象封装了窗口标题、工具按钮、地址栏、状态栏等,这些窗口的组成部分,也被定义为浏览器对象,都是window的成员对象,因此,构成一种层次结构,也就是浏览器对象模型(Browser Object Model)

    6)关于视口、内容大小、滚动位置

    window.innerWidth,innerHeight获得视口大小

    移动设备优化:在<head>中使用<meta name="viewport">标签为页面设置视口宽度

    文档宽高获取:使用document.documentElement的getBoundingClientRect()方法或offsetWidth和offsetHeight属性(返回CSS像素大小)

    文档在视口中的滚动位移获取:window.scrollX和window.scrollY(只读,不能通过设置它们的值来滚动文档),滚动文档应该用window.scrollTo()

    关于滚动的更多属性p415

    11.Web组件

    Web组件是在JS中定义的,在HTML中使用Web组件,需要包含定义该组件的JS文件。p417

    Web组件不能使用自关闭标签定义,不能写成<search-box/>,HTML文件必须包含开标签和闭标签。

    Web组件需要子组件时会放在插槽(slot)中,slot属性是对HTML的扩展,用于指定把哪个子元素放到哪里。

    8)什么是shadow DOM?作用?

    直译为潜藏在黑暗中的 DOM 结构,也就是我们无法直接控制操纵的 DOM 结构。shadow-dom 其实是浏览器的一种能力,它允许在浏览器渲染文档(document)的时候向其中的 Dom 结构中插入一棵 DOM 元素子树,但是特殊的是,这棵子树(shadow-dom)并不在主 DOM 树中。

    以 w3c 上的一个 <video> 例子为例,我们仅仅是填写了一个空白的标签,再加上 src 属性里填上视频地址,就可以播放视频了:我们仅仅填写了一行代码,却拥有比这行代码更多的功能,譬如暂停,播放,音量控制,全屏按钮,进度条等等。这些就是影子DOM封装好的内容。

    在控制台的shadow-root中可看到并操作属性。

    12.SVG是可伸缩矢量图形,是一种图片格式,SVG“图片”是一种对绘制期望图形的精确的、分辨率无关(“可伸缩”)的描述。它通过XML标记语言描述。

    什么是XML语言?
    XML(扩展性标识语言。)它只是用来创造标记语言(比如HTML)的元语言。XML不是HTML的升级,它只是HTML的补充。不能用XML来直接写网页。即便是包含了XML数据,依然要转换成HTML格式才能在浏览器上显示。

    1)<canvas>与图形:有强大的绘图API。使用画布(canvas)绘图要调用方法,使用SVG创建图形需构建XML元素树。

    2)网页中包含的音频和视频---Audio API

    使用<audio>和<video>标签播放音频、视频

    创建方法:通过document.createElement()或者直接使用Audio()构造函数动态创建<audio>元素。播放媒体不一定要把创建的元素添加到文档中,只要调用其play()方法。

    cloneNode()方法可当用户快速点击时,同时播放多个重叠的音效。会有多个Audio元素。(由于Audio元素并未添加到文档中,so播放结束后会被当做垃圾清理)

    13.Window和document对象的location属性引用的都是Location对象,该对象表示当前窗口显示文档的URL,提供了在窗口中加载新文档的API。p455

    Location对象中的:

    href属性以字符串形式返回整个URL,和toString()一样

    hash属性返回URL的“片段标识符”部分(如果有),包含#和一个元素ID

    search属性返回URL中以问号开头的部分,通常是一些查询字符串

    14.fetch规范(传给它一个URL,它返回一个期约  章13

    1. 当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
    2. fetch()的第一个参数是一个用于指定URL的字符串或URL对象。第二个参数用于提供额外选项,包括请求头部,请求方法或请求体。

    15.跨源请求

    同源:协议、主机名、端口都相同

    *想中断已经发出的fetch()请求,需在创建请求前先创建一个AbortController对象(new一下),即中断控制器,想中断请求时调用控制器对象的abort()方法

    16.服务器发送事件p473

    17.WebSocket

    WebSocket API是一个复杂,强大的网络协议对外暴露的简单接口。服务器端和客户端可以进行双向发送。

    https://zhuanlan.zhihu.com/p/74326818

    18.客户端存储:

    1)Web Storage:其API包含localStorage、sessionStorage对象(引用Storage对象),本质上是映射字符串键和值的持久化对象(适合存储大量数据)

    1.1)Storage对象必须是字符串(只能存储字符串,而数值会自动转换为字符串),存储的属性是持久化的。删除所有属性用clear()、删除属性用delete操作符,可被getItem()、setItem()、deleteItem()代替

    1.2)localStorage:刷新页面仍能访问属性中保存的值,存储的数据为永久性的,不同浏览器访问数据存储相互获取不到。数据发生变化时,在其他可见的window对象(不包括导致该变化的窗口)上触发“storage”事件(可看作广播机制)。

    *注册“storage”事件:使用window.onstorage事件属性或调用window.addEventListener()并传入“storage”

    1.3)sessionStorage:窗口或标签页关闭之后,数据都会被删除(特殊:打开最近关闭的标签页并恢复上次浏览会话时,其生命周期拉长)。不同标签页相互隔离,不能读取或重写另一标签页的数据。

    2)Cookie:古老的客户端存储机制,该API难实现,只适合保存少量数据。默认的生命周期也是只在会话期间,但可指定其max-age属性。数据会自动在浏览器和web服务器之间传输(服务器端脚本可读写存储在客户端的cookie值)。cookie默认是不安全的(即在普通不安全的http连接上传输),但可在HTTPS或其他传输协议上安全传输,通过secure属性设置(布尔值)。其path属性和domain属性用来设置可以共享该cookie的网页url路径前缀p484

    3)IndexedDB:异步API,可访问支持索引的对象数据库,每个源可以有任意数量的IndexedDB数据库,每个数据库的名字必须在当前来源下唯一。(IndexedDB中,数据库就是一个名为对象存储的集合,对象存储中存储的是对象)

    19.工作线程与消息传递

    Worker类:该类的实例代表与主线程和事件循环同时运行的线程。

    Worker运行于独立的运行环境,有独立的全局对象,与主线程只能通过异步消息机制通信。

    Worker对象的方法:postMessage()、addEventListener()、removeEventListener()、terminate()p491  importScripts()同步地按顺序加载并执行文件  close()、preventDefault()

    postMessage()方法:调用该方法会触发关联消息端口的”message“事件。:

    对于工作线程,它为两个独立的线程提供了无须共享内存就能通信的安全机制;

    对于窗口,为两个独立的来源提供了安全交换消息的受控机制。

    20.防御XSS安全漏洞、Content-Security-Policy HTTP头部、CSP、CORS跨源

    章16 Node服务器端 JavaScript

    1.什么是Node?

    一个基于Chrome V8引擎的JavaScript运行环境,一个让JavaScript运行在服务端的开发平台。可以 让JS程序读写文件、执行子进程以及实现网络通信。

    2.特点:由其默认异步的API赋能的单线程基于事件的并发能力。

    3.CommonJS模块指Node的模块系统:使用require()函数向模块中导入值,用exports对象或module.exports属性从模块中导出值。(JS代码保存在.cjs结尾的文件中)p230章10也有

    ES6模块使用import和export声明(JS代码在.mjs结尾的文件中)、

    若没有上面的两个文件,Node会在同级目录及所有包含目录中查找一个最近的名为package.json的文件,检查其中JSON对象的顶级type属性,type属性的值为module,则按照ES6模块来加载,值为commonjs,按CommonJS模块加载。

    4.什么是callback回调函数?

    调用一个函数并传一个函数c给它,它执行完之后将c函数调用并返回给我,则该c函数就是回调函数。https://zhuanlan.zhihu.com/p/22677687

    5.Node中的流是什么?https://www.cnblogs.com/yinhaiying/p/10784880.html

    流数据:就是字节数据,在应用程序中各种对象之间交换与传输数据的时候,总是先将该对象中所包含的数据转化为字节数据也就是流数据。再通过流的传输,到达目的对象后,再将流数据转化为该对象中可以使用的数据。
    流:在一个应用程序中,流是一组有序的,有起点和终点的字节数据(流数据)的传输手段。

    作用:处理数据的算法中,需要先把所有数据读到内存中,进行处理,然后再把数据写到某个地方。而流的算法可以把数据分割成小块,内存中不会保存全部数据,这样就不需要使用copyFile()函数(必须分配足够的内存来保存文件的全部内容,且该函数不能在读完旧文件之前写新文件)

    6.管道

    https://blog.csdn.net/u011413061/article/details/50311457

    章17 JavaScript工具和扩展

    1.ESLint检查代码

    2.Prettier格式化代码

    3.Jest做单元测试

    4.npm管理依赖包

    5.使用Babel转译:是一个编译工具,“转译器”,将用现代语言特性编写的JS代码编译为旧版本的代码,兼容只支持ES5的浏览器

    6.JSX:JS中的标记表达式,使用HTML风格的语法定义元素树,eg. let line = <hr/>;

    使用了JSX后,需要用Babel把JSX表达式编译为常规JS

    7.Flow检查类型:Flow是一个相对窄的语言扩展,只为JS代码添加类型注解,然后可以运行Flow工具分析代码、报告类型错误。

    等修复错误并准备好运行代码之后,可以使用Babel从代码中剥离Flow类型注解,返回标准JS代码

    展开全文
  • 21.2 脚本化音频和视频 21.3 SVG:可伸缩的矢量图形 21.4 中的图形 第22章 HTML5 API 22.1 地理位置 22.2 历史记录管理 22.3 跨域消息传递 22.4 Web Worker 22.5 类型化数组和ArrayBuffer 22.6 Blob 22.7 文件系统...
  • JavaScript权威指南(原书第7版)》 适合有一定编程经验、想学习JavaScript的读者,也适合已经在使用JavaScript但希望更深入地理解进而真正掌握这门语言的程序员。《JavaScript权威指南(原书第7版)》的目标是...

    JavaScript权威指南(原书第7版)

    适合有一定编程经验、想学习JavaScript的读者,也适合已经在使用JavaScript但希望更深入地理解进而真正掌握这门语言的程序员。《JavaScript权威指南(原书第7版)》的目标是全面、权威地讲解JavaScript语言,对JavaScript程序中可能用到的最重要的客户端API和服务器端API提供深入的介绍。因此《JavaScript权威指南(原书第7版)》篇幅较长,内容非常详尽,相信认真研究本书的读者都能获益良多。

    近25年来,这本畅销书一直是JavaScript程序员必读的技术著作,《JavaScript权威指南(原书第7版)》已经更新到涵盖JavaScript的2020版。新增的关于类、模块、迭代器、生成器、期约和async/await的章节中,令人深思、富有启发性的示例随处可见。

    JavaScript权威指南(原书第7版)》涵盖以下内容:

    类型、变量、操作符、语句、对象和数组。

    函数、类、模块、迭代器、生成器、期约和async/await。

    JavaScript标准库,包括数据结构、正则表达式、JSON、国际化和URL。

    Web平台,包括文档、组件、图形、网络、存储和线程。

    Node.js,包括缓冲区、文件、流、线程、子进程、Web客户端和Web服务器。

    专业JavaScript开发者必备的工具和语言扩展。

    PC版:http://product.china-pub.com/8078753

    移动版:http://m.china-pub.com/touch/touchproduct.aspx?id=8078753

    JavaScript权威指南(原书第7版)

    JavaScript编程精解(原书第3版)

    第3版深入研究JavaScript语言,详细介绍如何编写漂亮、高效的代码。更新的内容包括:类表示法、箭头函数、迭代器、异步函数、模板字符串和块作用域等功能的全新内容。

    JavaScript编程精解(原书第3版)》通过大量示例进行讲解,并提供大量习题和完整项目案例,为读者提供了编写自己的程序的实践经验。书中不仅介绍JavaScript语言的基本结构以及控制结构、函数和数据结构,还详细介绍错误处理和错误修复、模块化和异步编程,以及Web浏览器编程。

    剖析了JavaScript编程语言的内部细节,并阐述了编写优雅高效代码的方法。作者Marijn Haverbeke从示例代码开始讲解,逐步实现了完整的项目,与此同时作者还提供了一系列习题供读者练习,可以从中学习并了解如何编写自己的程序。首先,你将学习JavaScript语言的基本结构,以及控制结构、函数和数据结构。然后在进入Web浏览器编程之前,你将学习错误处理与bug修复、模块化和异步编程。在构建诸如浏览器游戏、简单的编程语言和绘画程序的项目时,你将学习如何:
    了解编程的基本要素,包括语法、控制和数据。
    使用面向对象和函数式编程技术组织和阐明代码。
    编写浏览器脚本并开发基本的Web应用程序。
    高效地使用DOM与浏览器进行交互。
    利用Node.js构建服务器和实用程序。

    PC版:http://product.china-pub.com/8067951

    移动版:http://m.china-pub.com/touch/touchproduct.aspx?id=8067951

    JavaScript编程精解(原书第3版)

    JavaScript物联网:架构与数据处理

    以JavaScript全栈物联网构建、数据面分析为主线,以实操推进,涵盖必要基础知识、架构、数据收集到展示、接入层开发、开源硬件、生物芯片、安全等核心技术。

    正如Linus的名言:“Talk is cheep.Show me the code.”一样,《JavaScript物联网:架构与数据处理》最重要的,也是首要的一个特点就是注重实践,特别是代码实践。

    从实践层面上讲,笔者不仅在前面的理论章节中给出了大量使用JavaScript进行物联网开发与系统设计实践的例子,而且在实战篇中以真实项目的完整设计作为内容的主体,将项目的重要细节呈现,以飨读者。笔者力求最大化地使用JavaScript,在书中一切适合使用JavaScript来进行分析与描述的部分,一律使用JavaScript来实现。

    从技术层面上讲,本书首次介绍了许多仍然处于实验阶段的新技术,其中包括基于Node.js的一些大数据处理技术(如Skale),以及基于JavaScript的深度学习技术(如Keras.js)。

    PC版:http://product.china-pub.com/7955021

    移动版:http://m.china-pub.com/touch/touchproduct.aspx?id=7955021

    JavaScript物联网:架构与数据处理

    【JavaScript相关书籍推荐】

    斯坦福程序设计入门课:JavaScript实现

    http://product.china-pub.com/8077042

    http://m.china-pub.com/touch/touchproduct.aspx?id=8077042

     

    零基础学JavaScript

    http://product.china-pub.com/8074883

    http://m.china-pub.com/touch/touchproduct.aspx?id=8074883

     

    自己动手做智能产品:嵌入式JavaScript实现

    http://product.china-pub.com/8064272

    http://m.china-pub.com/touch/touchproduct.aspx?id=8064272

     

    JavaScript机器人:用Raspberry Pi、Arduino和BeagleBone构建NodeBots

    http://product.china-pub.com/8062860

    http://m.china-pub.com/touch/touchproduct.aspx?id=8062860

     

    区块链开发实战:基于JavaScript的公链与DApp开发

    http://product.china-pub.com/8062314

    http://m.china-pub.com/touch/touchproduct.aspx?id=8062314

     

    物联网系统开发:树莓派JavaScript编程指南

    http://product.china-pub.com/7282855

    http://m.china-pub.com/touch/touchproduct.aspx?id=7282855

     

    JavaScript+jQuery Mobile+Node.js跨平台网页设计

    http://product.china-pub.com/64143

    http://m.china-pub.com/touch/touchproduct.aspx?id=64143

     

    JavaScript编程精解(原书第2版)

    http://product.china-pub.com/4889547

    http://m.china-pub.com/touch/touchproduct.aspx?id=4889547

     

    JavaScript程序设计:基础·PHP·XML

    http://product.china-pub.com/4613656

    http://m.china-pub.com/touch/touchproduct.aspx?id=4613656

     

    JavaScript性能优化:度量、监控与可视化[图书]

    http://product.china-pub.com/3769687

    http://m.china-pub.com/touch/touchproduct.aspx?id=3769687

     

    Effective JavaScript:编写高质量JavaScript代码的68个有效方法[图书]

    http://product.china-pub.com/3768857

    http://m.china-pub.com/touch/touchproduct.aspx?id=3768857

     

    JavaScript应用开发实践指南[图书]

    http://product.china-pub.com/62134

    http://m.china-pub.com/touch/touchproduct.aspx?id=62134

     

    JavaScript入门经典[按需印刷]

    http://product.china-pub.com/3767299

    http://m.china-pub.com/touch/touchproduct.aspx?id=3767299

     

    编写高质量代码:改善JavaScript程序的188个建议[按需印刷]

    http://product.china-pub.com/3020482

    http://m.china-pub.com/touch/touchproduct.aspx?id=3020482

     

    JavaScript编程精解(JavaScript之父高度评价并强力推荐,系统学习JS首选)[图书]

    http://product.china-pub.com/3684096

    http://m.china-pub.com/touch/touchproduct.aspx?id=3684096

     

    JavaScript权威指南(第6版)      

    http://product.china-pub.com/199271

    http://m.china-pub.com/touch/touchproduct.aspx?id=199271

     

    测试驱动的JavaScript开发(JavaScript敏捷测试指南)[图书]

    http://product.china-pub.com/199036

    http://m.china-pub.com/touch/touchproduct.aspx?id=199036

     

    JavaScript从入门到精通(视频实战版)[图书]

    http://product.china-pub.com/197466

    http://m.china-pub.com/touch/touchproduct.aspx?id=197466

     

    零基础学JavaScript(第2版)[按需印刷]

    http://product.china-pub.com/196255

    http://m.china-pub.com/touch/touchproduct.aspx?id=196255

     

    JavaScript实战手册[图书]

    http://product.china-pub.com/195570

    http://m.china-pub.com/touch/touchproduct.aspx?id=195570

     

    JavaScript完全自学手册[图书]

    http://product.china-pub.com/209229

    http://m.china-pub.com/touch/touchproduct.aspx?id=209229

     

    JavaScript实例精通[图书]

    http://product.china-pub.com/195257

    http://m.china-pub.com/touch/touchproduct.aspx?id=195257

     

    Ajax、JavaScript和PHP编程导学[图书]

    http://product.china-pub.com/129890

    http://m.china-pub.com/touch/touchproduct.aspx?id=129890

     

    挑战JavaScript&Ajax应用开发[图书]

    http://product.china-pub.com/209151

    http://m.china-pub.com/touch/touchproduct.aspx?id=209151

     

    JavaScript 权威指南(第四版)[图书]

    http://product.china-pub.com/9296

    http://m.china-pub.com/touch/touchproduct.aspx?id=9296

     

    【JavaScript特价书推荐】

     (特价书)零基础学JavaScript

    http://product.china-pub.com/233744

    http://m.china-pub.com/touch/touchproduct.aspx?id=233744

     

    (特价书)自己动手做智能产品:嵌入式JavaScript实现

    http://product.china-pub.com/233034

    http://m.china-pub.com/touch/touchproduct.aspx?id=233034

     

    (特价书)JavaScript机器人:用Raspberry Pi、Arduino和BeagleBone构建NodeBots

    http://product.china-pub.com/232738

    http://m.china-pub.com/touch/touchproduct.aspx?id=232738

     

    (特价书)区块链开发实战:基于JavaScript的公链与DApp开发

    http://product.china-pub.com/232667

    http://m.china-pub.com/touch/touchproduct.aspx?id=232667

     

    (特价书)JavaScript物联网:架构与数据处理

    http://product.china-pub.com/231736

    http://m.china-pub.com/touch/touchproduct.aspx?id=231736

     

    (特价书)物联网系统开发:树莓派JavaScript编程指南

    http://product.china-pub.com/231368

    http://m.china-pub.com/touch/touchproduct.aspx?id=231368

     

    (特价书)Three.js开发指南:WebGL的JavaScript 3D库(原书第2版)

    http://product.china-pub.com/230598

    http://m.china-pub.com/touch/touchproduct.aspx?id=230598

     

    (特价书)JavaScript和jQuery实战手册(原书第3版)

    http://product.china-pub.com/231036

    http://m.china-pub.com/touch/touchproduct.aspx?id=231036

     

    (特价书)JavaScript+jQuery Mobile+Node.js跨平台网页设计

    http://product.china-pub.com/230196

    http://m.china-pub.com/touch/touchproduct.aspx?id=230196

     

    (特价书)JavaScript编程精解(原书第2版)

    http://product.china-pub.com/230183

    http://m.china-pub.com/touch/touchproduct.aspx?id=230183

     

    (特价书)JavaScript应用程序设计:使用Node、HTML5和现代JavaScript类库打造稳健的Web应用

    http://product.china-pub.com/230746

    http://m.china-pub.com/touch/touchproduct.aspx?id=230746

     

    (特价书)JavaScript程序设计:基础•PHP•XML

    http://product.china-pub.com/227599

    http://m.china-pub.com/touch/touchproduct.aspx?id=227599

     

    (特价书)Windows 8应用开发实战:使用JavaScript

    http://product.china-pub.com/230418

    http://m.china-pub.com/touch/touchproduct.aspx?id=230418

     

    (特价书)JavaScript入门经典(附光盘)

    http://product.china-pub.com/64507

    http://m.china-pub.com/touch/touchproduct.aspx?id=64507

     

    (特价书)编写高质量代码:改善JavaScript程序的188个建议

    http://product.china-pub.com/222247

    http://m.china-pub.com/touch/touchproduct.aspx?id=222247

    展开全文
  • JavaScript权威指南(第6版)》主要讲述的内容涵盖JavaScript语言本身,以及Web浏览器所实现的JavaScript API。本书第6版涵盖了HTML5和ECMAScript 5,很多章节完全重写,增加了当今Web开发的最佳实践的内容,新增...
  • JavaScript权威指南(第6版)》主要讲述的内容涵盖JavaScript语言本身,以及Web浏览器所实现的JavaScript API。本书第6版涵盖了HTML5和ECMAScript 5,很多章节完全重写,增加了当今Web开发的最佳实践的内容,新增...
  • OReilly精品图书系列:JavaScript权威指南(第6版) 作者简介  David Flanagan是一名程序员,也是一名作家,它的个人网站是 。他在O’Reilly出版的其他畅销书还包括《JavaScript Pocket Reference》、《The Ruby ...
  • 自1996年以来,JavaScript的:权威指南已为JavaScript圣经程序员,程序员指南和全面的参考,以核心语言和客户端JavaScript API的Web浏览器定义。第6版包括HTML5和ECMAScript 5,与jQuery和服务器端JavaScript新的...
  • javascript权威,最新一版 目录 前言 1 第1章 JavaScript概述 5 1.1 JavaScript语言核心 8 1.2 客户端JavaScript 12 第一部分 JavaScript 语言核心 第2章 词法结构 25 2.1 字符集 25 2.2 注释 27 2.3 直接量 27 2.4 ...
  • 挺不错的一本书,值得一看!
  • 第15章 Web浏览器中的JavaScript15.1 网络编程基础15.1.1 HTML script 标签中的JavaScript模块指定脚本类型脚本运行时:异步和延迟按需加载脚本15.1.2 文档对象模型(DOM)15.1.3 Web浏览器中的全局对象15.1.4 脚本...

    JavaScript语言创建于1994年,其明确目的是在web浏览器显示的文档中启用动态行为。自那以后,这种语言有了很大的发展,与此同时,web平台的范围和功能也在爆炸性地增长。今天,JavaScript程序员可以把web看作是一个功能齐全的应用程序开发平台。Web浏览器专门用于显示格式化的文本和图像,但与本机操作系统一样,浏览器还提供其他服务,包括图形、视频、音频、网络、存储和线程。JavaScript是一种使web应用程序能够使用web平台提供的服务的语言,本章将演示如何使用这些服务中最重要的一种。

    本章从web平台的编程模型开始,解释脚本是如何嵌入到HTML页面中的(§15.1),以及JavaScript代码是如何由事件异步触发的(§15.2)。简介后面的部分是核心JavaScript API,它使您的web应用程序能够:

    • 控制文档内容(§15.3)和样式(§15.4)
    • 确定文档元素在屏幕上的位置(§15.5)
    • 创建可重用的用户界面组件(§15.6)
    • 绘制图形(§15.7和§15.8)
    • 播放并生成声音(§15.9)
    • 管理浏览器导航和历史记录(§15.10)
    • 通过网络交换数据(§15.11)
    • 将数据存储在用户计算机上(§15.12)
    • 使用线程执行并行计算(§15.13)

    客户端JavaScript
    在这本书中,在网络上,你会看到术语“客户端JavaScript”。这个术语只是编写在web浏览器中运行的JavaScript的同义词,它与运行在web服务器上的“服务器端”代码形成鲜明对比。

    这两个“端”字是指将web服务器和web浏览器分开的网络连接的两端,web软件开发通常需要在“两端”编写代码。客户端和服务器端通常也被称为“前端”和“后端”。

    这本书的前几版试图全面地涵盖web浏览器定义的所有JavaScript API,结果,这本书在十年前已经太长了。web API的数量和复杂性在不断增长,我认为试图在一本书中涵盖它们已经没有意义了。在第七版中,我的目标是明确介绍JavaScript语言,并深入介绍如何在Node和web浏览器中使用JavaScript语言。本章不能涵盖所有的web API,但它详细介绍了最重要的API,以便您立即开始使用它们。而且,在了解了这里介绍的核心API之后,您应该能够在需要时使用新的API(如§15.15中总结的API)。

    Node只有一个实现和一个权威的文档源。相比之下,Web API是由主要的Web浏览器供应商达成一致的,而权威文档采用的是为实现API的C++程序员而设计的规范,而不是使用JavaScript程序员的规范。幸运的是,Mozilla的“MDN网络文档”项目是一个可靠而全面的web API文档源1

    遗留API
    自JavaScript首次发布以来的25年中,浏览器供应商一直在为程序员添加属性和API。其中许多API现在已经过时。它们包括:

    • 从未被其他浏览器供应商标准化和/或从未实现过的专有API。微软的IE定义了很多这样的API。有些(比如innerHTML属性)被证明是有用的,并且最终被标准化了。其他方法(比如attachEvent()方法)已经过时多年了。
    • 效率低下的API(如document.write()方法)对性能的影响非常严重,以至于不再可以接受它们的使用。
    • 过时的API早已被新的API所取代,以达到同样的目的。一个允许设置文档背景颜色的示例document.bgColor。随着CSS的出现,document.bgColor变成了一个没有实际用途的奇特的特例。
    • 设计拙劣的API被更好的API所取代。在web的早期,标准委员会以一种与语言无关的方式定义了关键的文档对象模型API,以便在Java程序中使用相同的API来处理XML文档,并在JavaScript程序中使用同一API来处理HTML文档。这就导致了一个不太适合JavaScript语言的API,它具有web程序员并不特别关心的属性。从早期的设计错误中恢复需要几十年的时间,但是今天的web浏览器支持一个大大改进的文档对象模型。

    浏览器供应商可能需要在可预见的将来支持这些遗留API,以确保向后兼容性,但本书不再需要对它们进行文档记录,也不需要您了解它们。web平台已经成熟和稳定,如果你是一个经验丰富的web开发人员,还记得这本书的第四或第五版,那么你可能会忘记很多过时的知识,就像你有新的东西需要学习一样。

    15.1 网络编程基础

    本节将解释用于web的JavaScript程序是如何构造的,它们是如何加载到web浏览器中的,它们如何获得输入,如何生成输出,以及它们如何通过响应事件异步运行。

    15.1.1 HTML script 标签中的JavaScript

    Web浏览器显示HTML文档。如果您希望web浏览器执行JavaScript代码,那么HTML文档中必须包含(或引用)代码,而这正是HTML<script>标签所做的。

    JavaScript代码可以在HTML文件中的<script>和</script>标签之间显示。例如,这里是一个HTML文件,其中包含一个带有JavaScript代码的script标签,动态更新文档的一个元素,使其行为类似于数字时钟:

    <!DOCTYPE html> <!-- 这是一个HTML5文件 -->
    <html>
    <!-- 根元素 -->
    
    <head>
      <!-- 标题,脚本和样式可以在这里 -->
      <title>数字时钟</title>
      <style>
        /* 时钟的CSS样式表 */
        #clock {
          /* 样式应用于id=“clock”的元素 */
          font: bold 24px sans-serif;
          /* 使用粗体大字体 */
          background: #ddf;
          /* 在浅蓝灰色的背景上。 */
          padding: 15px;
          /* 用一些空白把它围起来 */
          border: solid black 2px;
          /* 和一个实体黑色边框 */
          border-radius: 10px;
          /* 有圆角。 */
        }
      </style>
    </head>
    
    <body>
      <!-- 主体保存文档的内容。 -->
      <h1>数字时钟</h1> <!-- 显示标题。 -->
      <span id="clock"></span> <!-- 我们将在这个元素中插入时间。 -->
      <script>
        // 定义函数以显示当前时间
        function displayTime() {
          let clock = document.querySelector("#clock"); // 获取id=“clock”的元素
          let now = new Date();                         // 获取当前时间
          clock.textContent = now.toLocaleTimeString(); // 在时钟中显示时间
        }
        displayTime()                    // 马上显示时间
        setInterval(displayTime, 1000);  // 然后每秒钟更新一次。
      </script>
    </body>
    
    </html>
    

    尽管JavaScript代码可以直接嵌入到<script>标签中,但更常见的做法是使用<script>标签的src属性(attribute)来指定包含JavaScript代码的文件的URL(绝对URL或相对于显示的HTML文件URL的URL)。如果我们从这个HTML文件中取出JavaScript代码并将其存储在它自己的scripts/digital_clock.js文件中,则<script>标签可能使用如下所示引用这个文件:

    <script src="scripts/digital_clock.js"></script>
    

    JavaScript文件包含纯JavaScript,没有<script>标签或任何其他HTML。按照惯例,JavaScript代码的文件名以.js结尾。

    带有src属性的<script>标签的行为就像指定的JavaScript文件的内容直接出现在<script>和</script>标签之间。请注意,即使指定了src属性,HTML文档中也需要结束符</script>标签:HTML不支持<script/>标签。

    使用src属性有许多优点:

    • 它简化了你的HTML文件,允许你删除大量的JavaScript代码,也就是说,它有助于保持内容和行为的分离。
    • 当多个网页共享相同的JavaScript代码时,使用src属性可以只维护该代码的一个副本,而不必在代码更改时编辑每个HTML文件。
    • 如果一个JavaScript代码文件由多个页面共享,则只需下载一次,由使用它的第一个页面下载,后续页面可以从浏览器缓存中检索该文件。
    • 由于src属性采用任意URL作为其值,所以来自一个web服务器的JavaScript程序或web页面可以使用其他web服务器导出的代码。很多网络广告都依赖于这个事实。

    模块

    §10.3记录了JavaScript模块并涵盖了它们的导入和导出指令。如果您使用模块编写了JavaScript程序(并且没有使用代码打包工具将所有模块组合到单个非模块JavaScript文件中),则必须使用具有type=“module”属性的<script>标签加载程序的顶层模块。如果您这样做,那么您指定的模块将被加载,它导入的所有模块都将被加载,并且(递归地)加载它们导入的所有模块。完整详情见§10.3.5。

    指定脚本类型

    在web早期,人们认为浏览器可能有一天会实现JavaScript以外的语言,程序员在其<script>标签中添加了language=“javascript”和type=“application/javascript”等属性。这完全没有必要。JavaScript是web的默认(也是唯一)语言。language属性已弃用,在<script>标签上使用type属性只有两个原因:

    • 指定脚本是一个模块
    • 将数据嵌入网页而不显示(见§15.3.4)

    脚本运行时:异步和延迟

    当JavaScript第一次被添加到web浏览器中时,还没有用于遍历和操作已呈现文档的结构和内容的API。JavaScript代码影响文档内容的唯一方法是在文档加载过程中动态生成该内容。它通过使用document.write()方法将HTML文本注入到脚本所在的文档中。

    document.write()的使用不再被认为是一种好的风格,但事实上它是可能的,这意味着当HTML解析器遇到<script>元素时,它必须在默认情况下运行脚本,以确保它在继续解析和呈现文档之前不会输出任何HTML。这会显著降低网页的解析和呈现速度。

    幸运的是,这种默认的同步或阻塞脚本执行模式并不是唯一的选择。<script>标签可以具有defer和async属性,这会导致脚本以不同的方式执行。这些是布尔属性,它们没有值;它们只需要出现在<script>标签上。请注意,这些属性仅在与src属性一起使用时才有意义:

    <script defer src="deferred.js"></script>
    <script async src="async.js"></script>
    

    defer和async属性都是告诉浏览器链接脚本不使用document.write()生成HTML输出的方法,因此浏览器可以在下载脚本的同时继续解析和呈现文档。defer属性使浏览器推迟脚本的执行,直到文档被完全加载和解析并准备好进行操作。async属性使浏览器尽快运行脚本,但在下载脚本时不会阻止文档解析。如果<script>标签同时具有这两个属性,则async属性优先。

    请注意,延迟脚本按照它们在文档中出现的顺序运行。异步脚本在加载时运行,这意味着它们可能会无序执行。

    默认情况下,带有type=“module”属性的脚本将在文档加载后执行,就像它们具有defer属性一样。您可以使用async属性覆盖此默认值,这将导致在加载模块及其所有依赖项后立即执行代码。

    对于直接包含在HTML中的代码,async和defer属性的一个简单替代方法是将脚本放在HTML文件的末尾。这样,脚本可以在文档内容被解析并准备好操作之前运行。

    按需加载脚本

    有时,您可能有一些JavaScript代码,当第一次加载文档时不使用这些代码,并且只有在用户执行某些操作(如单击按钮或打开菜单)时才需要该代码。如果您使用模块开发代码,您可以使用import()按需加载模块,如§10.3.6所述。

    如果不使用模块,只需在需要加载脚本时向文档添加<script>标签,就可以按需加载JavaScript文件:

    // 从指定的URL异步加载和执行脚本
    // 返回一个在脚本加载后解决的Promise。
    function importScript(url) {
        return new Promise((resolve, reject) => {
            let s = document.createElement("script"); // 创建<script>元素
            s.onload = () => { resolve(); };          // 加载后解决Promise
            s.onerror = (e) => { reject(e); };        // 失败时拒绝
            s.src = url;                              // 设置脚本URL
            document.head.append(s);                  // 将<script>添加到文档
        });
    }
    

    这个importScript()函数使用DOM API(§15.3)创建一个新的<script>标签并将其添加到文档<head>中。它使用事件处理程序(§15.2)来确定脚本何时成功加载或何时加载失败。

    15.1.2 文档对象模型(DOM)

    客户端JavaScript编程中最重要的对象之一是Document对象,它表示在浏览器窗口或选项卡中显示的HTML文档。用于处理HTML文档的API称为文档对象模型,或DOM,§15.3将对此进行详细介绍。但是DOM是客户端JavaScript编程的核心,因此值得在这里介绍它。

    HTML文档包含一个嵌套的HTML元素,形成一个树。考虑以下简单的HTML文档:

    <html>
    
    <head>
        <title>Sample Document</title>
    </head>
    
    <body>
        <h1>An HTML Document</h1>
        <p>This is a <i>simple</i> document.
    </body>
    
    </html>
    

    顶层的<html>标签包含<head>和<body>标签。<head>标签包含一个<title>标签。并且<body>标签包含<h1>和<p>标签。<title>和<h1>标签包含文本字符串,<p>标签包含两个文本字符串,它们之间有一个<i>标签。

    DOM API映射HTML文档的树结构。对于文档中的每个HTML标签,都有一个对应的JavaScript元素对象,对于文档中每次运行的文本,都有一个对应的Text(文本)对象。Element(元素)和Text(文本)类以及Document(文档)类本身都是更通用的Node(节点)类的子类,节点对象被组织成树状结构,JavaScript可以使用DOM API查询和遍历这些树结构。本文档的DOM表示如图15-1所示。

    在这里插入图片描述
    图15-1. HTML文档的树表示

    如果您还不熟悉计算机编程中的树结构,那么知道它们借用了家谱中的术语是很有帮助的。节点正上方的节点是该节点的父节点。另一个节点正下方一个级别的节点是该节点的子节点。处于同一级别且具有相同父级的节点是兄弟节点。另一个节点下任意数量级别的节点集都是该节点的后代。父节点、祖父母节点和节点上方的所有其他节点都是该节点的祖先。

    DOM API包括创建新元素和文本节点的方法,以及将它们作为其他元素对象的子节点插入到文档中的方法。还有一些方法可以在文档中移动元素并完全删除它们。虽然服务器端应用程序可能通过使用console.log()编写字符串来生成纯文本输出,但是客户端JavaScript应用程序可以通过使用DOM API构建或操作文档树文档来生成格式化的HTML输出。

    每个HTML标签类型都对应一个JavaScript类,并且文档中的每个标签都由该类的一个实例表示。例如,<body>标签由HTMLBodyElement的实例表示,<table>标签由HTMLTableElement的实例表示。JavaScript元素对象具有与标签的HTML属性相对应的属性。例如,表示<img>标签的HTMLImageElement的实例具有与标签的src属性相对应的src属性。src属性的初始值是HTML标签中显示的属性值,使用JavaScript设置此属性会更改HTML属性的值(并导致浏览器加载和显示新图像)。大多数JavaScript元素类只是镜像HTML标签的属性,但有些类定义了其他方法。例如,HTMLAudioElement和HTMLVideoElement类定义了play()和pause()等方法来控制音频和视频文件的播放。

    15.1.3 Web浏览器中的全局对象

    每个浏览器窗口或选项卡都有一个全局对象(§3.7)。在该窗口中运行的所有JavaScript代码(在工作线程中运行的代码除外;请参见§15.13)都共享这个全局对象。不管文档中有多少脚本或模块,这都是正确的:一个文档的所有脚本和模块共享一个全局对象;如果一个脚本定义了该对象的属性,则该属性对所有其他脚本也可见。

    全局对象是JavaScript的标准库定义的地方:parseInt()函数、Math对象、Set类等等。在web浏览器中,全局对象还包含各种web API的主要入口点。例如,document属性表示当前显示的文档,fetch()方法发出HTTP网络请求,Audio()构造函数允许JavaScript程序播放声音。

    在web浏览器中,全局对象有双重作用:除了定义内置类型和函数外,它还表示当前的web浏览器窗口,并定义诸如history(§15.10.2)之类的属性,history表示窗口的浏览历史,innerWidth保存窗口的像素宽度。这个全局对象的一个属性名为window,它的值是全局对象本身。这意味着您可以简单地键入window来引用客户端代码中的全局对象。当使用特定于窗口的属性时,通常最好包含一个window.前缀:例如,window.innerWidth比innerWidth更清晰。

    15.1.4 脚本共享一个命名空间

    对于模块,在模块的顶层(即任何函数或类定义之外)定义的常量、变量、函数和类对模块是私有的,除非它们被显式导出,在这种情况下,它们可以被其他模块选择性地导入。(请注意,代码打包工具也支持模块的这个属性。)

    但是,对于非模块脚本,情况则完全不同。如果脚本中的顶层代码定义了常量、变量、函数或类,则该声明将对同一文档中的所有其他脚本可见。如果一个脚本定义函数f(),另一个脚本定义类c,那么第三个脚本可以调用函数并实例化类,而不必执行任何操作来导入它们。因此,如果不使用模块,文档中的独立脚本共享一个名称空间,其行为方式就好像它们都是单个较大脚本的一部分。这对于小程序来说可能很方便,但是对于较大的程序来说,避免命名冲突的需要可能会成为问题,特别是当一些脚本是第三方库时。

    这个共享名称空间的工作方式有一些历史上的怪癖。顶层的var和function声明在共享全局对象中创建属性。如果一个脚本定义了顶级函数f(),那么同一文档中的另一个脚本可以调用f()或window.f()。另一方面,在顶层使用ES6声明const、let和class时,不会在全局对象中创建属性。但是,它们仍然是在一个共享的命名空间中定义的:如果一个脚本定义了一个类C,其他脚本将能够用new C()创建该类的实例,但不能用new window.C()创建。

    总结一下:在模块中,顶级声明的作用域是模块,可以显式导出。但是,在非模块脚本中,顶级声明的作用域是包含文档的,并且声明由文档中的所有脚本共享。旧的var和函数声明是通过全局对象的属性共享的。更新的const、let和class声明也被共享并具有相同的文档范围,但它们不作为JavaScript代码可以访问的任何对象的属性存在。

    15.1.5 JavaScript程序的执行

    在客户端JavaScript中没有程序的正式定义,但是可以说JavaScript程序由文档中或从文档引用的所有JavaScript代码组成。这些独立的代码共享一个全局窗口对象,这使它们能够访问表示HTML文档的同一个底层Document对象。不是模块的脚本还共享一个顶级命名空间。

    如果网页包含一个被嵌入的框架(使用<iframe>元素),则被嵌入文档中的JavaScript代码与包含被嵌入文档的文档中的代码具有不同的全局对象和文档对象,可以将其视为一个单独的JavaScript程序。不过,请记住,JavaScript程序的边界并没有正式的定义。如果包含文档和被包含文档都是从同一个服务器加载的,那么一个文档中的代码可以与另一个文档中的代码进行交互,如果需要,可以将它们视为单个程序的两个交互部分。§15.13.6解释了JavaScript程序如何在<iframe>中运行的JavaScript代码之间收发消息。

    可以将JavaScript程序的执行看作是分两个阶段执行的。在第一阶段,加载文档内容,并运行来自<script>元素(内联脚本和外部脚本)的代码。脚本通常按照它们在文档中出现的顺序运行,尽管这个默认顺序可以通过我们描述的async和defer属性进行修改。任何单个脚本中的JavaScript代码都是自上而下运行的,当然,还包括JavaScript的条件语句、循环和其他控制语句。有些脚本在第一阶段并不做任何事情,而是定义在第二阶段使用的函数和类。其他脚本可能在第一个阶段执行重要的工作,而在第二个阶段什么也不做。想象一下,在文档末尾有一个脚本,它在文档中找到所有<h1>和<h2>标签,并通过在文档开头生成和插入目录来修改文档。这完全可以在第一阶段完成。(请参见§15.3.6中的具体示例。)

    一旦加载了文档并运行了所有脚本,JavaScript执行将进入第二阶段。这个阶段是异步和事件驱动的。如果一个脚本要参与第二个阶段,那么在第一个阶段它必须完成的一件事就是注册至少一个事件处理程序或其他异步调用的回调函数。在这个事件驱动的第二阶段,web浏览器调用事件处理程序函数和其他回调来响应异步发生的事件。事件处理程序通常在响应用户输入(鼠标单击、击键等)时调用,但也可能由网络活动、文档和资源加载、运行时间或JavaScript代码中的错误触发。事件和事件处理程序在§15.2中有详细描述。

    在事件驱动阶段,首先发生的一些事件是“DOMContentLoaded”和“load”事件。“DOMContentLoaded”在HTML文档被完全加载和解析后被触发。当文档的所有外部资源(如图像)也已完全加载时,将触发“load”事件。JavaScript程序通常使用这些事件之一作为触发器或启动信号。常见的情况是,程序的脚本定义函数,但除了注册事件处理程序函数之外,不执行任何操作,以便在事件驱动的执行阶段开始时由“load”事件触发。正是这个“load”事件处理程序,然后操纵文档并执行程序应该执行的任何操作。请注意,在JavaScript编程中,事件处理程序函数(如这里描述的“加载”事件处理程序)注册其他事件处理程序是很常见的。

    JavaScript程序的加载阶段相对较短:理想情况下不到一秒钟。一旦加载了文档,事件驱动阶段将持续到文档通过web浏览器显示的时间。因为这个阶段是异步的和事件驱动的,所以可能会有很长一段时间没有执行JavaScript,中间是由用户或网络事件触发的突发活动。接下来我们将更详细地介绍这两个阶段。

    客户端JavaScript线程模型

    JavaScript是一种单线程语言,单线程执行使编程更加简单:您可以编写代码,并保证两个事件处理程序永远不会同时运行。您可以在没有其他线程试图同时修改文档内容的情况下操作文档内容,而且在编写JavaScript代码时,您不必担心锁、死锁或竞争条件。

    单线程执行意味着web浏览器在脚本和事件处理程序执行时停止响应用户输入。这给JavaScript程序员带来了负担:这意味着JavaScript脚本和事件处理程序不能运行太长时间。如果脚本执行计算密集型任务,它将在文档加载过程中引入延迟,并且在脚本完成之前,用户将看不到文档内容。如果事件处理程序执行计算密集型任务,浏览器可能变得无响应,可能导致用户认为它已崩溃。

    web平台定义了一种称为“web worker”的受控并发形式。web worker是一个后台线程,用于执行计算密集型任务,而不冻结用户界面。运行在web worker线程中的代码不能访问文档内容,不能与主线程或其他工作线程共享任何状态,并且只能通过异步消息事件与主线程和其他工作线程通信,因此主线程无法检测到并发性,并且web worker不会更改基本的JavaScript程序的单线程执行模型。有关网络安全线程机制的详细信息,请参见§15.13。

    客户端JavaScript时间轴

    我们已经看到JavaScript程序开始于脚本执行阶段,然后过渡到事件处理阶段。这两个阶段可以进一步细分为以下步骤:

    1. web浏览器创建一个Document对象并开始解析web页面,在解析HTML元素及其文本内容时向文档添加元素对象和文本节点。document.readyState属性在此阶段具有值“loading”。
    2. 当HTML解析器遇到不具有async、defer或type=“module”属性的<script>标签时,它会将该脚本标签添加到文档中,然后执行脚本。脚本是同步执行的,当脚本下载(如果需要)并运行时,HTML解析器会暂停。像这样的脚本可以使用document.write()将文本插入到输入流中,当解析器继续时,该文本将成为文档的一部分。像这样的脚本通常只定义函数并注册事件处理程序以供以后使用,但它可以遍历和操作文档树,因为它此时已经存在。也就是说,没有async或defer属性的非模块脚本可以看到它们自己的<script>标签和前面的文档内容。
    3. 当解析器遇到设置了async属性的<script>元素时,它开始下载脚本文本(如果脚本是一个模块,它还会递归地下载脚本的所有依赖项),并继续解析文档。脚本将在下载后尽快执行,但解析器不会停止并等待下载。他们可以看到自己的<script>标签和它前面的所有文档内容,并且可能有权也可能无权访问其他文档内容。
    4. 当文档被完全解析后,document.readyState属性将更改为“interactive”。
    5. 任何设置了defer属性的脚本(以及没有async属性的模块脚本)将按照它们在文档中出现的顺序执行。此时也可以执行async脚本。延迟脚本可以访问完整的文档,并且不能使用document.write()方法。
    6. 浏览器在Document对象上触发一个“DOMContentLoaded”事件。这标志着从同步脚本执行阶段过渡到程序执行的异步、事件驱动阶段。但是,请注意,此时可能仍有一些async脚本尚未执行。
    7. 此时文档已完全解析,但浏览器可能仍在等待其他内容(如图像)加载。当所有这些内容加载完毕,并且所有async脚本都已加载和执行时,document.readyState属性将更改为“complete”,web浏览器将对窗口对象触发“load”事件。
    8. 从现在起,事件处理程序将异步调用,以响应用户输入事件、网络事件、计时器过期等。

    15.1.6 程序输入和输出

    与任何程序一样,客户端JavaScript程序处理输入数据以生成输出数据。有多种可用的输入:

    • 文档本身的内容,JavaScript代码可以使用DOM API访问这些内容(§15.3)。
    • 用户输入,以事件的形式,例如HTML<button>元素上进行鼠标点击(或触摸屏点击),或文本输入到HTML<textrarea>元素中。§15.2演示了JavaScript程序如何响应用户事件。
    • 正在显示的文档的URL可以作为document.URL提供给客户端JavaScript。如果将此字符串传递给URL()构造函数(§11.9),则可以轻松访问URL的path、query和fragment部分。
    • HTTP“Cookie”请求头的内容作为document.cookie可供客户端代码使用。服务器端代码通常使用cookie来维护用户会话,但客户端代码也可以在必要时读取(和写入)Cookies。更多详情见§15.12.2。
    • 全局navigator属性提供对有关web浏览器、运行在其上的操作系统以及每个浏览器的功能的信息的访问。例如,navigator.userAgent是标识web浏览器的字符串,navigator.language是用户的首选语言,navigator.hardwareConcurrency返回web浏览器可用的逻辑CPU数。类似地,全局screen属性通过screen.width和screen.height属性提供对用户显示大小的访问。在某种意义上,这些navigator和screen对象对于web浏览器就像环境变量对于Node程序一样。

    客户端JavaScript通常在需要时生成输出,方法是使用DOM API(§15.3)操作HTML文档,或者使用更高级的框架(如React或Angular)来操作文档。客户端代码还可以使用console.log()和相关方法(§11.8)生成输出。但此输出仅在web开发人员控制台中可见,因此在调试时很有用,但对于用户可见的输出则不可用。

    15.1.7 程序错误

    与直接在操作系统上运行的应用程序(如Node应用程序)不同,web浏览器中的JavaScript程序不会真正“崩溃”。如果JavaScript程序运行时发生异常,并且您没有catch语句来处理,则开发人员控制台中将显示一条错误消息,但任何已注册的事件处理程序都会继续运行并响应事件。

    如果您想定义在发生此类未捕获异常时调用的最后一个错误处理程序,请将Window对象的onerror属性设置为错误处理程序函数。当一个未捕获的异常沿着调用堆栈向上传播,并且开发人员控制台中将显示一条错误消息时,将使用三个字符串参数调用window.onerror函数。window.onerror的第一个参数是描述错误的消息。第二个参数是一个字符串,它包含导致错误的JavaScript代码的URL。第三个参数是发生错误的文档中的行号。如果onerror处理程序返回true,它将告诉浏览器该处理程序已处理错误,并且无需进一步操作,换句话说,浏览器不应显示自己的错误消息。

    当一个Promise被拒绝并且没有.catch()函数来处理它时,这种情况非常类似于未处理的异常:程序中的意外错误或逻辑错误。您可以通过定义window.onunhandledrejection函数或使用window.addEventListener()为“unhandledrejection”事件注册处理程序来检测此情况。传递给这个处理程序的事件对象将有一个promise属性,其值是被拒绝的promise对象,而reason属性的值是传递给.catch()函数的值。与前面描述的错误处理程序一样,如果对未处理的拒绝事件对象调用preventDefault(),则它将被视为已处理,并且不会在开发人员控制台中导致错误消息。

    通常不需要定义onerror或onunhandledrejection处理程序,但如果您希望向服务器报告客户端错误(例如,使用fetch()函数发出HTTP POST请求),以便获取有关用户浏览器中发生的意外错误的信息,则它可以作为遥测机制非常有用。

    15.1.8 Web安全模型

    网页可以在您的个人设备上执行任意JavaScript代码这一事实具有明显的安全隐患,浏览器供应商一直在努力平衡两个相互竞争的目标:

    • 定义功能强大的客户端API以支持有用的web应用程序
    • 防止恶意代码读取或更改您的数据,损害您的隐私,欺骗您,或浪费您的时间

    下面的小节简要介绍了作为JavaScript程序员应该注意的安全限制和问题。

    JavaScript不能做什么

    Web浏览器抵御恶意代码的第一道防线就是它们根本不支持某些功能。例如,客户端JavaScript不提供任何方法来写入或删除客户端计算机上的任意文件或列出任意目录。这意味着JavaScript程序不能删除数据或植入病毒。

    同样,客户端JavaScript没有通用的联网功能。客户端JavaScript程序可以发出HTTP请求(§15.11.1)。另一个被称为WebSockets(§15.11.3)的标准定义了一个与专用服务器通信的类套接字API。但这两个API都不允许对更广泛的网络进行非中介访问。通用internet客户端和服务器不能用客户端JavaScript编写。

    同源策略

    同源策略是对Java脚本代码可以与哪些web内容进行交互的全面安全限制。它通常在网页包含<iframe>元素时发挥作用。在这种情况下,同源策略控制一个框架中JavaScript代码与其他框架内容的交互。特别是,脚本只能读取与包含脚本的文档具有相同来源的窗口和文档的属性。

    文档的来源定义为从中加载文档的URL的协议、主机和端口。从不同的web服务器加载的文档具有不同的来源。通过同一主机的不同端口加载的文档具有不同的来源。而且加载了http:protocol的文档与使用https:protocol加载的文档具有不同的来源,即使它们来自同一个web服务器。浏览器通常将每个file:URL视为一个单独的来源,这意味着如果您正在开发一个显示来自同一服务器的多个文档的程序,您可能无法使用file:URL在本地测试它,并且必须在开发期间运行静态web服务器。

    重要的是要理解脚本本身的来源与同源策略无关:重要的是包含嵌入脚本的文档的来源。例如,假设主机a托管的脚本(使用<script>元素的src属性)包含在主机B提供服务的网页中。该脚本的来源是主机B,并且该脚本对包含它的文档的内容具有完全访问权限。如果这个文档包含一个<iframe>,该iframe包含来自主机B的第二个文档,则该脚本还可以完全访问该第二个文档的内容。但是,如果顶级文档包含另一个<iframe>,该iframe显示来自主机C的文档(甚至来自主机a的文档),则同源策略将生效,并阻止脚本访问此嵌套文档。

    同源策略也适用于脚本化的HTTP请求(见§15.11.1)。JavaScript代码可以向加载包含文档的web服务器发出任意的HTTP请求,但它不允许脚本与其他web服务器通信(除非这些web服务器选择使用CORS,如下面所述)。

    同源策略给使用多个子域的大型网站带来了问题。例如,源为“orders.example.com”的脚本可能需要从“example.com”上的文档中读取属性。为了支持此类多域网站,脚本可以通过将“document.domain”设置为域后缀来更改其来源。所以一个源为”https://orders.example.com“的脚本可以通过将“document.domain”设置为“example.com”将其来源更改为”https://example.com“,但该脚本无法将“document.domain”设置为“orders.example”、“ample.com”或“com”。

    放松同源策略的第二种技术是跨源资源共享(Cross-Origin Resource Sharing,CORS),它允许服务器决定他们愿意为哪些源服务。CORS用一个新的Origin:请求头和一个新的Access-Control-Allow-Origin响应头扩展了HTTP。它允许服务器使用报头显式列出可能请求文件的源,或者使用通配符,并允许任何站点请求文件。浏览器尊重这些CORS头文件,除非它们存在,否则不会放松同源限制。

    跨站点脚本

    跨站点脚本(XSS)是一类安全问题的术语,其中攻击者将HTML标签或脚本注入目标网站。客户端JavaScript程序员必须了解并防范跨站点脚本。

    如果网页动态生成文档内容是基于用户提交的数据,但是不首先通过删除任何嵌入的HTML标签来“净化”这些数据,则网页容易受到跨站点脚本的攻击。作为一个简单的示例,请考虑以下使用JavaScript按名字问候用户的网页:

    <script>
    let name = new URL(document.URL).searchParams.get("name");
    document.querySelector('h1').innerHTML = "Hello " + name;
    </script>
    

    这个两行脚本从文档URL的“name”查询参数提取输入。然后它使用DOM API将一个HTML字符串注入到文档中的第一个<h1>标签中。此页面旨在通过如下URL调用:

    http://www.example.com/greet.html?name=David

    当这样使用时,它会显示文本“Hello David”。但是请考虑使用以下查询参数调用它时会发生什么情况:

    name=%3Cimg%20src=%22x.png%22%20οnlοad=%22alert(%27hacked%27)%22/%3E

    当对URL转义参数进行解码时,此URL将导致将以下HTML注入到文档中:

    Hello <img src=“x.png” οnlοad=“alert(‘hacked’)”/>

    图像加载后,onload属性中的JavaScript字符串被执行。全局alert()函数的作用是:显示一个模式对话框。一个单独的对话框相对来说是良性的,但它表明在这个站点上可以执行任意代码,因为它显示未经净化的HTML。

    之所以称为跨站点脚本攻击,是因为涉及多个站点。站点B包含到站点A的精心编制的链接(如前一个示例中的链接)。如果站点B能够说服用户单击该链接,他们将被带到站点A,但该站点现在将运行来自站点B的代码。该代码可能会损坏页面或导致页面故障。更危险的是,恶意代码可以读取站点A存储的cookie(可能是账号或其他个人识别信息),并将这些数据发送回站点B。注入的代码甚至可以跟踪用户的按键并将数据发送回站点B。

    一般来说,防止XSS攻击的方法是在使用任何不受信任的数据创建动态文档内容之前删除HTML标签。通过将不受信任的输入字符串中的特殊HTML字符替换为等效的HTML实体,可以修复前面显示的greet.html文件:

    name = name
    	.replace(/&/g, "&amp;")
    	.replace(/</g, "&lt;")
    	.replace(/>/g, "&gt;")
    	.replace(/"/g, "&quot;")
    	.replace(/'/g, "&#x27;")
    	.replace(/\//g, "&#x2F;")
    

    解决XSS问题的另一种方法是构建web应用程序,使不受信任的内容始终显示在<iframe>中,并将sandbox属性设置为禁用脚本和其他功能。

    跨站点脚本是一个有害的漏洞,其根源深入到web体系结构中。深入了解这个漏洞是值得的,但进一步的讨论超出了本书的范围。有许多在线资源可以帮助您抵御跨站点脚本。

    15.2 事件

    客户端JavaScript程序使用异步事件驱动编程模型。在这种编程风格中,每当文档或浏览器或与之相关的元素或对象发生有趣的事情时,web浏览器就会生成一个事件。例如,web浏览器在完成加载文档、用户将鼠标移到超链接上或用户敲击键盘上的键时生成事件。如果JavaScript应用程序关心特定类型的事件,它可以注册一个或多个函数,以便在该类型的事件发生时调用。请注意,这并不是web编程所独有的:所有具有图形用户界面的应用程序都是这样设计的:它们坐在那里等待与之交互(即,它们等待事件发生),然后做出响应。

    在客户端JavaScript中,事件可以发生在HTML文档中的任何元素上,这使得web浏览器的事件模型比Node的事件模型复杂得多。我们从一些重要的定义开始本节,这些定义有助于解释事件模型:

    事件类型

    • 此字符串指定发生的事件类型。例如,“mousemove”类型表示用户移动了鼠标。“keydown”类型表示用户按下键盘上的某个键。“load”类型表示文档(或其他资源)已从网络加载完毕。因为事件的类型只是一个字符串,它有时被称为事件名,实际上,我们使用这个名称来标识我们所讨论的事件的类型。

    事件目标

    • 这是发生事件或与事件关联的对象。当我们谈到一个事件时,我们必须同时指定类型和目标。例如,window上的load事件或<button>元素上的click事件。窗口、文档和元素对象是客户端JavaScript应用程序中最常见的事件目标,但有些事件是在其他类型的对象上触发的。例如,一个Worker对象(一种线程,包含在§15.13中)是当Worker线程向主线程发送消息时发生的“message”事件的目标。

    事件处理程序或事件侦听器

    • 此函数用于处理或响应事件2。应用程序使用web浏览器注册其事件处理程序函数,指定事件类型和事件目标。当指定目标上发生指定类型的事件时,浏览器将调用处理程序函数。当为一个对象调用事件处理程序时,我们称浏览器已“激发”、“触发”或“调度”事件。注册事件处理程序的方法有很多种,§15.2.2和§15.2.3解释了处理程序注册和调用的详细信息。

    事件对象

    • 此对象与特定事件关联,并包含有关该事件的详细信息。事件对象作为参数传递给事件处理程序函数。所有事件对象都有一个指定事件类型的type属性和一个指定事件目标的target属性。每个事件类型为其关联的事件对象定义一组属性。例如,与鼠标事件相关联的对象包括鼠标指针的坐标,与键盘事件关联的对象包含有关按下的键和按下的修改键的详细信息。许多事件类型只定义一些标准属性,例如type和target,并且不包含太多其他有用的信息。对于这些事件,重要的是事件的发生,而不是事件的细节。

    事件传播

    • 这是浏览器决定在哪个对象上触发事件处理程序的过程。对于特定于单个对象的事件,例如窗口对象上的“load”事件或Worker对象上的“message”事件,不需要传播。但是,当HTML文档中的元素发生某些类型的事件时,它们会在文档树上传播或“冒泡”。如果用户将鼠标移动到超链接上,则鼠标mousemove事件首先会在定义该链接的<a>元素上触发。然后,它会被触发到包含元素上:可能是<p>元素、一个<section>元素和文档对象本身。在文档或其他容器元素上注册单个事件处理程序有时比在感兴趣的每个元素上注册处理程序更方便。事件处理程序可以停止事件的传播,这样它就不会继续冒泡,也不会触发包含元素的处理程序。处理程序通过调用事件对象的方法来实现这一点。在另一种形式的事件传播(称为事件捕获)中,在容器元素上特别注册的处理程序有机会在将事件传递到实际目标之前拦截(或“捕获”)事件。事件冒泡和捕获在§15.2.4中有详细说明。

    有些事件具有与它们关联的默认操作。例如,当超链接上发生单击事件时,默认操作是浏览器跟随链接并加载新页面。事件处理程序可以通过调用事件对象的方法来防止此默认操作。这有时被称为“取消”事件,并在§15.2.5中进行了说明。

    15.2.1 事件类别

    客户端JavaScript支持大量的事件类型,本章无法涵盖所有这些类型。不过,将事件分组到一些常规类别中,以说明支持的事件的范围和广泛的多样性是很有用的:

    设备相关输入事件

    • 这些事件直接绑定到特定的输入设备,如鼠标或键盘。它们包括诸如“mousedown”、“mousemove”、“mouseup”、“touchstart”、“touchmove”、“touchend”、“keydown”和“keyup”等事件类型。

    设备无关输入事件

    • 这些输入事件不直接绑定到特定的输入设备。例如,“click”事件表示链接或按钮(或其他文档元素)已激活。这通常是通过鼠标点击来完成的,但也可以通过键盘或(在触摸敏感设备上)点击来完成。“input”事件是“keydown”事件的一个独立于设备的替代项,它支持键盘输入以及诸如剪切粘贴和用于象形文字的输入方法等替代方法。“pointerdown”、“pointermove”和“pointerup”事件类型是与设备无关的鼠标和触摸事件的替代品。它们适用于鼠标型指针、触摸屏以及笔式或手写笔式输入。

    用户界面事件

    • UI事件是更高级别的事件,通常在HTML表单元素上,这些元素定义web应用程序的用户界面。它们包括“focus”事件(当文本输入字段获得键盘焦点时)、“change”事件(当用户更改表单元素显示的值时)和“submit”事件(当用户单击表单中的提交按钮时)。

    状态更改事件

    • 有些事件不是由用户活动直接触发的,而是由网络或浏览器活动触发的,它们表示某种生命周期或状态相关的变化。在文档加载结束时,分别对窗口和文档对象触发的“load”和“DOMContentLoaded”事件可能是这些事件中最常用的(参见“客户端JavaScript时间轴”)。当网络连接发生变化时,浏览器在窗口对象上触发“online”和“offline”事件。浏览器的历史管理机制(§15.10.4)触发“popstate”事件以响应浏览器的后退按钮。

    API特定事件

    • 许多由HTML和相关规范定义的web API包括它们自己的事件类型。HTML<video>和<audio>元素定义了一长串相关事件类型,如“waiting”、“playing”、“seeking”、“volumechange”等等,您可以使用它们自定义媒体播放。一般来说,异步的web平台API是在向JavaScript添加Promise之前开发的,它们基于事件并定义API特定的事件。例如,IndexedDB API(§15.12.3)在数据库请求成功或失败时触发“success”和“error”事件。尽管用于发出HTTP请求的新fetch() API(§15.11.1)是基于Promise的,但是它所替代的XMLHttpRequest API定义了许多特定于API的事件类型。

    15.2.2 注册事件处理程序

    注册事件处理程序有两种基本方法。第一种,从web早期开始,是在作为事件目标的对象或文档元素上设置一个属性。第二种(更新和更通用的)技术是将处理程序传递给对象或元素的addEventListener()方法。

    设置目标对象的事件处理程序属性

    注册事件处理程序的最简单方法是将事件目标的属性设置为所需的事件处理程序函数。按照惯例,事件处理程序属性的名称由单词“on”组成,后跟事件名称:onclick、onchange、onload、onmouseover等等。请注意,这些属性名称区分大小写,并且全部用小写字母书写3,即使事件类型(如“mousedown”)由多个单词组成。以下代码包括两个此类事件处理程序注册:

    // 将Window对象的onload属性设置为函数。
    // 这个函数是事件处理程序:它在文档加载时被调用。
    window.onload = function () {
        // 查找<form>元素
        let form = document.querySelector("form#shipping");
        // 在表单上注册事件处理程序函数,在提交表单之前将调用该函数。
        // 假设isFormValid()在其他地方定义。
        form.onsubmit = function (event) { // 当用户提交表单时
            if (!isFormValid(this)) { // 检查表单输入是否有效
                event.preventDefault(); // 如果无效,就阻止表单提交。
            }
        };
    };
    

    事件处理程序属性的缺点是,它们的设计是基于这样一个假设:事件目标对于每种类型的事件最多只能有一个处理程序。使用addEventListener()注册事件处理程序通常更好,因为该技术不会覆盖任何以前注册的处理程序。

    设置HTML标签的事件处理程序属性

    文档元素的事件处理程序属性也可以直接在HTML文件中定义为相应HTML标签上的属性。(用JavaScript在Window元素上注册的处理程序可以用HTML中的<body>标签上的属性来定义)这种技术在现代web开发中通常是不受欢迎的,但是它是可能的,本文将其记录在这里,因为您仍然可以在现有代码中看到它。

    将事件处理程序定义为HTML属性时,属性值应为JavaScript代码的字符串。该代码应该是事件处理程序函数的主体,而不是完整的函数声明。也就是说,您的HTML事件处理程序代码不应该用大括号括起来并以function关键字作为前缀。例如:

    <button onclick="console.log('Thank you');">Please Click</button>
    

    如果一个HTML事件处理程序属性包含多个JavaScript语句,则必须记住用分号分隔这些语句,或者将属性值分隔多行。

    当您指定一个JavaScript代码字符串作为HTML事件处理程序属性的值时,浏览器会将字符串转换为一个函数,其工作方式如下:

    function(event) {
        with (document) {
            with (this.form || {}) {
                with (this) {
                    /* 你的代码在这里 */
                }
            }
        }
    }
    

    event参数表示处理程序代码可以将当前事件对象作为event引用。with语句意味着处理程序的代码可以直接引用目标对象、包含<form>和包含文档对象的属性,就像它们是作用域中的变量一样。在严格模式下禁止使用with语句(§5.6.3),但是HTML属性中的JavaScript代码从不严格。以这种方式定义的事件处理程序在定义了意外变量的环境中执行。这可能是令人困惑的bug的来源,也是避免用HTML编写事件处理程序的一个很好的理由。

    addEventListener()

    任何可以作为事件目标的对象(包括窗口和文档对象)以及所有文档元素都定义了一个名为addEventListener()的方法,您可以使用该方法为该目标注册事件处理程序。addEventListener()接受三个参数。第一个是为其注册处理程序的事件类型。事件类型(或名称)是一个字符串,不包括设置事件处理程序属性时使用的“on”前缀。addEventListener()的第二个参数是在发生指定类型的事件时应调用的函数。第三个参数是可选的,将在下面解释。

    下面的代码为<button>元素上的“click”事件注册了两个处理程序。注意使用的两种技术之间的差异:

    <button id="mybutton">Click me</button>
    <script>
    let b = document.querySelector("#mybutton");
    b.onclick = function() { console.log("Thanks for clicking me!"); };
    b.addEventListener("click", () => { console.log("Thanks again!"); });
    </script>
    

    以“click”作为第一个参数调用addEventListener()不会影响onclick属性的值。在这段代码中,单击一个按钮将两条消息记录到开发人员控制台。如果我们先调用addEventListener()然后设置onclick,我们仍然会以相反的顺序记录两条消息。更重要的是,可以多次调用addEventListener()为同一对象上的同一事件类型注册多个处理程序函数。当一个事件发生在一个对象上时,为该类型事件注册的所有处理程序都将按注册顺序调用。对具有相同参数的同一对象多次调用addEventListener()没有任何影响,处理程序函数只保留注册一次,重复调用不会改变调用处理程序的顺序。

    addEventListener()与removeEventListener()方法成对出现,该方法需要相同的两个参数(加上可选的第三个参数),但从对象中移除事件处理程序函数,而不是添加它。临时注册一个事件处理程序,然后很快将其删除,这通常很有用。例如,当您得到一个“mousedown”事件时,您可以为“mousemove”和“mouseup”事件注册临时事件处理程序,这样您就可以看到用户是否拖动了鼠标。然后在“mouseup”事件到达时注销这些处理程序。在这种情况下,事件处理程序移除代码可能如下所示:

    document.removeEventListener("mousemove", handleMouseMove);
    document.removeEventListener("mouseup", handleMouseUp);
    

    addEventListener()的第三个可选参数是布尔值或对象。如果传递true,则处理程序函数将注册为捕获事件处理程序,并在事件分派的不同阶段调用。我们将在§15.2.4中介绍事件捕获。如果在注册事件侦听器时传递第三个参数true,则如果要移除处理程序,则还必须将true作为第三个参数传递给removeEventListener()。

    注册捕获事件处理程序只是addEventListener()支持的三个选项之一,您也可以传递一个显式指定所需选项的对象,而不是传递单个布尔值:

    document.addEventListener("click", handleClick, {
    	capture: true,
    	once: true,
    	passive: true
    });
    

    如果Options对象的capture属性设置为true,则事件处理程序将注册为捕获处理程序。如果该属性为false或被省略,则处理程序将不捕获。

    如果Options对象的once属性设置为true,那么事件侦听器将在触发一次后自动删除。如果此属性为false或被省略,则不会自动删除处理程序。

    如果Options对象的passive属性设置为true,则表示事件处理程序永远不会调用preventDefault()来取消默认操作(请参见§15.2.5)。这对于移动设备上的触摸事件尤其重要,如果用于“touchmove”事件的事件处理程序可以阻止浏览器的默认滚动操作,则浏览器无法实现平滑滚动。这个passive属性提供了一种注册这种类型的潜在破坏性事件处理程序的方法,但是它让web浏览器知道它可以在事件处理程序运行时安全地开始它的默认行为,例如滚动。平滑的滚动对于一个好的用户体验非常重要,以至于Firefox和Chrome在默认情况下会使“touchmove”和“mousewheel”事件变为passive。因此,如果您真的想注册一个为这些事件之一调用preventDefault()的处理程序,那么应该显式地将passive属性设置为false。

    也可以将Options对象传递给removeEventListener(),但只有capture属性相关。删除侦听器时不需要指定once或passive,这些属性将被忽略。

    15.2.3 事件处理程序调用

    注册事件处理程序后,当指定对象上发生指定类型的事件时,web浏览器将自动调用它。本节详细描述事件处理程序调用,解释事件处理程序参数、调用上下文(this值)和事件处理程序返回值的含义。

    事件处理程序参数

    事件处理程序以事件对象作为其单个参数来调用。事件对象的属性提供有关事件的详细信息:

    type

    • 发生的事件的类型。

    target

    • 发生事件的对象。

    currentTarget

    • 对于传播的事件,此属性是注册当前事件处理程序的对象。

    timeStamp

    • 表示事件发生时间但不代表绝对时间的时间戳(以毫秒为单位)。您可以通过从第二个事件的时间戳中减去第一个事件的时间戳来确定两个事件之间经过的时间。

    isTrusted

    • 如果事件是由web浏览器本身调度的,则此属性为true;如果事件是由JavaScript代码调度的,则此属性为false。

    特定类型的事件具有附加属性。例如,鼠标和指针事件具有clientX和clientY属性,它们指定事件发生的窗口坐标。

    事件处理程序上下文

    通过设置属性注册事件处理程序时,看起来就像是在目标对象上定义新方法:

    target.onclick = function() { /* 处理程序代码 */ };
    

    因此,将事件处理程序作为定义它们的对象的方法来调用并不奇怪。也就是说,在事件处理程序的主体中,this关键字引用注册事件处理程序的对象。

    即使使用addEventListener()注册处理程序,也会将目标作为其this值来调用。但是,对于定义为箭头函数的处理程序,这不起作用:箭头函数的this值始终与定义它们的作用域相同。

    处理程序返回值

    在现代JavaScript中,事件处理程序不应该返回任何内容。您可能会看到在旧代码中返回值的事件处理程序,并且返回值通常是向浏览器发出的信号,指示它不应执行与事件关联的默认操作。例如,如果表单中提交按钮的onclick处理程序返回false,则web浏览器将不提交表单(通常是因为事件处理程序确定用户的输入未通过客户端验证)。

    阻止浏览器执行默认操作的标准和首选方法是对事件对象调用preventDefault()方法(§15.2.5)。

    调用顺序

    一个事件目标可以为特定类型的事件注册多个事件处理程序。当该类型的事件发生时,浏览器将按注册顺序调用所有处理程序。有趣的是,即使您混合使用addEventListener()注册的事件处理程序和在对象属性(如onclick)上注册的事件处理程序,也是如此。

    15.2.4 事件传播

    当事件的目标是窗口对象或其他独立对象时,浏览器只需调用该对象上的适当处理程序即可响应该事件。然而,当事件目标是文档或文档元素时,情况会更复杂。

    在调用在目标元素上注册的事件处理程序之后,大多数事件都会在DOM树上“冒泡”。将调用目标父级的事件处理程序。然后调用在目标的祖父母上注册的处理程序。这将一直持续到Document对象,然后再延伸到Window对象。事件冒泡提供了一种替代方法,不需要在许多单独的文档元素上注册处理程序:相反,您可以在一个公共祖先元素上注册一个处理程序并在那里处理事件。例如,您可以在<form>元素上注册“change”处理程序,而不是为表单中的每个元素注册“change”处理程序。

    文档元素上发生的大多数事件都会冒泡。值得注意的例外是“focus”、“blur”和“scroll”事件。文档元素上的“load”事件会冒泡,但它在文档对象处停止冒泡,并且不会传播到窗口对象。(窗口对象的“load”事件处理程序仅在整个文档已加载时触发。)

    事件冒泡是事件传播的第三个“阶段”。对目标对象本身的事件处理程序的调用是第二个阶段。第一个阶段甚至在调用目标处理程序之前发生,称为“捕获”阶段。回想一下addEventListener()接受可选的第三个参数。如果这个参数是true,或者{capture:true},则事件处理程序注册为捕获事件处理程序,以便在事件传播的第一阶段进行调用。事件传播的捕获阶段与冒泡阶段相反。首先调用窗口对象的捕获处理程序,然后调用文档对象的捕获处理程序,然后调用主体对象的捕获处理程序,依此类推,直到事件目标的父级的捕获事件处理程序被调用为止。不会调用在事件目标本身上注册的捕获事件处理程序。

    事件捕获提供了一个在事件传递到目标之前查看事件的机会。捕获事件处理程序可以用于调试,也可以与下一节中描述的事件取消技术一起使用,以筛选事件,从而永远不会实际调用目标事件处理程序。事件捕获的一个常见用途是处理鼠标拖动,其中鼠标运动事件需要由被拖动的对象处理,而不是由拖动对象所在的文档元素来处理。

    15.2.5 事件取消

    浏览器响应许多用户事件,即使您的代码没有响应:当用户在超链接上单击鼠标时,浏览器会跟随链接。如果HTML文本输入元素具有键盘焦点并且用户键入键,浏览器将输入用户的输入。如果用户在触摸屏设备上移动手指,浏览器将滚动。如果为此类事件注册事件处理程序,则可以通过调用事件对象的preventDefault()方法阻止浏览器执行其默认操作。(除非使用passive选项注册了处理程序,这会使preventDefault()无效。)

    取消与事件关联的默认操作只是事件取消的一种。我们还可以通过调用事件对象的stopPropagation()方法来取消事件的传播。如果在同一对象上定义了其他处理程序,则仍将调用其余处理程序,但在调用stopPropagation()之后,不会调用任何其他对象上的事件处理程序。stopPropagation()在捕获阶段、事件目标本身和冒泡阶段工作。stopImmediatePropagation()的工作原理与stopPropagation()类似,但它还会阻止调用在同一对象上注册的任何后续事件处理程序。

    15.2.6 分发自定义事件

    客户端JavaScript的事件API是一个相对强大的API,您可以使用它来定义和分发自己的事件。例如,假设您的程序周期性地需要执行长时间的计算或发出网络请求,并且当此操作处于挂起状态时,其他操作是不可能的。您希望通过显示“旋转器”来指示应用程序正忙,从而让用户知道这一点。但是繁忙的模块不需要知道旋转器应该显示在哪里。相反,该模块可能只是分发一个事件来宣布它正忙,然后在它不再忙时分发另一个事件。然后,UI模块可以为这些事件注册事件处理程序,并采取任何适当的UI操作来通知用户。

    如果JavaScript对象有addEventListener()方法,那么它就是一个“事件目标”,这意味着它还有一个dispatchEvent()方法。您可以使用CustomEvent()构造函数创建自己的事件对象,并将其传递给dispatchEvent()。CustomEvent()的第一个参数是指定事件类型的字符串,第二个参数是指定事件对象属性的对象。将此对象的detail属性设置为表示事件内容的字符串、对象或其他值。如果计划在文档元素上分发事件并希望它在文档树中冒泡,请在第二个参数中添加 bubbles:true:

    // 分发一个自定义事件,以便UI知道我们很忙
    document.dispatchEvent(new CustomEvent("busy", { detail: true }));
    
    // 执行网络操作
    fetch(url)
        .then(handleNetworkResponse)
        .catch(handleNetworkError)
        .finally(() => {
            // 在网络请求成功或失败后,分发另一个事件让UI知道我们不再忙了。
            document.dispatchEvent(new CustomEvent("busy", { detail: false }));
        });
    
    // 在其他地方,你可以在程序中注册一个“busy”事件的处理程序,
    // 并用它来显示或隐藏旋转器,让用户知道。
    document.addEventListener("busy", (e) => {
        if (e.detail) {
            showSpinner();
        } else {
            hideSpinner();
        }
    });
    

    15.3 编写文档脚本

    客户端JavaScript用于将静态HTML文档转换为交互式web应用程序。因此,编写网页内容的脚本实际上是JavaScript的核心目的。

    每个窗口对象都有一个引用文档对象的Document属性。Document对象表示窗口的内容,它是本节的主题。但是,Document对象并不是独立的。它是DOM中用于表示和操作文档内容的中心对象。

    DOM在§15.1.2中引入。本节将详细解释API。它包括:

    • 如何从文档中查询或选择单个元素。
    • 如何遍历文档,以及如何查找任何文档元素的祖先、兄弟姐妹和后代。
    • 如何查询和设置文档元素的属性。
    • 如何查询、设置和修改文档内容。
    • 如何通过创建、插入和删除节点来修改文档结构。

    15.3.1 选择文档元素

    客户端JavaScript程序通常需要操作文档中的一个或多个元素。全局document属性引用Document对象,Document对象具有head和body属性,分别引用<head>和<body>标签的Element对象。但是,如果一个程序想要操作嵌入在文档中更深层的元素,则必须以某种方式获取或选择引用这些文档元素的Element对象。

    使用CSS选择器选择元素

    CSS样式表有一种非常强大的语法,称为选择器,用于描述文档中的元素或元素集。DOM方法querySelector()和querySelectorAll()允许我们在文档中查找与指定CSS选择器匹配的一个或多个元素。在介绍这些方法之前,我们将从一个关于CSS选择器语法的快速教程开始。

    CSS选择器可以通过标签名、id属性的值或class属性中的单词来描述元素:

    div // <div>元素
    #nav // id=“nav”的元素
    .warning // class属性中包含“warning”的任何元素
    

    #字符用于根据id属性进行匹配,并且.字符用于基于class属性进行匹配。也可以根据更一般的属性值选择元素:

    p[lang="fr"] // 法语段落:<p lang=“fr”>
    *[name="x"] // 任何具有name=“x”属性的元素
    

    请注意,这些示例将标签名选择器(或标签名通配符 * )与属性选择器组合在一起。也可以采用更复杂的组合:

    span.fatal.error // 任何class中有"fatal""error"的<span>
    span[lang="fr"].warning // 任何<span>,法语,class中有"warning"
    

    选择器还可以指定文档结构:

    #log span // id=“log”的元素后代中的任何<span>
    #log>span // id=“log”的元素子结点中的任何<span>
    body>h1:first-child // <body>的第一个<h1>子结点
    img + p.caption // 紧接在<img>之后的class属性中有"caption"的<p>元素
    h2 ~ p // 任何跟在<h2>之后并且是其兄弟的<p>
    

    如果两个选择器之间用逗号分隔,则表示我们选择了与其中任一个选择器匹配的元素:

    button, input[type="button"] // 所有 <button> 和 <input type="button"> 元素
    

    如您所见,CSS选择器允许我们按类型、ID、类、属性和文档中的位置引用文档中的元素。querySelector()方法以CSS选择器字符串为参数,返回它在文档中找到的第一个匹配元素,如果没有匹配,则返回null:

    // 找到属性id=“spinner”的HTML标签的文档元素
    let spinner = document.querySelector("#spinner");
    

    querySelectorAll()类似,但它返回文档中所有匹配的元素,而不仅仅返回第一个元素:

    // 查找<h1>、<h2>和<h3>标签的所有元素对象
    let titles = document.querySelectorAll("h1, h2, h3");
    

    querySelectorAll()的返回值不是元素对象的数组。相反,它是一个类似数组的对象,称为NodeList。NodeList对象有一个length属性,可以像数组一样被索引,所以可以用传统的for循环遍历它们。NodeList也是可迭代的,因此也可以将它们用于for/of循环。如果要将NodeList转换为真正的数组,只需将其传递给Array.from()。

    如果文档中没有与指定选择器匹配的元素,则querySelectorAll()返回的NodeList的length属性将设置为0。

    querySelector()和querySelectorAll()由Element类和Document类实现。当对元素调用时,这些方法将只返回该元素的后代元素。

    注意CSS定义了::first-line和::first-letter伪元素。在CSS中,这些匹配部分是文本节点而不是实际元素。如果与querySelectorAll()或querySelector()一起使用,则它们将不匹配。另外,许多浏览器会拒绝返回:link和:visited伪类的匹配项,因为这可能会暴露用户的浏览历史信息。

    另一个基于CSS的元素选择方法是closest()。此方法由Element类定义,并将选择器作为其唯一参数。如果选择器与调用它的元素匹配,它将返回该元素。否则,它返回选择器匹配的最近的祖先元素,如果没有匹配则返回null。在某种意义上,closest()与querySelector()相反:closest()从一个元素开始并在树中查找该元素上方的匹配项,而querySelector()则从一个元素开始并在树中查找该元素下方的匹配项。当您在文档树的高层注册了事件处理程序时,closest()非常有用。例如,如果您正在处理一个“click”事件,您可能想知道它是否是一个点击了超链接的事件。event对象将告诉您目标是什么,但目标可能是链接中的文本,而不是超链接的<a>标签本身。事件处理程序可以像这样查找最近的包含超链接:

    // 查找最近的包含href属性的<a>标签。
    let hyperlink = event.target.closest("a[href]");
    

    下面是另一种使用closest()的方法:

    // 如果元素e在HTML列表元素内,则返回true
    function insideList(e) {
    	return e.closest("ul,ol,dl") !== null;
    }
    

    相关方法matches()不返回祖先或后代:它只测试元素是否与CSS选择器匹配,如果匹配,则返回true,否则返回false:

    // 如果e是HTML标题元素,则返回true
    function isHeading(e) {
    	return e.matches("h1,h2,h3,h4,h5,h6");
    }
    

    其他元素选择方法

    除了querySelector()和querySelectorAll()之外,DOM还定义了许多现在或多或少已经过时的旧元素选择方法。您可能仍然会看到其中一些方法(尤其是getElementById())正在使用中,但是:

    // 按id查找元素。参数只是id,没有CSS选择器前缀#。
    // 类似document.querySelector("#sect1")
    let sect1 = document.getElementById("sect1");
    
    // 查找具有name=“color”属性的所有元素(如表单复选框)。
    // 类似document.querySelectorAll('*[name="color"]');
    let colors = document.getElementsByName("color");
    
    // 在文档中查找所有<h1>元素。
    // 类似于document.querySelectorAll("h1")
    let headings = document.getElementsByTagName("h1");
    
    // getElementsByTagName()也在元素上定义。
    // 获取sect1元素中的所有<h2>元素。
    let subheads = sect1.getElementsByTagName("h2");
    
    // 查找所有具有类“tooltip”的元素
    // 类似于document.querySelectorAll(".tooltip")
    let tooltips = document.getElementsByClassName("tooltip");
    
    // 查找所有具有类“侧边栏”的sect1的后代
    // 类似于sect1.querySelectorAll(".sidebar")
    let sidebars = sect1.getElementsByClassName("sidebar");
    

    与querySelectorAll()一样,此代码中的方法返回一个NodeList(getElementById()除外,它返回一个元素对象)。但是,与querySelectorAll()不同,这些旧的选择方法返回的NodeList是“动态的”,这意味着如果文档内容或结构发生更改,列表的长度和内容可能会更改。

    预选元素

    由于历史原因,Document类定义了访问某些类型节点的快捷属性。例如,images、forms和links属性可以方便地访问文档的<img>、<form>和<a>元素(但仅限于具有href属性的<a>标签)。这些属性引用HTMLCollection对象,它们非常类似于NodeList对象,但是它们还可以通过元素ID或名称进行索引。例如,使用document.forms属性,您可以访问<form id=“address”>标签:

    document.forms.address;
    

    一个更过时的用于选择元素的API是document.all属性,它类似于文档中所有元素的HTMLCollection。document.all已弃用,您不应再使用它。

    15.3.2 文档结构和遍历

    一旦从文档中选择了一个元素,您有时需要找到文档结构上相关的部分(父结点、兄弟结点、孩子节点)。当我们主要关注文档的元素而不是其中的文本(以及它们之间的空白也是文本)时,有一个遍历API允许我们将文档视为元素对象的树,而忽略同时也是文档一部分的文本节点。此遍历API不涉及任何方法;它只是元素对象的一组属性,允许我们引用给定元素的父结点、兄弟结点和孩子结点:

    parentNode

    • 元素的此属性引用元素的父结点,它是另一个元素或文档对象。

    children

    • 此NodeList包含元素的子元素结点,但不包括文本节点(和注释节点)等非元素子结点。

    childElementCount

    • 子元素结点的数目。返回与children.length相同的值。

    firstElementChild, lastElementChild

    • 这些属性引用元素的第一个子元素和最后一个子元素。如果元素没有子元素,则它们为null。

    nextElementSibling, previousElementSibling

    • 这些属性引用紧靠在元素之前或之后的同级元素,如果没有此类同级元素,则为null。

    使用这些元素属性,可以使用以下表达式之一引用文档第一个子元素的第二个子元素:

    document.children[0].children[1]
    document.firstElementChild.firstElementChild.nextElementSibling
    

    (在标准HTML文档中,这两个表达式都引用文档的<body>标签。)

    以下两个函数演示如何使用这些属性递归地对文档元素执行深度优先遍历,并且每个元素调用指定函数:

    // 递归地遍历文档或元素e,对e及其每个后代调用函数f
    function traverse(e, f) {
    	f(e); // 对e调用f()
    	for(let child of e.children) { // 对子结点进行迭代
    		traverse(child, f); // 对每一个进行递归
    	}
    }
    
    function traverse2(e, f) {
    	f(e); // 对e调用f()
    	let child = e.firstElementChild; // 按链表形式进行遍历
    	while(child !== null) {
    		traverse2(child, f); // 递归
    		child = child.nextElementSibling;
    	}
    }
    

    作为节点树的文档

    如果要遍历文档或文档的某个部分而不想忽略文本节点,则可以使用在所有节点对象上定义的不同属性集。这将允许您查看元素、文本节点甚至注释节点(它们表示文档中的HTML注释)。

    所有节点对象都定义以下属性:

    parentNode

    • 此节点的父节点,或者对于没有父节点的Document对象这样的节点为null。

    childNodes

    • 一个只读节点列表,包含节点的所有子节点(不仅仅是元素子节点)。

    firstChild, lastChild

    • 节点的第一个子节点和最后一个子节点,如果节点没有子节点,则为null。

    nextSibling, previousSibling

    • 节点的下一个和上一个同级节点。这些属性连接双链接列表中的节点。

    nodeType

    • 一个指定节点类型的数字。文档节点的值为9。元素节点的值为1。文本节点的值为3。注释节点的值为8。

    nodeValue

    • 文本或注释节点的文本内容。

    nodeName

    • 元素的HTML标签名,转换为大写。

    使用这些节点属性,可以使用如下表达式引用文档第一个子节点的第二个子节点:

    document.childNodes[0].childNodes[1]
    document.firstChild.firstChild.nextSibling
    

    假设所讨论的文档如下:

    <html><head><title>Test</title></head><body>Hello World!</body></html>
    

    第一个子结点的第二个子结点是<body>元素。它的nodeType为1,nodeName为“BODY”。

    但是请注意,这个API对文档文本的变化非常敏感。例如,如果通过在<html>和<head>标签之间插入一个换行符来修改文档,则表示换行符的文本节点将成为第一个子节点的第一个子节点,第二个子节点是<head>元素而不是<body>元素。

    为了演示这种基于节点的遍历API,下面是一个返回元素或文档中所有文本的函数:

    // 返回元素e的纯文本内容,递归到子元素中。
    // 此方法的工作方式与textContent属性类似
    function textContent(e) {
        let s = ""; // 这里的文本进行累加
        for (let child = e.firstChild; child !== null; child = child.nextSibling) {
            let type = child.nodeType;
            if (type === 3) { // 如果是文本节点
                s += child.nodeValue; // 将文本内容添加到字符串中。
            } else if (type === 1) { // 如果是元素节点
                s += textContent(child); // 那么递归。
            }
        }
        return s;
    }
    

    这个函数只是一个演示,实际上,您只需编写e.textContent就可以获得e元素的文本内容。

    15.3.3 属性

    HTML元素由一个标签名和一组名为属性的名称/值对组成。例如,定义超链接的<a>元素使用其href属性的值作为链接的目标。

    Element类定义了用于查询、设置、测试和删除元素属性的常规getAttribute()、setAttribute()、hasAttribute()和removeAttribute()方法。但是HTML元素的属性值(对于标准HTML元素的所有标准属性)可以作为表示这些元素的HTMLElement对象的属性使用,并且通常将它们作为JavaScript属性使用比调用getAttribute()和相关方法要容易得多。

    HTML属性作为元素属性

    表示HTML文档元素的Element对象通常定义映射元素的HTML属性的读/写属性。元素定义通用HTML属性的属性,如id、title、lang和dir,以及事件处理程序属性(如onclick)。元素特定的子类型定义特定于这些元素的属性。例如,要查询图像的URL,可以使用表示<img>元素的HTMLElement的src属性:

    let image = document.querySelector("#main_image");
    let url = image.src; // src属性是图像的URL
    image.id === "main_image" // => true; 我们按id查询图像
    

    类似地,您可以使用如下代码设置<form>元素的表单提交属性:

    let f = document.querySelector("form"); // 文档中的第一个<form>元素
    f.action = "https://www.example.com/submit"; // 设置要提交到的URL。
    f.method = "POST"; // 设置HTTP请求类型。
    

    对于某些元素,例如<input>元素,一些HTML属性名映射到不同名称的属性。例如,<input>的HTML value属性由JavaScript defaultValue属性映射。<input>元素的JavaScript value属性包含用户的当前输入,但是对value属性的更改不会影响defaultValue属性和HTML的value属性。

    HTML属性不区分大小写,但JavaScript属性名区分大小写。要将属性名转换为JavaScript属性,请使用小写形式。但是,如果属性的长度超过一个单词,则将每个单词的第一个字母放在第一个大写字母之后:例如defaultChecked和tabIndex。但是,像onclick这样的事件处理程序属性是一个例外,并且是用小写字母编写的。

    一些HTML属性名是JavaScript中的保留字。对于这些,一般规则是在属性名前面加上“html”。例如,HTML for属性(属于<label>元素)成为JavaScript htmlFor属性。“class”是JavaScript中的保留字,非常重要的HTML class属性是此规则的一个例外:它在JavaScript代码中变成了className。

    表示HTML属性的属性通常具有字符串值。但是当属性是布尔值或数值(例如<input>元素的defaultChecked和maxLength属性)时,属性是布尔值或数字而不是字符串。事件处理程序属性的值始终是函数(或null)。

    请注意,此用于获取和设置属性值的基于属性的API没有定义从元素中移除属性的任何方法。尤其是,delete运算符不能用于此目的。如果需要删除属性,请使用removeAttribute()方法。

    class属性

    HTML元素的class属性是一个特别重要的属性。它的值是一个以空格分隔的CSS类列表,这些CSS类应用于元素并影响如何使用CSS设置样式。因为class是JavaScript中的保留字,所以这个属性的值可以通过Element对象的className属性获得。className属性可以设置并以字符串形式返回class属性的值。但是class属性的名称不好:它的值是一个CSS类的列表,而不是一个类,在客户端JavaScript编程中,通常希望在该列表中添加或删除单个类名,而不是将列表作为单个字符串处理。

    因此,元素对象定义了一个classList属性,该属性允许您将class属性视为列表。classList属性的值是可迭代的类数组对象。尽管属性的名称是classList,但它的行为更像一组类,并定义add()、remove()、contains()和toggle()方法:

    // 当我们想让用户知道我们很忙时,我们会显示一个旋转器。
    // 为此,我们必须删除“hidden”类并添加“animated”类(假设样式表配置正确)。
    let spinner = document.querySelector("#spinner");
    spinner.classList.remove("hidden");
    spinner.classList.add("animated");
    

    数据集属性

    将附加信息附加到HTML元素有时很有用,通常JavaScript代码将选择这些元素并以某种方式操作它们。在HTML中,任何名称为小写并以前缀“data-”开头的属性都被认为是有效的,您可以将它们用于任何目的。这些“数据集属性”不会影响它们出现的元素的表示,它们定义了一种标准的方法来附加额外的数据,而不会影响文档的有效性。

    在DOM中,元素对象有一个dataset属性,该属性引用一个对象,该对象的属性与去掉前缀的数据属性相对应。因此,dataset.x将保存data-x属性的值。用连字符连接的属性映射到驼峰风格的属性名称:属性data-section-number成为属性dataset.sectionNumber。

    假设HTML文档包含以下文本:

    <h2 id="title" data-section-number="16.1">Attributes</h2>
    

    然后您可以编写这样的JavaScript来访问该分区号:

    let number = document.querySelector("#title").dataset.sectionNumber;
    

    15.3.4 元素内容

    再看看图15-1所示的文档树,问问自己<p>元素的“内容”是什么。有两种方法可以回答这个问题:

    • 内容是HTML字符串“This is a simple document”。
    • 内容是纯文本字符串“This is a simple document”。

    这两个答案都是有效的,而且每个答案都有自己的用处。接下来的部分将解释如何使用元素内容的HTML表示和纯文本表示。

    元素内容为HTML

    读取元素的innerHTML属性将返回该元素的内容作为标记字符串。在元素上设置此属性将调用web浏览器的解析器,并将元素的当前内容替换为新字符串的解析表示形式。您可以通过打开开发人员控制台并键入以下命令来进行测试:

    document.body.innerHTML = "<h1>Oops</h1>";
    

    你会看到整个网页消失了,取而代之的是一个标题“Oops”。Web浏览器非常擅长解析HTML,而设置innerHTML通常相当高效。但是,请注意,使用+=运算符将文本附加到innerHTML属性效率是比较低的,因为它既需要序列化步骤将元素内容转换为字符串,又需要解析步骤将新字符串转换回元素内容。

    在使用这些HTML API时,不要在文档中插入用户输入,这一点非常重要。如果这样做,就允许恶意用户将自己的脚本注入到应用程序中。有关详细信息,请参阅第425页的“跨站点脚本”。

    元素的outerHTML属性与innerHTML类似,只是其值包括元素本身。查询outerHTML时,该值包括元素的开始和结束标记。在元素上设置outerHTML时,新内容将替换元素本身。

    一个相关的元素方法是insertAdjacentHTML(),它允许您在指定元素附近插入任意HTML标记字符串。标记作为第二个参数传递给这个方法,“相邻”的确切含义取决于第一个参数的值。第一个参数应该是一个字符串,其中一个值是“beforebegin”、“afterbegin”、“beforeend”或“afterend”。这些值对应于图15-2所示的插入点。

    在这里插入图片描述
    图15-2. insertAdjacentHTML()的插入点

    纯文本形式的元素内容

    有时,您希望以纯文本的形式查询元素的内容,或者将纯文本插入文档(而不必转义HTML标记中使用的尖括号和&号)。标准的方法是使用textContent属性:

    let para = document.querySelector("p"); // 文件中的第一个<p>元素
    let text = para.textContent; // 获取段落内容
    para.textContent = "Hello World!"; // 修改这段文字
    

    textContent属性由Node类定义,因此它适用于文本节点和元素节点。对于元素节点,它查找并返回元素所有后代中的所有文本。

    Element类定义了一个与textContent类似的innerText属性。innerText有一些异常和复杂的行为,比如试图保留表格格式。但是,它没有正规地规范,也没有在浏览器之间兼容地实现,因此不应该再使用它。

    <script>元素中的文本
    内嵌代码的<script>元素(即那些没有src属性的元素)有一个text属性,可以用来检索它们的文本。浏览器从不显示<script>元素的内容,HTML解析器忽略脚本中的尖括号和&号。这使得<script>元素成为嵌入任意文本数据以供应用程序使用的理想位置。只需将元素的type属性设置为某个值(例如“text/x-custom-data”),以明确说明脚本不是可执行的JavaScript代码。如果您这样做,JavaScript解释器将忽略该脚本,但元素将存在于文档树中,其text属性将向您返回数据。

    15.3.5 创建、插入和删除节点

    我们已经了解了如何使用HTML和纯文本字符串查询和更改文档内容。我们还看到,我们可以遍历一个文档来检查由它组成的单个元素和文本节点。也可以在单个节点级别更改文档。Document类定义了用于创建元素对象的方法,而Element和Text对象具有用于插入、删除和替换树中节点的方法。

    使用Document类的createElement()方法创建一个新元素,并使用其append()和prepend()方法将文本字符串或其他元素附加到其中:

    let paragraph = document.createElement("p"); // 创建一个空的<p>元素
    let emphasis = document.createElement("em"); // 创建一个空的<em>元素
    emphasis.append("World"); // 向<em>元素添加文本
    paragraph.append("Hello ", emphasis, "!"); // 将文本和<em>添加到<p>
    paragraph.prepend("¡"); // 在<p>开头添加更多文本
    paragraph.innerHTML // => "¡Hello <em>World</em>!"
    

    append()和prepend()接受任意数量的参数,可以是节点对象或字符串。字符串参数将自动转换为文本节点。(可以使用document.createTextNode()显式创建文本节点,但很少有理由这样做。)append()将参数添加到孩子列表元素末尾。prepend()在孩子列表的开头添加参数。

    如果要将元素或文本节点插入包含元素的孩子列表的中间,则append()或prepend()都不适用。在这种情况下,应该获取对兄弟节点的引用,并调用before()在该兄弟节点之前插入新内容,或者调用after()在该兄弟节点之后插入新内容。例如:

    // 使用class=“greetings”查找标题元素
    let greetings = document.querySelector("h2.greetings");
    
    // 现在在标题后面插入新段落和一条横线
    greetings.after(paragraph, document.createElement("hr"));
    

    与append()和prepend()一样,after()和before()接受任意数量的字符串和元素参数,并在将字符串转换为文本节点后将它们全部插入文档中。append()和prepend()只在元素对象上定义,而after()和before()同时适用于元素和文本节点:可以使用它们插入相对于文本节点的内容。

    请注意,元素只能插入文档中的一个位置。如果某个元素已经在文档中,而您将其插入到其他位置,则该元素将被移动到新位置,而不是被复制:

    // 我们在这个元素之后插入了paragraph,但是现在我们移动它,使它出现在元素之前
    greetings.before(paragraph);
    

    如果确实要复制元素,请使用cloneNode()方法,传递true以复制其所有内容:

    // 制作一个段落的副本,并将其插入greetings元素之后
    greetings.after(paragraph.cloneNode(true));
    

    可以通过调用元素或文本节点的remove()方法从文档中移除元素或文本节点,也可以通过调用replaceWith()来替换它。remove()不带参数,replaceWith()接受任意数量的字符串和元素,就像before()和after()一样:

    // 从文档中删除greetings元素并将其替换为paragraph元素
    // (如果paragraph已经插入到文档中,则将其从当前位置移动)。
    greetings.replaceWith(paragraph);
    
    // 现在删除paragraph。
    paragraph.remove();
    

    DOM API还定义了上一代用于插入和删除内容的方法。appendChild()、insertBefore()、replaceChild()和removeChild()比此处显示的方法更难使用,因此不应该需要这些方法。

    15.3.6 示例:生成目录

    例15-1展示了如何动态地为文档创建目录。它演示了前面几节中描述的许多文档脚本技术。这个例子注释得很好,您应该可以很容易地理解代码。

    例15-1. 使用DOM API生成目录

    /**
     * TOC.js: 为文档创建目录。
     *
     * 此脚本在触发DOMContentLoaded事件时运行,并自动生成文档的目录。
     * 它不定义任何全局符号,因此不应与其他脚本冲突。
     *
     * 当这个脚本运行时,它首先查找id为“TOC”的文档元素。
     * 如果没有这样的元素,它会在文档的开头创建一个元素。
     * 接下来,该函数查找所有<h2>到<h6>标记,将它们视为章节标题,
     * 并在TOC元素中创建一个目录。该函数将章节编号添加到每个章节标题,
     * 并将标题包装在命名锚中,以便TOC可以链接到它们。
     * 生成的锚点的名称以“TOC”开头,因此您应该避免在自己的HTML中使用这个前缀。
     *
     * 生成的TOC中的条目可以用CSS设置样式。所有条目都有一个类“TOCEntry”。
     * 条目也有一个与章节标题级别相对应的类。<h1>标记生成类“TOCLevel1”的条目,
     * <h2>标记生成类“TOCLevel2”的条目,依此类推。
     * 插入标题中的章节编号具有“TOCSectNum”类。
     *
     * 您可以将此脚本与以下样式表一起使用:
     *
     *   #TOC { border: solid black 1px; margin: 10px; padding: 10px; }
     *   .TOCEntry { margin: 5px 0px; }
     *   .TOCEntry a { text-decoration: none; }
     *   .TOCLevel1 { font-size: 16pt; font-weight: bold; }
     *   .TOCLevel2 { font-size: 14pt; margin-left: .25in; }
     *   .TOCLevel3 { font-size: 12pt; margin-left: .5in; }
     *   .TOCSectNum:after { content: ": "; }
     *
     * 要隐藏章节编号,请使用以下命令:
     *
     *   .TOCSectNum { display: none }
     **/
    document.addEventListener("DOMContentLoaded", () => {
        // 找到TOC容器元素。
    	// 如果没有,请在文档开头创建一个。
        let toc = document.querySelector("#TOC");
        if (!toc) {
            toc = document.createElement("div");
            toc.id = "TOC";
            document.body.prepend(toc);
        }
    
        // 查找所有章节标题元素。这里我们假设文档标题使用<h1>并且文档中的部分用<h2>到<h6>标记。
        let headings = document.querySelectorAll("h2,h3,h4,h5,h6");
    
        // 初始化一个数组来跟踪章节编号。
        let sectionNumbers = [0,0,0,0,0];
    
        // 现在遍历我们找到的章节标题元素。
        for(let heading of headings) {
            // 如果标题在TOC容器中,则跳过该标题。
            if (heading.parentNode === toc) {
                continue;
            }
    
            // 找出它是什么级别的标题。
    		// 减去1,因为<h2>是一级标题。
            let level = parseInt(heading.tagName.charAt(1)) - 1;
    
            // 增加此标题级别的章节编号,并将所有较低的标题级别编号重置为零。
            sectionNumbers[level-1]++;
            for(let i = level; i < sectionNumbers.length; i++) {
                sectionNumbers[i] = 0;
            }
    
            // 现在合并所有标题级别的章节编号,生成类似2.3.1的章节编号。
            let sectionNumber = sectionNumbers.slice(0, level).join(".");
    
            // 将章节编号添加到章节标题中。
    		// 我们把数字放在一个<span>中,使其具有样式。
            let span = document.createElement("span");
            span.className = "TOCSectNum";
            span.textContent = sectionNumber;
            heading.prepend(span);
    
            // 将标题包装在命名锚中,以便我们可以链接到它。
            let anchor = document.createElement("a");
            let fragmentName = `TOC${sectionNumber}`;
            anchor.name = fragmentName;
            heading.before(anchor);    // 在标题前插入锚
            anchor.append(heading);    // 将标题移动到锚内
    
            // 现在创建一个指向此章节的链接。
            let link = document.createElement("a");
            link.href = `#${fragmentName}`;     // 链接目标
    
            // 将标题文本复制到链接中。这是innerHTML的安全使用,
            // 因为我们没有插入任何不受信任的字符串。
            link.innerHTML = heading.innerHTML;
    
            // 将链接放在基于级别的可设置样式的div中。
            let entry = document.createElement("div");
            entry.classList.add("TOCEntry", `TOCLevel${level}`);
            entry.append(link);
    
            // 并将div添加到TOC容器中。
            toc.append(entry);
        }
    });
    

    译者注:以下部分是自己添加的
    现在我们创建一个html,来测试一下上面的js文件,先创建一个含有标题的文件toctest.html:

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>toc test</title>
    </head>
    
    <body>
        <h2>章节1</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
        <h2>章节2</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
        <h2>章节3</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
    </body>
    
    </html>
    

    显示效果如下:
    在这里插入图片描述

    现在我们把样式和js文件放入html中:

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>toc test</title>
        <style>
            #TOC {
                border: solid black 1px;
                margin: 10px;
                padding: 10px;
            }
    
            .TOCEntry {
                margin: 5px 0px;
            }
    
            .TOCEntry a {
                text-decoration: none;
            }
    
            .TOCLevel1 {
                font-size: 16pt;
                font-weight: bold;
            }
    
            .TOCLevel2 {
                font-size: 14pt;
                margin-left: .25in;
            }
    
            .TOCLevel3 {
                font-size: 12pt;
                margin-left: .5in;
            }
    
            .TOCSectNum:after {
                content: ": ";
            }
        </style>
        <script src="./TOC.js"></script>
    </head>
    
    <body>
        <h2>章节1</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
        <h2>章节2</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
        <h2>章节3</h2>
        <h3>子章节1</h3>
        <h3>子章节2</h3>
    </body>
    
    </html>
    

    再看一下效果:

    在这里插入图片描述


    1. 本书以前的版本有一个广泛的参考部分,包括JavaScript标准库和web API。它在第七版中被删除了,因为MDN已经使它过时了:今天,在MDN上查找东西比翻阅一本书要快得多,而且我以前在MDN的同事在保持在线文档的最新性方面做得比这本书更好。 ↩︎

    2. 一些源代码(包括HTML规范)根据处理程序和侦听器的注册方式在技术上对它们进行了区分。在这本书中,我们把这两个词当作同义词。 ↩︎

    3. 如果您使用React框架来创建客户端用户界面,这可能会让您大吃一惊。React对客户端事件模型做了一些小的更改,其中之一是在React中,事件处理程序属性名是用驼峰风格编写的:onClick、onMouseOver等等。然而,当以本地方式使用web平台时,事件处理程序属性完全以小写形式编写。 ↩︎

    展开全文
  • 以前都是看各种视频,感觉什么收获也没有,反而弄得脑袋混乱,希望能够按照这本书的节奏掌握javascript这门语言,为我的前端学习打下基础。 学习前准备:web浏览器(F12用来唤醒和关闭firebug界面,ctrl+shift+j...
  • 第1章 javascript概述 17 1.1 javascript语言核心 20 1.2 客户端javascript 24 第一部分 javascript 语言核心 35 第2章 词法结构 37 2.1 字符集 37 2.2 注释 39 2.3 直接量 39 2.4 标识符和保留字 ....
  • JavaScript权威指南(第6版)》要讲述的内容涵盖JavaScript语言本身,以及web浏览器所实现的JavaScript API。本书第6版涵盖了 html5 和 ecmascript 5,很多章节完全重写,增加了当今 web 开发的最佳实践的内容,新增...
  • JavaScript权威指南(第6版)》要讲述的内容涵盖JavaScript语言本身,以及web浏览器所实现的JavaScript API。本书第6版涵盖了 html5 和 ecmascript 5,很多章节完全重写,增加了当今 web 开发的最佳实践的内容,新增...
  • JavaScript 权威指南(第四版).part3.rar
  • 21.2 脚本化音频和视频 21.3 SVG:可伸缩的矢量图形 21.4 中的图形 第22章 HTML5 API 22.1 地理位置 22.2 历史记录管理 22.3 跨域消息传递 22.4 Web Worker 22.5 类型化数组和ArrayBuffer 22.6 Blob 22.7 文件系统...
  • JavaScript权威指南(第6版)》主要讲述的内容涵盖JavaScript语言本身,以及Web浏览器所实现的JavaScript API。本书第6版涵盖了HTML5和ECMAScript 5,很多章节完全重写,增加了当今Web开发的最佳实践的内容,新增...
  • 本书是程序员学习核心JavaScript语言和由Web浏览器定义的JavaScript API的指南和综合参考手册。 第6版涵盖HTML 5和ECMAScript 5。很多章节完全重写,以便与时俱进,紧跟当今的最佳Web开发实践。本书新增章节描述了...
  • 尽管在客户端提供了非常繁琐的javascript API来操作cookie,但它们难用至极,而且只适合少量的文本存储。不仅如此, 任何以cookie形式存储的数据,不论服务器端是否需要,每一次HTTP请求都要把这些数据传输到服务器...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,956
精华内容 1,182
关键字:

javascript权威指南视频

java 订阅