JavaScript 学习归纳

一、简介

参考JavaScript 教程JavaScript 参考手册,对里面内容进行了优化与总结。
JS 代码需要写在<script></script>之中,<script></script>可放在<head></head><body></body>中,或同时存在这两者中。当存在于多处时,将按顺序执行JS代码。
可从外部引入 JS,如<script src="xxx.js"></script>,但 xxx.js 中不使用<script></script>标签,而是直接写 JS 代码。
JS 对大小写是敏感的。

二、调试

  1. 警告框 alert()
    使用window.alert()弹出警告框,可简写成alert(),括号中为警告内容,如window.alert("弹框测试")

  2. 写入文档 write()
    使用document.write()将内容写入文档中。内容也可传入 html 语句,如document.write("<h1>1号标题</h1>")。可传入多个参数,用逗号隔开。
    要注意的是,若在文档加载完成后再使用该方法,内容会直接覆盖整个文档。

  3. 输出信息 log()
    使用console.log()将内容输出在控制台上,如console.log("打印在控制台")
    使用console.info()将内容输出在控制台上。
    使用console.warn()将警告输出在控制台上,警告前有个黄色三角。
    使用console.error()将错误输出在控制台上,错误前有一个红色的X。

    更多属性和方法详见 JavaScript 参考手册 -- DOM Console 对象

  4. 获取元素 getElementById()
    使用document.getElementById()通过传入的元素id来获取元素。使用元素的innerHTML属性来获取元素的内容,即<div>123</div>中的123,也可修改内容,如document.getElementById("id").innerHTML = "修改内容"

<body>
        <div id="div1">div1</div>
        <script>
            window.alert("弹框测试")
            document.write("<div>该div会插入到div1和div2之前,因为是按顺序的</div>")
            // 控制台会打印日期
            console.log(Date())
            
            // 获取id为div1的元素
            var ele = document.getElementById("div1")
            // 修改元素的内容为h1标题
            ele.innerHTML = "<h1>标题div1</h1>"
        </script>
        <div>div2</div>
    </body>
  1. 断点
    在要添加断点的代码处输入debugger。运行后,会在这个位置停止运行。
    在浏览器中按 F12 并选择 Sources 可以看到断点时的变量的值。

  2. 异常处理
    try 放入可能有异常的代码。
    catch 捕获并处理异常。
    finally 无论有无异常都会执行。
    throw 在try中使用,手动抛出异常,再由catch捕获处理。

try {
                throw "test_error"
            } catch(error) {
                document.write(error, "<br>")
            } finally {
                document.write("try catch end")
            }

若error为 Error 对象,则可使用namemessage属性,表示错误名与错误信息。
错误名有以下几种:
RangeError 数值超出规定的范围。
ReferenceError 非法引用,比如使用未定义的变量。
SyntaxError 语法错误。
TypeError 类型错误,比如number类型的变量使用string类型的方法。
URIError 执行函数encodeURI()产生的错误。

三、变量与常量

  1. 字面量
    在 JS 中,固定值一般称为字面量,字面量用来赋值给变量或常量。
  • 数字(Number)
    可为整数1、小数1.1、科学计数1e2
  • 字符串(String)
    字符串可使用双引号"string"或单引号'string'
    字符串里也可以有引号,但不能和外层引号相同。如"hello 'world'"'hello "world"'
    若需要里面引号与外层引号相同,要使用转义符\,如"hello \"world\""
    字符串可以用\换行,但代码不美观,如
            // 字符串换行
            document.write("hello \
world")

此时相当于document.write("hello world")

  • 表达式字面量
    1 + 2 "1" + "2"
  • 数组(Array)
    用中括号包裹,里面可为数字、字符串、数组、对象、函数。如[1, "string", {key: "value"}]
  • 对象(Object)
    用大括号包裹,为key-value对,key为字符串,value可为数字、字符串、数组、对象、函数。如{a: 1, b: "b", c: [1, 2]}
    若key中有空格,需要使用引号,如{"aa bb": 20}
  • 函数(Function)
    function(a, b) { return a * b; }
  1. 类型判断
  • 使用typeOf判断类型。
    但不能判断数组、正则和对象,返回的都是object。
    可以写成typeof(1),也可以写成typeof 1
            document.write(typeof(1))          //number
            document.write(typeof("1"))        //string
            document.write(typeof [1, 2])     //object
            document.write(typeof {a: 1})     //object
            document.write(typeof(function a() {}))//function
            // 正则
            document.write(typeof(/\d+/g))     //object
  • 使用isArray()判断是否为数组
            // 判断是否支持isArray方法
            if (Array.isArray) {
                document.write(Array.isArray([1, 2]))//true
                document.write(Array.isArray({a: 1}))//false
            }
  • 使用Instanceof判断类型
    不能用于判断对象,因为数组、正则和对象调用instanceof Object都会返回true。
document.write([1, 2] instanceof Array)//true
            document.write({a: 1} instanceof Array)//false
            
            document.write([1, 2] instanceof Object)//true
  • 使用constructor属性判断类型
    该属性会返回构造函数。
function type(obj) {
                return obj.constructor
            }
            document.write(type(1), "</br>")//function Number() { [native code] }
            document.write(type("1"), "</br>")//function String() { [native code] }
            document.write(type([1, 2]), "</br>")//function Array() { [native code] }
            document.write(type({a: 1}), "</br>")//function Object() { [native code] }
            document.write(type(function a() {}), "</br>")//function Function() { [native code] }
            document.write(type(/\d+/g), "</br>")//function RegExp() { [native code] }
  1. 变量
    变量命名可使用小驼峰firstName、大驼峰FirstName、下划线法first_name,建议使用小驼峰。
    变量通常以字母开头,且对大小写敏感。
  • var
    声明变量var a
    声明多个变量var a, b
    变量未赋值时默认为undefined
    声明变量并赋值var a = 1
    声明多个变量并赋值var a = 1, b = 2
    变量是可变的,可在声明变量后改变变量的值。如var a = 1;a = 10;
    重新声明变量后,变量值不会清空。如var a = 1;var a;,此时a还是为1。
    未声明直接赋值时,如a = 1,相当于var a;a = 1
    注:语句后面可不加分号,但多条语句在同一行时,则必须添加分号。如如var a = 1;a = 10;

  • let
    let也是一个变量,声明方式与var一致,但let只在包含它的{ }里(当前块作用域)有效,而var在{ }外(上级块作用域)也生效。for循环( )中声明的let变量也只在循环体内有效。

    document.write(a, "<br>")//undefined
            {
                var a = 1
            }
            document.write(a, "<br>")//1
            document.write(b, "<br>")//error  b is not defined
            {
                let b = 2
            }
            document.write(b, "<br>")//error  b is not defined

根据上面,let只在{ }内有效,所以不会影响括号外的同名变量。

var c = 3
            document.write(c, "<br>")//3
            {
                let c = 4
                document.write(c, "<br>")//4
            }
            document.write(c, "<br>")//3 若let改成var 这里输出4

但实际上,最好变量不要同名,就不会产生误导。

  1. 全局变量
    <script></script>内函数外直接声明的叫全局变量,可以在该脚本中任意地方使用。
    在函数内声明的变量叫局部变量,只在函数内有效。局部变量中的let只在对应的{ }中有效,而var在整个函数内有效。
    使用var声明的全局变量属于 window 对象,可以调用window.name来获取。而let声明的全局变量则不属于 window 对象。
var d = 4
            let e = 5
            document.write(d, e)// 4 5
            document.write(window.d, window.e)//4 undefined

但全局变量与 window 对象的变量也有区别。
全局变量不能用delete删除,而 window 对象的变量则可以。

var d = 1
            window.e = 2
            delete d
            delete e
            document.write(d, "<br>")//1
            document.write(window.e, "<br>")//undefined
  1. 变量重新声明
    在同一级作用域中,只能使用var来重新声明同名var变量。
let f = 6
            let f = 66//error Identifier 'f' has already been declared
            
            let g = 7
            var g = 77//error Identifier 'g' has already been declared
            
            var h = 9
            let h = 99//error Identifier 'h' has already been declared
            
            var i = 10
            var i = 100//success
  1. 声明提升
    在 JS 中,函数声明和var变量声明都将被提升到最顶部;若在函数内,则提升到函数最顶部。且函数比变量更优先提升。
    若变量声明并赋值,如var a = 1,只会声明提升,赋值还是在原来位置,即在赋值前使用变量,不会报错,但会返回undefined
    var声明的变量会声明提升,所以可以先使用再声明;而let声明的变量不能声明提升,必须先声明再使用。
            m = 5;n = 6;
            document.write(m, n)//5 6 声明提升 
            var n;var m;
            
            var o = 7
            document.write(o, p)//7 undefined 若直接声明并赋值,声明会提升,赋值还在原先位置。
            var p = 8
            
            
            q = 9
            document.write(q)//UncaughtReferenceError: q is not defined let变量不能声明提升
            let q

若存在同名var变量和函数,函数会先提升,var变量再提升,所以实际上var变量会覆盖同名函数。
建议:
函数与变量不应该同名,var变量、let变量与常量也不应该同名。
使用函数与变量时,都应该先声明再使用,这样不会产生隐性问题。声明也应该放在代码最上面。

  • 严格模式
    可以在脚本的开头添加"use strict"来使用严格模式。也可以在函数的开头添加,使严格模式只有该函数内生效。
    严格模式下必须先声明才能使用变量和函数,更多限制查看严格模式
    使用严格模式可以保证代码运行的安全;提高编译器效率,增加运行速度;
    注:"use strict"的上面不能有代码(可以有注释),否则严格模式无效。
  1. const
    const声明一个或多个常量,声明时必须进行赋值,且值不可再修改和重新声明。
    但当常量是一个数组或对象时,是可以修改里面元素的值的。
const l = { name: "zhangsan" }
            l.name = "lisi"//能修改不报错 
            l = { name: "lisi" }//UncaughtTypeError: Assignment to constant variable.

可以使用Object.freeze()来冻结对象,使之不能删除、添加、修改对象的元素。

四、数据类型

JS 是动态的数据类型,会根据后面值的类型判断现在的变量类型。

var a//此时是Undefined
            a = 1//Number
            a = "2"//String
            a = [3]//Array
            a = { key: 4 }//Object

数据类型可分为值类型与引用类型。

  • 值类型
    值类型分为字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、独一无二的值(Symbol)。
    值类型是存放在栈内存(Stack)里的,两变量相等时,修改一个变量的值不会影响另一个变量。
var a = 5
            var b = a
            a = 6
            document.write(a, b)//6 5
  • 引用类型
    引用类型分为对象(Object)、数组(Array)、函数(Function)。
    引用类型的值保存在堆内存(Heap)中的,栈内存中只存放值在堆内存中的指针地址。
    当修改元素的值,修改的是堆内存中的值,所有指向该对象的变量的值都会改变。
    为变量赋另一个值时,变量失去之前值的指针,与之前值再无关系。
var c = { name: "zhangsan" }
            var d = c
            c.name = "lisi"//修改c.name会影响d.name的值,因为指向同一个地址
            c = {name: "wangwu"}//为c重新赋值,与之前的值再无关系
            document.write(c.name, d.name)//wangwu lisi
  1. String 字符串
  • 初始化
    使用字面量:var a = "hello 'world'"
    使用构造函数:var a = new String("hello 'world'")。但此时typeof a == object
  • 访问字符
    使用[]来访问每个字符,如a[3],表示获取索引为3的字符,索引有效值为0到length-1。length表示字符串的长度。
    或使用charAt()访问每个字符,a[3]相当于a.charAt(3)
  • 转换成字符串
    String(exp) 将表达式转换成字符串。表达式可以是一个变量或常量。
    exp.toString() 将表达式转换成字符串。
    string.toUpperCase() 将字符串转换成大写字符串。
    string.toLowerCase() 将字符串转换成小写字符串。
  • 运算字符串
    使用+来拼接字符串,如"a" + "b" == "ab",相当于"a".concat("b")

更多属性和方法详见 JavaScript 参考手册 -- String 对象

  1. Number 数字
  • 初始化
    使用字面量:var a = 1.1。可为整数1、小数1.1、科学计数1e2
    使用构造函数:var a = new Number(123),但此时typeof a == object
    整数前加0,表示使用八进制;前面加0x,表示使用十六进制。
    使用toString()可进制转换,如(10).toString(2) == 1010,不加括号时会报错,因为解析器会把10.看成10,但可以使用10..toString(2)
    注:在 JS 中,整数实际上是浮点类型。
  • 精度
    整数最多为15位。如2222222222222222(16个2),打印出来是1000000000000000(15个0)
    小数的小数部分最多为17位。如0.1 + 0.2 == 0.30000000000000004(小数部分共17位),所以0.1 + 0.2 != 0.3
    可以通过(0.1*10 + 0.2*10)/10 == 0.3来比较。只要整数部分不为0,就能正常比较,如1.1 + 0.2 == 1.3
  • 特殊值
    infinity 无穷大,一个数字除以0结果为infinity。
    infinity与任何值加减乘除都是infinity,即infinity + 1 == infinity
    正负无穷不相等,即infinity != -infinity
    NaN 非数值(Not a Number)。一个表达式不能转换成数字就会返回NaN,即Number("abc") == NaN
    非数值与任何值都不相等,包括本身,即NaN != NaN
    使用Number.isNaN()用于判断是否为NaN,如Number.isNaN(Number("a")) == true
  • 转换成数字
    Number(exp) 将表达式转换成数字。表达式可以是一个变量或常量。
    +exp 将表达式转换成数字,如+"50" == 50
    parseFloat(exp) 将表达式转换成浮点。
    parseInt(exp) 将表达式转换成整数。
    注:若不能转换成数字,则会返回NaN。

更多属性和方法详见 JavaScript 参考手册 -- Number 对象

  1. Boolean 布尔
  • 初始化
    使用字面量:var a = true
    使用构造函数:var a = new Boolean(true),但此时typeof a == object
    若无初始值或者其值为0、-0、null、""、false、undefined、NaN,布尔值为false。
  • 转换成布尔
    Boolean(exp) 将表达式转换成布尔。表达式可以是一个变量或常量。
    !!exp 将表达式转换成布尔。
    注:0、-0、null、""、false、undefined、NaN会转换成false,其余全部都会转换成true。

更多属性和方法详见 JavaScript 参考手册 -- Boolean 对象

  1. Null 空
    空值,表示一个空对象引用,数据类型为object。
    给一个变量赋值null将会清空变量,通常将数组或对象赋值null以释放内存。

  2. Undefined 未定义
    所有未赋值变量的默认值,在变量声明后变量的值就是undefined
    为一个变量赋值undefined后,数据类型为undefined。
    注:null == undefined null !== undefined

  3. Symbol 独一无二的值

  • 初始化
    语法:var a = Symbol()。
    symbol是唯一的,即使里面的值相等symbol也不相等,如Symbol("123") != Symbol("123")
    若想获取同一个symbol,可使用Symbol.for(),如Symbol.for("123") === Symbol.for("123")
    若想获取symbol的值,可使用Symbol.keyFor()
            let sym = Symbol.for("b");
            document.write(Symbol.keyFor(sym))//b
  • 用法
    symbol被用作对象的key。但symbol拥有隐藏性,所以不能通过for···in等常规遍历方式获取key。
let sym = Symbol.for('b');
            var a = {
                [sym]: "1",
                c: "2"
            }
            for (key in a) {
                document.write(key, "<br>")//c 
            }

可以使用Object.getOwnPropertySymbols()获取对象中Symbol类型的key(但实测返回[null],不知为何)。
详见Symbol

  1. Object 对象
    JS 中的所有事物都是对象,数字、日期、字符串、布尔等都是对象。
    对象是带有属性和方法的特殊数据类型,属性通过objectName.propertyName来使用,方法通过objectName.methodName()来使用。如message.lengthmessage.toUpperCase()
  • 字面量初始化
    var a = { a: 1, b: 2 }
    键值对的键为字符串,使用时不必加引号,若字符串中有空格,则必须加引号,如var a = { "a b": 1 }
    键值对的值为包括null和undefined在内的数据类型。
    若键是一个变量,需要在变量两头加上[],如var a = "name"; var b = { [a]: "zhangsan" }
    注:对象最后的元素后不能加逗号。
  • 构造函数初始化
    var a = new Object({ a: 1, b: 2 })
    另外,new Object(true)new Boolean(true)完全相同,类型都为object。
    通常使用var a = new Object();e.name = "zhangsan";这种方式来创建键值对的对象。
  • 函数初始化
function Person() {
                this.name = arguments[0]
                this.age = arguments[1]
                this.adress = arguments[2]
            }
            var p = new Person("zhangsan", 20, "chengdu")
            document.write(typeof p)//object
  • 访问元素
    使用.来访问元素,如e.name
    或使用[]来访问元素,如e["name"]。当键为带空格的字符串时,必须使用[],如e["a b"]
    若元素值是一个函数,加()时执行函数,则返回函数的返回值;不加()则返回函数的代码。
    对象的函数中,this指的是对象本身。
var e = { name: 'zhangsan' }//用字面量初始化并赋值
            var e = new Object()//构造函数初始化
            e.name = "zhangsan"//赋值
            e.adress = "cd"
            e.full = function() {
                return e.name+"_"+this.adress//this表示对象本身
            }
            document.write(e.name)//zhangsan
            //访问元素 通过. 或 []
            //元素值是一个函数时,需要加()执行函数,并显示返回值
            //不加(),则会返回函数的代码
            document.write(e.full(), " ", e['full'])//zhangsan_cd function () { return e.name+"_"+this.adress }
            
            var f = {"a b":"aa"}
            document.write(f['a b'])//aa
  • 原型对象
    所有的 JS 对象都会从一个 prototype(原型对象)中继承属性和方法。
    Date 对象从Date.prototype继承,Array 对象从Array.prototype继承,String 对象从String.prototype继承,而它们都是Object,所以它们都继承于Object.prototype
    当访问一个对象的属性或方法时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾(Object.prototype)。
    可以通过原型对象prototype给对象添加新的属性或方法。
            // 给Number添加新属性newAttr,值为newAttrValue
            Number.prototype.newAttr = 'newAttrValue'
            // 给Number添加新方法
            Number.prototype.newFunc = function() {
                document.write("newFunc")
            }
            var a = 10
            document.write(a)//10
            document.write(a.newAttr)//newAttrValue
            a.newFunc()//newFunc
  1. Array 数组
  • 初始化
    使用字面量:var a = [1, 2, 3],最后的元素后不能加逗号。
    使用构造函数:var a = new Array(1, 2, 3)

  • 访问元素
    使用[]访问数组的元素,如a[1]。 索引范围为0到length-1,length为数组元素的数量。
    也可以通过[]来修改元素的值,如a[1] = 11

  • 数组运算
    使用concat()拼接数组,如[1, 2, 3].concat([4, 5]) == [1, 2, 3, 4, 5]
    使用+,但与concat()有差别,如[1, 2, 3] + [4, 5] == "1, 2, 34, 5",最终变成了字符串。

  • 数组修改
    使用push()在末尾新增一个或多个元素,如[1, 2, 3].push(4)后原数组变为 [1, 2, 3, 4]。
    使用pop()删除末尾的元素,如[1, 2, 3].pop()后原数组变为 [1, 2]。
    使用unshift()在开头新增一个或多个元素,如[1, 2, 3].unshift(4)后原数组变为 [4, 1, 2, 3]。
    使用shift()删除开头的元素,如[1, 2, 3].shift()后原数组变为 [2, 3]。
    使用splice()删除并添加元素,如[1, 2, 3, 4].splice(1, 2, 10, 11, 12)后原数组变为 [1, 10, 11, 12, 4]。前两个参数表示在索引1处删除2个元素,后面的参数表示在索引1处新增元素10、11、12。

  • 数组遍历
    使用for循环,详见 八、条件语句 -- 3. for
    使用forEach(function(currentValue,index,arr), thisValue)

    • 回调函数为必须值,每个元素都会调用该函数。
      • currentValue 元素值,必须。
      • index 元素的索引。
      • arr 遍历的数组。
    • thisValue 函数中this的值。

更多属性和方法详见 JavaScript 参考手册 -- Array 对象

  1. 函数(Function)
  • 函数声明
    语法:function functionName(var1, var2) { return true }

    • functionName 函数名,可任意大小写。
    • var1, var1 参数,可有0个或多个参数,用逗号隔开。
    • return 返回值,给执行函数返回一个值,也可以不返回。return后立即退出函数,后面的代码无效。
  • 调用函数
    语法:var result = functionName("value1", "value2")

    • var result 若函数有返回值,则获取返回值。若函数无返回值,var result可省略。
    • functionName("value1", "value2") 调用函数,若函数无参数,则使用functionName()
    • "value1", "value2" 函数传入的参数。

    在函数中,this指向函数的所属者,即 window 对象。所以functionName()window.functionName()相同。

  • 使用call和apply调用函数
    语法: functionName.apply(para1, para2)functionName.call(para1, para2, para3...)

    • functionName 声明的函数名。
    • para1 函数中this的值。若传入null或undefined,this则会变为 window 对象。
    • para2 在apply方法中是一个数组,数组的元素值为要调用函数的参数。
      在call方法中是要调用函数的第一个参数,para3则是第二个参数,以至类推。
  • 自调用函数
    将一个函数前后加上(),再在后面添加(),就可以函数自调用。

(function functionName(para) {
                document.write(para, "<br>")
            })("hello")//hello

上面函数会自调用,输出hello。
但只能调用一次,不能通过functionName()再次调用。
所以函数名可以省略,即写成(function(para) { document.write(para, "<br>") })("hello")
箭头函数自调用(() => {})()

  • 特殊函数声明
    匿名函数 const functionName = function (var1, var2) { return true }
    箭头函数 const functionName = (var1, var2) => { return true }
    若只有一个参数,可以省略()。若只有一句表达式,可以省略{},如const functionName = var1 => return true
    构造函数 const functionName = new Function("var1", "var2", "return true"),尽量少用。
    这几种函数的调用方式与普通的相同。
  • 函数声明提升
    函数也能够声明提升,而且比变量优先提升,所以同名变量会覆盖同名函数。
    但上面三种特殊函数声明就不能提升,因为它实际在是一个常量,当然,即使改成var也不能提升。
    函数中的声明的变量只作用于函数,在函数执行时创建,并在函数结束后删除。
    若在函数内使用未声明的变量,则函数会将该变量变为全局变量。
            function c () {
                d = "hello"
            }
            document.write(d)//UncaughtReferenceError: d is not defined 因为c()前变量d还未创建
            c()//执行函数时会调用d = "hello",此时会发生变量提升,var d会自动放在脚本顶部,成为一个全局变量。
            document.write(d)//hello c()后d会变成一个全局变量
  • 函数参数
    若传入的参数比需要的多,则忽略多余的入参;若传入的参数比需要的少,则未传的会用undefined代替。
    函数可以给入参设置默认值,如function functionName(x, y = 1) { }
    函数里可使用一个对象arguments,它是所有入参值的数组。可通过arguments[index]获取入参的值。
function functionName() {
                for (let i = 0; i < arguments.length; i++) {
                    document.write(arguments[i])//123
                }
            }
            funName(1, 2, 3)
  • 闭包
    函数内的变量只能在函数中使用,而全局变量可以在函数中使用,但脚本内所有地方也都能使用。而使用闭包就可以在函数外使用函数内的变量(意义上)。
function fun1() {
                //声明一个函数内的变量
                var x = 10
                //返回一个函数
                return function() {
                    return x += arguments[0]
                }
            }
            var y = fun1()
            document.write(y, "<br>")//function () { return x += arguments[0] } 
            document.write(typeof y, "<br>")//function y是一个函数
            
            var outX = y(20)//这里就使用了函数里的变量与20相加 实现了在函数外使用函数内的变量这个功能
            document.write(outX, "<br>")//30

一般来说,函数调用完成后,函数内的变量就会被释放。根据上面,变量x被返回的函数持有,而返回的子函数被变量y持有,相当于y持有x,所以x不会被释放。
所以闭包就是 使用了父函数的变量并且可以被外部调用的 子函数。

也可以使用自调用的方式实现闭包,更精简。

            //自调用
            var y = (function() {
                var x = 10
                return function() { return x += arguments[0] }
            })()
            var outX = y(20)//30
  • 全局函数与属性
    JS 已创建好的能直接使用的属性与函数。
    详见全局属性/函数

五、其他数据类型

  1. 日期 Date
  • 初始化
    当前日期:var a = new Date()
    传入时间戳:var a = new Date(1000*3600*24*365*10)
    传入日期字符串:var a = new Date("2021-02-01 10:20:30")
    传入年月日时分秒毫秒:var a = new Date(2021, 5, 1, 12, 13, 14, 0),前两个参数必传,因为只传一个参数的时候是时间戳。

  • 修改日期
    使用setHours()来修改小时数,如a.setHours(a.getHours() + 5)表示增加5小时。
    同样的,修改年setFullYear()、月setMonth()、日setDate()、时setHours()、分setMinutes()、秒setSeconds()、毫秒setMilliseconds()、时间戳setTime()
    使用setTime()时需要时间戳,可以通过Date.parse()获取,如a.setTime(Date.parse(a.toString()) + 1000*3600*24*1)表示增加一天。

  • 比较日期
    可通过>、>=、<、<=来比较日期。

更多属性和方法详见 JavaScript 参考手册 -- Date 对象

  1. Math 数学
    Math主要是用于执行科学计算。
  • 算术值
    Math.E 自然对数的底数e(约为2.718)。
    LN10 10的自然对数(约为2.302)。
    Math.PI 圆周率π(约为3.14)。
    Math.SQRT2 2的平方根(约为1.414)。
  • 算数方法
    Math.sin()、Math.cos()、Math.tan()为正弦、余弦、正切,参数为弧度。
    Math.abs() 绝对值。
    Math.ceil()、Math.floor()、Math.round()为上舍入、下舍入、四舍五入,即ceil(1.3) == 2、floor(1.6) == 1、round(1.5) == 2
    Math.min(x, y...)、Math.max(x, y...)为最小值、最大值。
    Math.random() 0~1之间的随机数。使用Math.floor(Math.round()*100)获取<100的随机数;使用Math.floor(Math.round()*(100-50))+50获取>=50并且<100的随机数。

更多属性和方法详见 JavaScript 参考手册 -- Math 对象

  1. RegExp 正则表达式
    正则表达式(Regular Expression,简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。正则表达式是匹配字符串的条件。
  • 初始化
    使用字面量:var a = /world/i
    使用构造函数:var a = new RegExp("world", "i")
    第一个参数是表达式的模式,若模式中要使用\字符,则需要使用转义符,如var a = /w\\orld/i
    第二个参数为修饰符。

  • 修饰符
    修饰符是可选的,并且不区分大小写。
    修饰符有igm三种,并且可同时使用多种,如/a/gi
    i 大小写不敏感。/A/i能匹配abcd中的a。
    g 全局匹配。/a/g匹配abacad时,能匹配到3个a,默认时只能匹配第一个a。
    m 多行匹配。???

  • 匹配
    使用test()测试是否能匹配成功字符串,如/wor/i.test("hello world") == true
    使用exec()获取匹配成功的字符串,如/w[opq]r/i.exec("hello world") == "wor"
    当存在g修饰符时,可连续调用test()exec()来进行匹配,lastIndex属性指示下次匹配的起始位置。

var b = /bc/g
            var c = "abcdefgbcba"
            document.write(b.test(c), b.lastIndex, "<br>")//true3
            document.write(b.test(c), b.lastIndex, "<br>")//true9
            document.write(b.test(c), b.lastIndex, "<br>")//false0 未匹配到时lastIndex会重置为0
  • 表达式模式
    条件:
    []匹配中括号中的任意字符,如"abdc".match(/[bc]/g) == ['b', 'c']
    [^]匹配不在中括号中的字符,如"abdc".match(/[^bc]/g) == ['a', 'd']
    里面可以使用连接符,0-9表示任何0到9的数字,A-Z、a-z、A-z表示任何大写字母、小写字母、字母。
    (x|y|z) 匹配|左边条件或右边条件,如"abcdefg".match(/(bc|ce|ef)/g) == ["bc", "ef"]
    字符:
    . 匹配所有字符(除了换行符与行结束符)。
    \w 匹配数字、字母、下划线,相当于[0-9A-z_]
    \W 匹配非数字、字母、下划线,相当于[^0-9A-z_]
    \d 匹配数字,相当于[0-9]
    \D 匹配非数字,相当于[^0-9]
    \s 查找空白字符,相当于[ ]
    \b 匹配单词边界,如"aabc abcd".search(/\babc/g) == 5,会匹配第二个abc。测试出只对单词开头有效,结尾无效。
    \B 匹配非单词边界。
    量词:
    表示匹配多少个字符。
    n+ 至少有一个n,即数量>1。
    n* 任意数量的n,即数量>=0。
    n? 至多有一个n,即数量<=1 。
    n{3} 有三个n,即数量=3。
    n{3,} 有至少三个n,即数量>=3
    n{1, 3} 有一到三个n,即数量>=1并且<=3。
    特殊:
    ^n 以n开始。
    n$ 以n结束。
    ?=n 匹配后接n的字符串,如"aabcde".match(/ab(?=c)/g) == ["ab"]
    ?!n 匹配不后接n的字符串。

更多属性和方法详见 JavaScript 参考手册 -- RegExp 对象

六、事件触发

事件可以是浏览器行为,如页面加载完成;也可以是用户行为,如点击标签。

  1. 标签中绑定事件
    语法:<element-name event-name="表达式">
    • element-name 元素名,如<div>、<a>
    • event-name 事件名称。如onclick 点击标签、onload页面加载完成。
    • "表达式" 可以是单引号,也可以是双引号。当为单引号时,里面可以用双引号来使用字符串;为双引号时用单引号来使用字符串。
      表达式可以是一个函数调用,如<div onclick="tapAction()">hello</div>
      可以是一句实现某功能的 JS 语句,如<div onclick="this.innerHTML = 'hello world'">hello</div>
      表达式中使用this时,表示的是元素本身。

关于this:
1、在对象函数(对象中某键的值为函数)中, this指向对象本身。
2、脚本中直接使用,this指向全局(Global)对象,即 window 对象。
3、在函数中使用,this指向函数的所属者,即 window 对象。
4、严格模式下函数没有所属者,所以this是undefined。
5、在HTML事件句柄中,this指向接收事件的HTML元素,即上面的例子。
6、apply()call()允许切换函数执行的上下文环境(context),所以this可以指向任何对象。可在 四、数据类型 -- 9. 函数(Function) -- 使用call和apply调用函数 中查看。

更多事件方法详见 JavaScript 参考手册 -- DOM 事件对象

  • void
    void是 JS 中非常重要的关键字,它表示 运行一个表达式但是不返回值。
    语法:void expjavascript:void expvoid(exp)javascript:void(exp)
    exp 一个表达式,可以是普通语句void(this.innerHTML = 'hello')或一个函数void(alert('warn!'))
    使用javascript:void(0)不会产生任何变化,常用于死链接。
// 阻止链接跳转,URL不会有任何变化
<a href="javascript:void(0)" rel="nofollow ugc">点击此处</a>
// 虽然阻止了链接跳转,但URL尾部会多个#,改变了当前URL。(# 主要用于配合 location.hash)
<a href="#" rel="nofollow ugc">点击此处</a>
// 同理,# 可以的话,? 也能达到阻止页面跳转的效果,但也相同的改变了URL。(? 主要用于配合 location.search)
<a href="?" rel="nofollow ugc">点击此处</a>
  1. DOM分配事件
    除了像上面一样在标签中绑定事件外,还可以使用 DOM 来给元素分配事件。
    语法: element.event-name = function
    function 是一个函数,如document.getElementById("id").onclick = function() { tapAction() };

  2. 事件监听
    语法: element.addEventListener(event, function, useCapture)
    该方法可向DOM 对象添加事件句柄。DOM 对象有 HTML 元素(element)、HTML 文档(document)、window 对象(window)。
    可添加多个事件句柄,如 click、mouseover、mouseout
    可添加多个相同的事件句柄,如两个click。

    • event 事件名,不要使用on前缀。使用 "click"而不是使用 "onclick"
    • function 事件触发后要调用的函数。
    • useCapture 布尔值,冒泡还是捕获。可选值。
      默认值为false, 即冒泡,true则为捕获。

事件传递定义了元素事件触发的顺序。 如果你将 <p> 元素插入到 <div> 元素中,用户点击 <p> 元素, 哪个元素的 click 事件先被触发呢?
在冒泡中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。
在捕获中则相反。

例:
document.getElementById("id").addEventListener("click", clickAction),函数名后不用加()
document.getElementById("id").addEventListener("click", function() { })
若要传递参数,可使用 document.getElementById("id").addEventListener("click", function() { clickAction(a, b, c) })

  • 移除监听
    如果要移除事件句柄,执行函数必须使用外部函数,如上面的第一个例子。
    匿名函数,类似document.getElementById("id").addEventListener("click", function() { })是无法移除的。
    语法: element.removeEventListener(event, function, useCapture)
    参数同addEventListener()

七、运算符

  1. 算术运算符
    + 加,除了数字相加外,
    可以字符串相加,如"hello" + " " + "world" == "hello world"
    字符串与数字相加,则将数字当成字符串使用,如"cc" + 5 + 6 == "cc56"
    字符串与布尔值相加,truefalse都当成字符串。
    数字与字符串相加,则先将字符串前面的数字先相加,和则当成字符串,如5 + 6 + "dd" + 5 + 6 == "11dd56"
    数字与布尔值相加,true当成1,false当成0。
    - 减。
    * 乘。
    / 除。
    % 取模(余数) ,如13%5 == 3
    模的正负与被取模数的正负相同,如-13%5 = -3
    ++ 自增。
    a=4,若b=a++,运算后b=4,a=5;若b=++a,运算后b=5,a=5。
    -- 自减。
    a=4,若b=a--,运算后b=4,a=3;若b=--a,运算后b=3,a=3。

  2. 赋值运算符
    = 赋值。
    += 加等,a += b相当于a = a + b。也可用于字符串、数字相加。
    -= 减等,a -= b相当于a = a - b
    *= 乘等,a *= b相当于a = a*b
    /= 除等,a /= b相当于a = a/b
    %= 取模等,a %= b相当于a = a%b

  3. 比较运算符
    == 值等于。
    != 值不等于。
    === 绝对等于,值和类型都相等。
    !== 不绝对等于 ,值和类型至少有一个不相等。
    < 小于。
    <= 小于或等于
    > 大于。
    >= 大于或等于。

    • string、number 等基础数据类型
      不同类型间比较,==先将其转换成同一类型后再比较 值 是否相等,===如果类型不同,结果就不相等。
      同类型比较,直接比较 值 是否相等,=====无区别。
    • Array、Object 等引用类型
      =====则无区别,都是比较 指针地址 是否一致。
  4. 逻辑运算符
    && 与,左右条件都为true,该语句则为true。
    || 或,左右条件有一个为true,该语句则为true。
    ! 非,右边条件为flase,该语句则为true。
    注:0、-0、null、""、false、undefined、NaN 为条件时会转换为false,其他转化为true。

  5. 条件运算符
    语法: (condition) ? value1 : value2
    若condition为true,则返回value1;否则返回value2.

  6. 位运算符
    先将数字转化为32位二进制,再进行运算。
    & 与,2&1相当于10&01,结果为00。
    | 或,10|01结果为11。
    ~ 取反,~01结果为11..110,总共有31个1。
    ^ 异或,10^01结果为11
    >> 右移,10>>1结果为01。
    << 左移,10<<1,结果为100。

八、条件语句

  1. if else
    语法:if (condition1) { code1 } else if (condition2) { code2 } else { code3 }
    若条件condition1为true,执行代码code1;否则若condition2为true,执行代码code2;否则执行代码code3。
    注:
    if else都必须用小写,条件必须用小括号包裹(有些语言中小括号可省略)。
    若code只有一句代码,可以省略大括号,如if (a == 1) b = 2

  2. switch
    语法:

            switch(value) {
                case 1:
                    code1
                    break;
                case 2:
                case 3:
                    code3
                    break;
                default:
                    code4
            }

value是一个表达式(通常是一个变量),将value的值与每个case后的值做比较,若相等则执行后面的代码code。
若不加break,在前面的代码code执行后会继续比较下一个case后的值。
若所有case值与表达式的值都不相等,则会执行default后面的代码code。
case 2后面没有写代码,表示当value=2或3时都会执行code3。
注:switch是使用===作比较的,case后的值可以是String 、Number、Boolean、char、null、undefined。

  1. for
    用来多次执行重复的代码。
    语法:for (code1; code2; code3) { repeatCode }

    • code1 会在循环开始前执行,常用来初始化一个变量。
    • code2 定义循环的条件。
    • code3 每循环一次后执行。

    for (let i = 1; i < 10; i++) { }
    code1中的let,表示变量只能在循环中使用。若改为var,变量则能在循环外且函数内使用。
    code1可以省略,但code1后面的分号不能删除,如let i = 1;for (; i < 10; i++) { }
    code1中也可以初始化多个变量,用逗号分隔,如for (let i = 1, number = 10; i < number; i++) { }
    code2也可以省略,后面的分号不能删除。但repeatCode里面必须要使用break以结束循环。
    code3也可能省略,但应该在repeatCode中添加变量变化的语句。
    3者都省略,如下

            let i = 1
            for (;;) {
                if (i >= 10) {
                    break
                }
                i += 2
            }
  • for in
    用来遍历数组或对象,也可以遍历字符串。
    语法: for (index in data) { repeatCode }

    • data 数据。可为数组、对象、字符串。
    • index 索引。
      当data为数组或字符串时,索引范围从0到length-1,使用data[index]来获取元素或字符。
      当data为对象时,索引为对象的键key,使用data[index]来获取对应的值value

    注:for in的小括号不能删除(有些语言不使用小括号)。
    当数组中有元素值为undefined时,for in循环会跳过这些元素,而for循环则会全部元素依次遍历。

  • for of
    用来遍历数组和字符串。
    语法: for (let ele of data) { repeatCode }
    for in用法类似,但ele返回的是数组的元素或字符串的字符。
    let表示变量ele只能在repeatCode中使用;使用var表示变量ele能用在循环外,且ele的值为最后一次遍历时ele的值。
    注:for of的小括号不能删除。

  1. while
    条件为真则一直循环代码。
    语法: while (condition) { repeatCode }
    • condition 条件。可以设置为true,但repeatCode中必须要有break以结束循环。
    • repeatCode 循环代码。需要在代码中改变某值以使condition不能一直为true。
  • do while
    语法:do { repeatCode } while (condition)
    while用法大致相同,不同之处是 会先执行一次repeatCode 再判断condition。
  1. 影响循环
  • break
    switch中,表示结束switch的比较。
    for、while循环中,表示结束循环。
  • continue
    for、while循环中,表示直接结束这次遍历,开始下一次的遍历。
    这会使continue后面的代码在这次遍历中不会执行,但前面的代码不会受影响。

九、JSON

JSON(JavaScript Object Notation)是存储和传输数据的格式,通常用于服务端向网页传递数据。
JSON 的数据为键值对,数据之间通过逗号隔开,大括号保存对象,中括号保存数组,数组中有多个对象。
键值对的键是字符串,两端必须加上引号;值可为字符串、数字、布尔值、null。

            {
                "key1":"value1",
                "key2":[
                    {"key2_1": "value2_1"},
                    {"key2_2": "value2_2"}
                ],
                "key3": {
                    "key3_1": "value3_1"
                }
            }

JSON与对象(Object)的结构相同,可以在JSON和Object之间相互转换。

  • 转换成Object
    使用JSON.parse(josn, transform)将JSON转换成对象Object。
    • json 要传入的json字符串。
    • transform 可选参数,它是一个函数,会为对象的每个键值对调用此函数。
      该函数有两个参数,分别为键值对的键与值,函数返回值会替换原键值对的值。
var a = JSON.parse('{"p": {"q": 5}}', function(k, v) {
                //v为对象时返回原值
                if (typeof v == "object") return v;
                return v * 2;               
            });
            document.write(a.p.q, "<br>")//10
  • 转换成JSON
    使用JSON.stringify(value, replacer, space)将对象转换成JSON。
    • value 对象或数组。
    • replacer 可选参数。
      • 它可以是一个函数,会为对象的每个键值对调用此函数。该函数有两个参数,分别为键值对的键与值,函数返回值会替换原键值对的值。若返回undefined,则会排除该键值对。
      • 也可以是一个数组,仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。
    • space 可选参数,文本添加缩进、空格和换行符。
      • 若是一个数字,则返回值文本在每个级别缩进指定数目的空格;若大于 10,则文本缩进10个空格。
      • 也可以使用非数字,如\t
var b = {a: 1, b: 2, c: 3, d: 4}
            var json = JSON.stringify(b)
            document.write(json, "<br>")//{"a":1,"b":2,"c":3,"d":4}
            var json = JSON.stringify(b, null, 1)
            document.write(json, "<br>")//{ "a": 1, "b": 2, "c": 3, "d": 4 }
            json = JSON.stringify(b, ["b", "c"])
            document.write(json, "<br>")//{"b":2,"c":3}
            json = JSON.stringify(b, function(k, v) {
                if (typeof v == "object") return v
                if (k == "b") return undefined//返回undefined时排除该键值对
                return v*2
            })
            document.write(json, "<br>")//{"a":2,"c":6,"d":8}

十、异步执行

  1. 延迟操作
    延迟一段时间后执行操作。
    语法: window.setTimeout(code, milliseconds, param1, param2, ...)
    使用时window可以省略。

    • code 必须值,要调用的表达式,如setTimeout("alert('hello')", 1000)
      可以是一个函数,如setTimeout(timeAction, 1000),函数名后不用加()
    • milliseconds 要延迟的时间,单位为毫秒,默认为0。
    • param1, param2 要传给code函数的参数。

    返回值是一个ID(数字),可使用window.clearTimeout()取消延迟操作。

var a = setTimeout(function(x, y) {
                document.write(x, " ", y)//hello world
            }, 1000, "hello", "world")
            clearTimeout(a)//取消延迟操作
  1. 定时操作
    每间隔一段时间执行一次操作。
    语法: window.setInterval(code, milliseconds, param1, param2, ...);
    参数与setTimeout()相同。
    返回值是一个ID(数字),可以使用window.clearTimeout()window.clearInterval取消定时操作。

  2. AJAX
    AJAX(Asynchronous JavaScript and XML) 异步的 JavaScript 和 XML。
    AJAX 是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。

var http;
                //创建请求对象
                if (window.XMLHttpRequest) {
                    http = new XMLHttpRequest()
                } else {
                    //适配IE5 6
                    http = new ActiveXObject("Microsoft.XMLHTTP")
                }
                //使用回调函数
                http.onreadystatechange = function() {
                    if (http.readyState == 4&&http.status == 200) {
                        document.write(http.responseText)//使用String类型数据
                        // document.write(http.responseXML)//使用XML类型数据
                    }
                }
                //GET时配置请求参数
                http.open("GET", "./response.php?name=zhangsan&age=18", true);
                //发送请求
                http.send();
                
                // //Post时配置请求参数
                // http.open("POST", "./response.php", true)
                // //设置http头
                // http.setRequestHeader("Content-type","application/x-www-form-urlencoded")
                // //发送请求
                // http.send("name=zhangsan&age=18")
            }

使用new XMLHttpRequest()创建请求对象。
使用open()配置请求的参数。

  • 参数1表示请求类型,常使用GET、POST
  • 参数2表示请求的文件地址,可以是本地的txt、也可以是服务器上的php、asp等。
  • 参数3表示异步还是同步,为true表示异步。

使用send()发送请求。

  • POST类型时需要传入参数,参数值为请求的参数,如send("name=zhangsan&age=18")
  • GET类型时,请求的参数拼接在open()的参数2上,如open("GET", "./response.php?name=zhangsan&age=20", ture)

使用setRequestHeader()传入HTTP头,POST类型时需要,如setRequestHeader("Content-type", "application/x-www-form-urlencoded")

XMLHttpRequest 对象有三个重要的属性。readyState表示 XMLHttpRequest 对象的状态,status表示http请求的状态,onreadystatechange为readyState改变时的回调函数。

  • readyState
    0: 请求未初始化
    1: 服务器连接已建立
    2: 请求已接收
    3: 请求处理中
    4: 请求已完成,且响应已就绪
    new XMLHttpRequest()之后,readyState变为0,open()后readyState变为1,send()后变为2。
  • status
    详见HTTP状态码,200表示成功。
  • onreadystatechange
    通常在回调中通过readyState == 4&&status == 200判断请求完成,此时使用responseText属性获取String类型的数据,使用responseXML属性获取xml类型的数据。
  1. Promise
    可让异步操作以同步操作(链式)的流程形式表现出来,使控制异步操作更加容易且更美观。
    Promise有三种状态:
    • pending 初始状态,不是成功或失败状态。
    • fulfilled 成功状态。该状态下可以调用then()函数。
    • rejected 失败状态。该状态下可以调用catch()函数。
var promise = new Promise(function(resolve, reject) {
                //执行异步操作
                resolve()
            })
            promise.then(function(value) {
                retrun ""
            }).catch(function(error) {
                
            }).finally(function() {
                
            })
  • 创建 Promise 对象
    使用var promise = new Promise(function(resolve, reject) { })创建一个 Promise 对象。

    • 需要传入一个函数,该函数有两个参数resolve、reject,两参数都是回调函数。
      异步操作写在该函数内,操作完成后,调用resolve()reject()将 Promise 对象变为fulfilledrejected状态。

    Promise 对象默认是pending状态,若转变为fulfilled,对象就会继续执行then()方法;若转变为rejected,对象就会继续执行catch()方法。

  • then
    只有fulfilled状态的 Promise 对象才会执行该方法。

    • 需要传入一个函数,函数有一个参数value,值与resolve()传入的参数相同。
      value通常是请求网络接口后返回的数据,一般在函数里处理数据。
    • 函数需要返回一个 Promise 对象,若状态为fulfilled,就会继续执行下一个then()方法;若状态为rejected,就会跳过后面的then()直接执行catch()方法;若状态为pending,就会一直等待 Promise 对象转换状态。
    • 也可以返回一个基础类型(String、Array等)的值。相当于返回了一个 Promise 对象,该对象回调了resolve(),且传入的参数为基础类型的值。
    • 也可以不返回,相当于resolve()传入的参数是undefined。
  • catch
    只有rejected状态的 Promise 对象才会执行该方法。

    • 需要传入一个函数,函数有一个参数error,值与reject()传入的参数相同。
      通常是 Error 对象,详见 二、调试 -- 6. 异常处理
      error通常是请求网络接口后返回的错误信息,一般在函数里弹出提示信息。
  • finally
    fulfilledrejected状态的Promise对象都能执行该方法。

    • 需要传入一个函数。可以在函数里执行一些公共操作,如隐藏加载的菊花。

Q&A:
Q: then、catch 和 finally 序列能否顺序颠倒?
A: 可以,效果完全一样。但不建议这样做,最好按 then-catch-finally 的顺序编写程序。
Q: 除了 then 块以外,其它两种块能否多次使用?
A: 可以,finally 与 then 一样会按顺序执行,但是 catch 块只会执行第一个,除非 catch 块里有异常。所以最好只安排一个 catch 和 finally 块。
Q: then 块如何中断?
A: then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。
Q: 什么时候我们需要再写一个 then 而不是在当前的 then 接着编程?
A: 当你又需要调用一个异步任务的时候。

  • all
    语法: var promise = Promise.all([promise1, promise2])

    • 需要传入一个数组,数组元素是 Promise 对象。
    • 会返回一个 Promise 对象。
      • 若数组所有元素的状态都是fulfilled,返回的对象的状态就是fulfilled,且回调值value是数组元素的回调值value组成的数组;
      • 若数组有一个元素的状态为rejected,返回的对象的状态就是rejected,且回调值error为该元素的回调值error。

    通常用该方法来同时调用多个网络接口,都成功后就显示界面,有一个失败就显示错误信息。

  • race
    语法: var promise = Promise.race([promise1, promise2])

    • 需要传入一个数组,数组元素是 Promise 对象。
    • 会返回一个 Promise 对象,对象的状态是数组中最先转变状态的 Promise 对象的状态。
  • resolve
    语法: var promise = Promise.resolve()

    • 需要传入基础类型(String、Array等)的值,返回一个状态为fulfilled的 Promise 对象。
      var promise = new Promise(function(resolve, reject) { resolve() })作用相同。
    • 也可以传入 Promise 对象,该对象会原封不动的返回。
  • reject
    语法: var promise = Promise.reject()

    • 需要传入基础类型(String、Array等)的值或 Error 对象,返回一个状态为rejected的 Promise 对象。
      var promise = new Promise(function(resolve, reject) { reject() })作用相同。

十一、DOM

DOM为Document Object Model(文档对象模型),用于操作 HTML 元素。


文档是一个文档节点,所有的 HTML 元素都是元素节点,所有 HTML 属性都是属性节点,文本插入到 HTML 元素是文本节点,注释是注释节点。
Document 对象是 HTML 文档的根节点。
Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。
Document 对象是 Window 对象的一部分,可通过window.document属性对其进行访问,window可省略。
元素对象代表着一个 HTML 元素。
元素对象的子节点可以是元素节点、文本节点、注释节点。
元素对象有属性,属性属于属性节点。

节点树中的节点彼此拥有层级关系。
我们常用父(parent)、子(child)和同胞(sibling)等术语来描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹),同胞是拥有相同父节点的节点。
在节点树中,顶端节点被称为根(root)。
每个节点都有父节点、除了根(它没有父节点)。
一个节点可拥有任意数量的子节点。

DOM全部属性和方法详见DOM Document 对象

  1. 查找元素element
  • 通过id
    语法:document.getElementById()

    • 需要传入一个参数,即<div id=""></div>中id的值。
    • 返回元素对象,若没有找到,则返回null。

    元素对象的属性和方法详见 JavaScript 参考手册 -- DOM 元素对象

  • 通过标签名
    语法:document.getElementsByTagName()element.getElementsByTagName()

    • 需要传入一个参数,即<div></div>中的div。
    • 返回 HTMLCollection 对象,相当于数组。
  • 通过类名
    语法:document.getElementsByClassName()element.getElementsByClassName()

    • 需要传入一个参数,即<div class=""></div>中class的值。
      多个类名使用空格分隔,如document.getElementsByClassName("test1 test2")
    • 返回 HTMLCollection 对象,相当于数组。
  • 通过名称
    语法:document.getElementsByName()

    • 需要传入一个参数,即<div name=""></div>中name的值。
    • 返回 NodeList 对象,相当于数组。
  • 通过CSS选择器
    语法:document.querySelectorAll()element.querySelectorAll()

    • 需要传入一个参数,为CSS选择器。即<p id="id" class="class">中的p、#id、.class,多个选择器用逗号隔开。
    • 返回 NodeList 对象,相当于数组。

    document.querySelector()querySelectorAll()用法相同,但只返回 NodeList 对象的第一个元素。

  1. HTMLCollection 对象
    HTMLCollection是 HTML 元素的集合,是一个伪数组,不能使用数组的某些方法。
    可以使用Array.prototype.slice.call(col)Array.prototype.slice.apply(col)Array.prototype.slice.bind(col)() 将 HTMLCollection 对象转换成一个数组,参数col为 HTMLCollection 对象。

    • 使用length获取元素的数量。
    • 使用item(index)[index]获取对应索引index的元素。
    • 使用namedItem(name)[name]获取对应name或id的元素。参数name即为<div id="" name=""></div>中的id或name的值,有一个相同即可。
  2. NodeList对象
    NodeList 是一个文档节点的集合,包含属性节点和文本节点,是一个伪数组,不能使用数组的某些方法。
    和 HTMLCollection 对象一样,可以使用call、apply、bind转换成数组。

    • 使用length获取元素的数量。
    • 使用item(index)[index]获取对应索引index的元素。

与 HTMLCollection 对象的不同点
removeChild()删除一个节点后,之前 NodeList 对象的元素数量不会变化,而之前 HTMLCollection 对象的元素数量会减少。
即 HtmlCollection 是动态绑定的,对节点的增删是敏感的。

  1. 修改元素
  • 修改内容
    语法:element.innerHTML = 新内容
    innerHTML是元素的一个属性,即<div id="id"><p>hello</p></div>中的<p>hello</p>。
    可修改该属性来改变 HTML 元素的内容,如 document.getElementById("id").innerHTML = "hello"

  • 修改元素属性值
    语法:element.attributeName = 新属性值
    attributeName是标签的各种属性名,如<img id="" src="" class="">中的id、src、class。
    通过该方法可改变元素的各种标签属性值,如document.getElementById("id").src= "./demo.png"

  • 修改样式
    语法: element.style.CSSName=" "
    CSSName是CSS的属性名,如backgroundColor、font
    通过该方法可改变元素的CSS样式,如document.getElementById("id").style.color= "red"

    style属于样式声明对象(CSSStyleDeclaration),属性和方法详见 JavaScript 参考手册 -- CSSStyleDeclaration 对象

  1. 操作元素
  • 创建元素节点
    HTML 元素通常是由元素节点和文本节点组成。
    语法:document.createElement(nodename)
    nodename 节点名称,如div、p等。

  • 创建文本节点
    语法:document.createTextNode(text)

  • 创建注释节点
    因为注释是不可见的,所有页面上无变化。
    语法:document.createComment(text)

  • 添加子节点。
    可为元素添加子节点,子节点可为元素节点、文本节点、注释节点。
    语法:element.appendChild(node)
    若 document 中已存在该元素节点,会先将节点从文档中删除,再插入到元素的子节点列表末尾。
    若 document 中不存在该元素节点,则会直接插入到元素的子节点列表末尾。

    • 可使用element.childNodes获取元素的子节点列表,包含元素节点、文本节点、注释节点。
    • 可使用element.children获取元素的子元素节点列表。
    • 可使用element.removeChild(node)删除子节点。
      若想将自己从父元素中删除,可使用element.parentNode.removeChild(element)
  • 插入子节点
    将子节点插入到另一个子节点前面。
    语法:element.insertBefore(newnode, existingnode)

    • newnode 要插入的元素节点。
    • existingnode 已存在的子节点

    appendChild()类似,若元素节点已存在于 document 中,会先删除原节点再插入。

  • 替换子节点
    语法:element.replaceChild(newnode,oldnode)

    • newnode 元素节点
    • oldnode 被替换的元素节点
  • 创建属性节点
    语法:document.createAttribute(attributename)
    attributename 属性名,如class、style、onclick等。

    • 创建成功后,可使用属性name获取属性节点的名称,使用属性value来设置或获取属性节点的值。
    • 可使用element.attributes获取元素的所有属性节点。

    属性节点的更多属性和方法详见 JavaScript 参考手册 -- DOM 属性对象

  • 设置属性节点
    为元素设置一个属性节点。
    语法:element.setAttributeNode(attributenode)
    使用element.setAttribute(attributename,attributevalue)直接为元素设置属性并指定值。

  • 获取属性节点
    语法:element.getAttributeNode(attributename)
    使用element.getAttribute(attributename)直接获取元素的属性值。

  • 删除属性节点
    语法:element.removeAttributeNode(attributenode)
    使用element.removeAttribute(attributename)直接为元素删除指定的属性。

var ele = document.createElement("div")//创建元素节点
            var text = document.createTextNode("hello")//创建文本节点
            ele.appendChild(text)//ele将文本节点添加为子节点
            
            var att = document.createAttribute("style")//创建属性节点
            att.value = "color: red;"//设置属性节点的值
            ele.setAttributeNode(att)//ele添加属性节点att
                        
            var com = document.createComment("comments");//创建注释节点
            ele.appendChild(com);//ele添加注释节点 但注释不可见
            
            document.body.appendChild(ele)//body上添加子节点ele

十二、BOM

BOM 是浏览器对象模型(Browser Object Model),即 window。
window 表示浏览器窗口。全局变量是 window 对象的属性,全局函数是 window 对象的方法。
DOM 中的 document 也是 window 对象的属性,document 详见 十一、DOM
使用 window 对象的属性或方法时,可以省略window,即window.innerHeight可省略成innerHeigh
全部属性与方法详见Window 对象

  1. screen
    window.screen 对象包含有关用户屏幕的信息,有屏幕宽、高、色彩等属性。
    属性和方法详见 JavaScript 参考手册 -- Screen 对象

  2. location
    window.location 对象包含当前页面的 URL 信息,可使用location.assign()加载新页面。
    属性和方法详见 JavaScript 参考手册 -- Location 对象

  3. history
    window.history 对象包含浏览器的历史记录,可使用history.back()后退到上一个页面,history.forward()前进到下一个页面。
    属性和方法详见 JavaScript 参考手册 -- History 对象

  4. navigator
    window.navigator 对象包含有关当前浏览器的信息。
    属性和方法详见 JavaScript 参考手册 -- Navigator 对象
    注:
    来自 navigator 对象的信息具有误导性,不应该被用于检测浏览器版本,这是因为:
    navigator 数据可被浏览器使用者更改。
    一些浏览器对测试站点会识别错误。
    浏览器无法报告晚于浏览器发布的新操作系统。

  5. 弹框
    JS 中有三种消息框:警告框、确认框、提示框。
    弹框会阻止代码执行,只有点击了确定或取消后才会继续执行代码。
    window.alert() 警告框,只有消息和确定。
    window.confirm() 确认框,有消息、取消和确定。返回一个布尔,为true表示点击了确定。
    window.prompt() 输入框,有消息、输入框、取消和确定。点确定后会返回输入的值。

  6. cookie
    window.document.cookie用于存储页面的用户信息,是存在于本地的数据。
    cookie是通过键值对保存的,键值用=连接,如key=value
    有些key有默认的作用,expires表示过期时间,path表示cookie的路径。
    注:若不设置过期时间,那么cookie的有效时间为当前窗口关闭之时,并且是存储在内存中。

  • 新增
    document.cookie = "username=zhangsan; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/"
    表示创建一个cookie,内容为username=zhangsan,过期时间为2043年,路径为当前页面。
  • 删除
    只需将过期时间设为以前的时间。如document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"
  1. storage
    storage分为window.sessionStorage(会话存储)和window.localStorage(本地存储),它们都可以对网页的数据进行增删查改,保存的数据是键值对,它们都是只读的。
    localStorage用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去除。
    sessionStorage用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
  • localStorage
    localStorage.setItem("key", "value") 新增(修改)数据,key和value都是字符串,其他类型需要先进行转换。
    var lastname = localStorage.getItem("key") 查询数据。
    localStorage.removeItem("key") 删除数据。
    localStorage.clear() 删除所有数据。
    localStorage.length 返回共有多少条数据。
    localStorage.key(index) 返回对应索引的key。

localStorage 拓展了 cookie 的 4K 限制。
localStorage在浏览器的隐私模式下面是不可读取的。
localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡。
每个页面都有自己的localStorage,不同页面之间不能访问对方的localStorage。
而当前页面能访问其他页面的cookie,但设置 阻止第三方cookie 后,也不能访问其他页面cookie了。

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

推荐阅读更多精彩内容