JavaScript学习笔记

参照文档学习JavaScript这一篇就够了

并非涵盖所有知识点,只是记录在学习过程中需要特殊记下的问题,大部分的知识点,看上面的链接

1 JavaScript 基础

JavaScript是严格区分大小写的,也就是abc和Abc会被解析器认为是两个不同的东西。

1.1 JavaScript引用

1.1.1 行内式

<body>
    <!-- 行内式 -->
    <input type="button" value="点我试试" onclick="alert('Hello World')" /> 
</body>

1.1.2 内嵌式

<body>
</body>

<script>
    // 嵌入式
    alert('自动显示');
</script>

1.1.3 外链式

test.html

<body>
</body>

<script src="Test.js"></script>

Test.js

alert('外链式');

1.2 JavaScript的输出

<script>
    // 向页面输出一句话
    document.write("Hello,World!"); 
    // 向控制台输出
    console.log("输出一条日志");     // 最常用
    console.info("输出一条信息");
    console.warn("输出一条警告");
    console.error("输出一条错误");
</script>

运行结果:
输出结果

1.3 基本数据类型

JavaScript中一共有5种基本数据类型:

  • 字符串型(String)
  • 数值型(Number)
    • Number表示的数字大小是有限的,如果超过了这个范围,则会返回 ±Infinity。
      • 最大值:+1.7976931348623157e+308
      • 最小值:-1.7976931348623157e+308
      • 0以上的最小值:5e-324
    • 特殊的数字:
      • Infinity:正无穷
      • -Infinity:负无穷
      • NaN:非法数字(Not A Number)
    • 其它的进制:
      • 二进制:0b 开头表示二进制,但是,并不是所有的浏览器都支持
      • 八进制:0 开头表示八进制
      • 十六进制:0x 开头表示十六进制

   注意:使用typeof检查一个Number类型的数据时(包括NaN 和 Infinity),会返回"number"。

  • 布尔型(Boolean)
  • undefined型(Undefined)
     Undefined 类型只有一个值,即特殊的 undefined。
     在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined。
  • null型(Null)
     Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null。
     undefined值实际上是由null值衍生出来的,所以如果比较undefined和null是否相等,会返回true
    注意:从语义上看null表示的是一个空的对象,所以使用typeof检查null会返回一个Object。
<script>
    console.log('typeof (true)' + '\t\t: ' + typeof (true));
    console.log('typeof (NaN)'  + '\t\t: ' + typeof (NaN));
    console.log('typeof (undefined)' + '\t: ' + typeof (undefined));
    console.log('typeof (null)' + '\t\t: ' + typeof (null));
</script>

运行结果:
运行结果
这5种之外的类型都称为Object,所以总的来看JavaScript中共有六种数据类型。

1.4 逻辑运算符(&&,||)

特点:短路运算
短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值

<script>
    //短路运算
    //短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值

    //逻辑与
    var a = 0;
    var b = 11;
    console.log(a++ && b++);            //0 (a++为非,即中断,打印a++的值,b++不处理)
    console.log('a=' + a, 'b=' + b);    //a=1 b=11

    console.log('----------');

    a = 1;
    b = 0;
    console.log(a++ && b++);            //0 (a++为真,b++为非,执行至b++,打印b++的值)
    console.log('a=' + a, 'b=' + b);    //a=2 b=1

    console.log('----------');

    //逻辑或
    a = 1;
    b = 11;
    console.log(a++ || b++);            //0 (a++为真,即中断,打印a++的值)
    console.log('a=' + a, 'b=' + b);    //a=2 b=11

    console.log('----------');

    a = 0;
    b = 11;
    console.log(a++ || b++);            //11 (a++为非,执行至b++,打印b++的值)
    console.log('a=' + a, 'b=' + b);    //a=1 b=12
</script>

1.5 函数

  • 形参的默认值为 undefined,所以当实参数量小于形参时,多余的形参值为undefined
  • 如果函数没有 return ,返回的值是 undefined
    <script>
        function fun1(n1, n2) {
            console.log(n1);    // 1
            console.log(n2);    // undefined
        }

        var ret1 = fun1(1);
        console.log(ret1);      // undefined

        function fun2() {
            return "a", "b";
        }
        console.log(fun2());    // b
    </script>

1.5.1 构造函数

构造函数就是一个普通的函数,创建方式和普通函数没有区别
不同点:

  • 构造函数习惯上首字母大写
  • 调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用

构造函数 new调用 时的处理:

  1. 它会立刻在内存中创建一个新的空对象。
  2. 让 this 指向这个新的对象。
  3. 执行构造函数里面的代码,给这个新对象添加属性和方法
  4. 返回这个新对象(所以构造函数里面不需要return

1.6 this对象

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象

  • 以函数的形式调用时,this永远都是window
  • 以方法的形式调用时,this就是调用方法的那个对象
  • 当以构造函数的形式调用时,this就是新创建的那个对象
  • 使用call和apply调用时,this是传入的那个指定对象

如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用这个函数就说调用对象的方法(method)。

注意:方法和函数只是名称上的区别,没有其它别的区别

<script>
    //创建一个全局变量:myName
    var myName = "全局myName";

    //创建一个函数
    function sayName() {
        console.log(this);
        console.log(this.myName);
    }

    //创建一个对象
    var obj = {
        myName: "objName",
        sayMyName: sayName
    };

    //以函数的形式调用时,this永远都是window
    //  this        : Window{......}
    //  this.myName : 全局myName
    sayName();

    //以方法的形式调用时,this就是调用方法的那个对象
    //  this        : {myName: 'objName'....}
    //  this.myName : objName
    obj.sayMyName();

    // 使用构造函数来创建对象
    function Person(name, age) {
        // 设置对象的属性
        this.name = name;
        this.age = age;
        // 设置对象的方法
        this.sayName = function () {
            // 当以构造函数的形式调用时,this就是新创建的那个对象
            console.log(this);          // this         : Person {name: 'testName',......}
            console.log(this.name);     // this.name    : testName
        };
    }

    var person1 = new Person("testName", 18);
    person1.sayName();

</script>

1.7 原型(prototype, __proto__)

构造函数方法存在浪费内存的问题:
  使用构造函数的方式进行创建对象,它还是存在一个问题,每一个对象的属性不一样这是一定的,但是它的方法似乎好像是一样的,如果我创建1000个对象,那岂不是内存中就有1000个相同的方法,这就会造成浪费内存的问题。

  解决方法:我们可以把函数抽取出来,作为全局函数,在构造函数中直接引用就可以了

// 使用构造函数来创建对象
function Person(name, age) {
    // 设置对象的属性
    this.name = name;
    this.age = age;
    // 设置对象的方法
    this.sayName = sayName
}

// 把函数抽取出来为全局函数
function sayName() {
    console.log(this.name);
}

var person1 = new Person("test", 18);

person1.sayName();

但是,在全局作用域中定义函数不是一个好的办法。
  因为,如果要是涉及到多人协作开发一个项目,别人也有可能叫sayName这个方法,这样在工程合并的时候就会导致一系列的问题,污染全局作用域。
  有没有一种方法,我只在Person这个类的全局对象中添加一个函数,然后在类中引用?
答案就是使用原型对象

  • 原型(prototype):
      我们创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象,即显式原型
      原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。

  函数以普通函数的形式调用prototype时,没有任何作用
  函数以构造函数的形式调用prototype时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__(隐式原型)来访问该属性。

  • __proto__:
      对象都会有一个属性 proto 指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在。
      __proto__对象原型和原型对象 prototype 是等价的(参照下图)
      __proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
<script>
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    Person.prototype.sayName = function () {
        console.log(this.name);
    }

    Person.prototype.sayAge = function () {
        console.log(this.age);
    }

    var p1 = new Person("P1", 18);
    //构造函数.prototype
    console.log(Person.prototype);
    //对象.__proto__
    console.log(p1.__proto__);

    //两者指向相同
    if (p1.__proto__ === Person.prototype) {
        console.log("true");
    }
</script>

运行结果:
在这里插入图片描述

  • constructor 构造函数:
      对象原型(__ proto __) 和构造函数(prototype)原型对象,里面都有一个属性 constructor 属性, constructor 我们称为构造函数,因为它指回构造函数本身
      constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数
      如果有多个对象的方法,我们可以给原型对象prototype采取对象形式赋值(参照下图),但是这样会覆盖构造函数原型对象原来的内容,这样修改后的原型对象constructor就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个constructor指向原来的构造函数
<script>
    function Boy(name, age) {
        this.name = name;
        this.age = age;
    }

    Boy.prototype.sayName = function () {
        console.log(this.name);
    }

    Boy.prototype.sayAge = function () {
        console.log(this.age);
    }

    console.log(Boy.prototype);
    var John = new Boy("John", 18);

    function Girl(name, age) {
        this.name = name;
        this.age = age;
    }

    Girl.prototype = {
        sayName: function () {
            console.log(this.name);
        },
        sayAge: function () {
            console.log(this.age);
        }
    }

    console.log(Girl.prototype);

    function Girl_Fix(name, age) {
        this.name = name;
        this.age = age;
    }

    Girl_Fix.prototype = {
        sayName: function () {
            console.log(this.name);
        },
        sayAge: function () {
            console.log(this.age);
        },
        constructor: Girl_Fix
    }

    console.log(Girl_Fix.prototype);
</script>

运行结果:
在这里插入图片描述

  • 构造函数、实例、原型对象三者关系
    在这里插入图片描述

1.8 原型链

  • 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  • 如果没有就查找它的原型(也就是_proto_指向的prototype原型对象)
  • 如果还没有就查找原型对象的原型(Object的原型对象),依次类推一直找到Object为止(null)
  • __ proto __对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
<script>

    function Fruit(type, count) {
        this.type = type;
        this.count = count;

        //对象自身有,原型里也有,执行自身中的
        this.printType = function () {
            console.log("Type-1:" + this.type);
        }
    }

    Fruit.prototype.printType = function () {
        console.log("Type-2:" + this.type);
    }

    //对象自身没有,原型里有,执行原型里的
    Fruit.prototype.printCount = function () {
        console.log("Count-2:" + this.count);
    }

    var apple = new Fruit("apple", 10);
    apple.printType();
    apple.printCount();

</script>

执行结果:
在这里插入图片描述

1.9 属性/方法的存在检查

  • in方法:检查对象的自身或者原型中,某个属性/方法是否存在。
  • hasOwnProperty()方法:仅检查对象的自身中,某个属性/方法是否存在。
<script>
    // 创造一个构造函数
    function Fruit() {
    }

    // 向Fruit的原型中添加一个name属性
    Fruit.prototype.type = "ALL";

    // 创建一个Fruit的实例
    var apple = new Fruit();
    apple.cnt = 10;

    // 使用in检查对象中是否含有某个属性
    // 对象自身中有,或者原型中有,都会返回true
    console.log("cnt" in apple);    //true 仅在自身中有
    console.log("type" in apple);   //true 仅在原型中有

    // 使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
    // 使用该方法只有当对象自身中含有属性时,才会返回true
    console.log(apple.hasOwnProperty("cnt"));   //true  仅在自身中有
    console.log(apple.hasOwnProperty("type"));  //false 仅在原型中有

    console.log("-------------------");
    // Fruit类对象中没有hasOwnProperty这个方法啊,它是哪来的?
    // 就是原型中的,在执行方法的时候它会通过原型链进行查找,这个方法是Object的特有方法
    // 检查当前对象
    console.log(apple.hasOwnProperty("hasOwnProperty"));    //false
    // 检查当前对象的原型对象
    console.log(apple.__proto__.hasOwnProperty("hasOwnProperty"));  //false
    // 检查当前对象的原型对象的原型对象
    console.log(apple.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));    //true
</script>

1.10 数组

1.10.1 创建数组

  • 使用对象创建
    var arr = new Array();
    arr[0] = 1;
    arr[1] = 2;
    arr[2] = 3;
    arr[3] = 4;
    arr[4] = 5;
    arr[5] = 6;
    
  • 使用字面量创建
    var arr = [1, 2, 3, 4, 5, 6];
    

1.10.2 遍历数组

for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

1.10.3 数组方法

  1. push():向数组的末尾添加一个或多个元素,并返回数组的新的长度。

  2. pop():删除数组的最后一个元素,并将被删除的元素作为返回值返回。

  3. unshift():向数组开头添加一个或多个元素,并返回新的数组长度。

  4. shift():删除数组的第一个元素,并将被删除的元素作为返回值返回。

  5. forEach():用来遍历数组
      forEach()方法需要一个函数作为参数,像这种函数,由我们创建但是不由我们调用的,我们称为回调函数。
    数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素,以实参的形式传递进来
    我们可以来定义形参,来读取这些内容。
    浏览器会在回调函数中传递三个参数

    • 第一个参数:当前正在遍历的元素
    • 第二个参数:当前正在遍历的元素的索引
    • 第三个参数:当前正在遍历的数组

    注意:这个方法只支持IE8以上的浏览器,IE8及以下的浏览器均不支持该方法,所以如果需要兼容IE8,
    则不要使用forEach(),还是使用for循环来遍历数组。

    var arr = ["L1", "L2", "L3"];
    arr.forEach(function (value, index, array) {
        console.log(value + " ### " + index + " ### " + array);
    });
    //执行结果
    //L1 #### 0 #### L1,L2,L3
    //L2 #### 1 #### L1,L2,L3
    //L3 #### 2 #### L1,L2,L3
    
  6. slice():用来从数组提取指定元素,该方法不会改变原数组,而是将截取到的元素封装到一个新数组中并返回
    参数

    • 第一个参数:截取开始的位置的索引,包含开始索引
    • 第二个参数:截取结束的位置的索引,不包含结束索引
             第二个参数可以省略不写,此时会截取从开始索引往后的所有元素

    注意:索引可以传递一个负值,如果传递一个负值,则从后往前计算,-1代表倒数第一个,-2代表倒数第二个。

    var arr = ["L1", "L2", "L3", "L4", "L5"];
    //index:1-3的元素取得
    var result = arr.slice(1, 4);   //['L2', 'L3', 'L4'] 
    console.log(result);
    //index:3 之后所有元素取得
    result = arr.slice(3);          //['L4', 'L5']
    console.log(result);
    //index:1 到 倒数第二个之前一个元素 取得
    result = arr.slice(1, -2);      //['L2', 'L3']
    console.log(result);
    
  7. splice():用于删除数组中的指定元素,该方法会影响到原数组,会将指定元素从原数组中删除,
         并将被删除的元素作为返回值返回
    参数

    • 第一个参数:表示开始位置的索引
    • 第二个参数:表示要删除的元素数量
    • 第三个参数及以后参数:可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
    var arr = ["L1", "L2", "L3", "L4", "L5"];
    var result = arr.splice(3, 2);
    console.log(arr);       // ['L1', 'L2', 'L3']
    console.log(result);    // ['L4', 'L5']
    result = arr.splice(1, 0, "L6", "L7", "L8");
    console.log(arr);       // ['L1', 'L6', 'L7', 'L8', 'L2', 'L3']
    console.log(result);    // []
    
  8. concat():可以连接两个或多个数组,并将新的数组返回,该方法不会对原数组产生影响

  9. join():可以将数组转换为一个字符串,该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回。

    在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符,如果不指定连接符,则默认使用","作为连接符

    var arr = ["L1", "L2", "L3"];
    console.log(arr.join());    //L1,L2,L3
    console.log(arr.join("#")); //L1#L2#L3
    
  10. reverse():用来反转数组(前边的去后边,后边的去前边),该方法会直接修改原数组

  11. sort():用来对数组中的元素进行排序,会影响原数组,默认会按照Unicode编码进行排序

    对于纯数字的数组,可能会得到错误的结果,解决方案参照一下代码

    var listLetter = ["a", "d", "b", "c", "f", "e"];
    listLetter.sort();
    console.log(listLetter);    //['a', 'b', 'c', 'd', 'e', 'f']
    
    // 对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序
    // 所以对数字进排序时,可能会得到错误的结果。
    var listNumber = [1, 3, 2, 4, 10, 11];
    listNumber.sort();
    console.log(listNumber);    //[1, 10, 11, 2, 3, 4]
    
    // 解决方案:
    //   可以在sort()添加一个回调函数,来指定排序规则,回调函数中需要定义两个形参
    //   浏览器会分别使用数组中的元素作为实参去调用回调函数,具体使用哪个元素调用不确定,
    //   但是肯定的是在数组中a一定在b前边,浏览器会根据回调函数的返回值来决定元素的顺序,
    //   如下:
    //     如果返回一个大于0的值,则元素会交换位置
    //     如果返回一个小于0的值,则元素位置不变
    //     如果返回一个等于0的值,则认为两个元素相等,也不交换位置
    // 经过上边的规则,我们可以总结下:
    //   如果需要升序排列,则返回 a-b
    //   如果需要降序排列,则返回 b-a
    listNumber.sort(function (a, b) {
        return a - b;
    });
    console.log(listNumber);    //[1, 2, 3, 4, 10, 11]
    
  12. filter():筛选对象数组中符合条件的所有元素,返回一个新数组

    // filter 筛选数组
    var arr = [1, 2, 3, 10, 11, 12];
    // function(currentValue, index, array)
    var newArr = arr.filter(function (value, index) {
        return value >= 10 || index == 0;
    });
    console.log(newArr);    //[1, 10, 11, 12]
    
  13. some():用于查找数组中是否有满足条件的元素
     返回的是布尔值
      true:数组中有满足条件的元素
      false:数组中没有

    如果找到一个满足条件的元素,则终止循环,不再继续查找

    var arr = ['L1', 'L2', 'L3'];
    var flag1 = arr.some(function (value, index, array) {
        return value == 'L2';
    });
    console.log(flag1);  //true
    
    var flag2 = arr.some(function (value, index, array) {
        return value == 'L4';
    });
    console.log(flag2);  //false
    

1.11 call()和apply()

 这两个方法都是函数对象的方法,需要通过函数对象来调用,当对函数调用call()和apply()都会调用函数执行
 在调用call()和apply()将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
 call():可以将实参在对象之后依次传递
 apply():需要将实参封装到一个数组中统一传递

function fun(a, b) {
    console.log("a = " + a);
    console.log("b = " + b);
    console.log("fun = " + this);
}

var obj = {
    name: "obj",
    sayName: function () {
        console.log(this.name);
    }
};

fun(1, 2);
//运行结果:
//  a = 1
//  b = 2
//  fun = [object Window]

console.log("===============");
//call()
fun.call(obj, 3, 4);
//运行结果:
//  a = 3
//  b = 4
//  fun = [object Object]

console.log("===============");
//apply()
fun.apply(obj, [5, 6]);
//运行结果:
//  a = 5
//  b = 6
//  fun = [object Object]

1.11 arguments参数

在调用函数时,浏览器每次都会传递进两个隐含的参数:

  • this:函数的上下文对象
  • arguments:封装实参的伪数组对象
     arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
     在调用函数时我们所传递的实参都会在arguments中保存,我们即使不定义形参,也可以通过arguments来使用实参,只不过比较麻烦

    不具有数组的push(), pop()等方法
    它里边有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象。

    function fun(a, b) {
    
        // 通过下标获取第一个参数
        console.log(arguments[0]);  // A1
        // 通过下标获取第二个参数
        console.log(arguments[1]);  // A2
        // 获取实参的个数
        console.log(arguments.length);  // 2
        // callee
        console.log(arguments.callee === fun);  // true
    }
    
    fun("A1", "A2");
    

1.12 预解析

JavaScript代码是由浏览器中的JavaScript 解析器来执行的。
JavaScript解析器在运行JavaScript代码的时候分为两步:

  1. 预解析:js引擎会把js里面所有的 var 还有 function 提升到当前作用域的最前面

    • 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
    • 函数的声明会被提升到当前作用域的最上面,但是不会调用函数

      函数为函数表达式方式声明时,调用必须写在函数声明的下面

        <script>
            /* 变量提升 */
            console.log(num);  // undefined
            var num = 10;
    
            //相当于执行了以下代码
            var num;		    // 变量声明提升到当前作用域最上面
            console.log(num);
            num = 10;		    // 变量的赋值不会提升
    
            //=====================================================
            /* 函数提升 */
            fn();		        //11
            function fn() {
                console.log('11');
            }
    
            //相当于执行了以下代码
            function fn() {
                console.log('11');
            }
            fn();		        //11
    
            //=====================================================
            /* 函数表达式 */
            // 匿名函数(函数表达式方式):若我们把函数调用放在函数声明上面
            fn();
            var fn = function () {
                console.log('22'); // 报错
            }
    
            //相当于执行了以下代码
            var fn;
            fn();                   // fn没赋值,没这个,报错
            var fn = function () {
                console.log('22');  // 报错
            }
        </script>
    
  2. 代码执行:从上到下执行JS语句

学习预解析能够让我们知道为什么在变量声明之前访问变量的值是 undefined,为什么在函数声明之前就可以调用函数。

注意:

var a = b = c = 6;
=>
var a = 6; b = 6; c = 6; //若在函数申明内部,b,c为全局变量

    <script>
        f1();
        console.log(c);
        console.log(b);
        console.log(a);
        function f1() {
            // 相当于 var a = 9; b = 9;c = 9;  b和c的前面没有var声明,当全局变量看
            // 集体声明 var a = 9,b = 9,c = 9;
            var a = b = c = 9;
            console.log(a);
            console.log(b);
            console.log(c);
        }

        //相当于执行了以下操作
        function f1() {
            var a;
            a = b = c = 9;
            console.log(a);	//9
            console.log(b);	//9
            console.log(c);	//9
        }
        f1();
        console.log(c);	//9
        console.log(b);	//9
        console.log(a);	//报错 a是局部变量
    </script>

2. JavaScript DOM

2.1 console.log()和console.dir()

console.log():无法看到标签对象的属性和方法,能输出多个数据,数据类型颜色有差异。
console.dir():以对象形式输出,只能输出一个数据,不能直观识别数据类型,但是可以看到标签对象的属性和方法。

<body>
    <ul id="list">
        <li>L1</li>
        <li>L2</li>
        <li>L3</li>
    </ul>
    <script>
        var lst = document.getElementById('list');
        console.log(lst);
        console.dir(lst);
    </script>
</body>

运行结果:
在这里插入图片描述

2.2 style, currentStyle, getComputedStyle()

元素.style.样式:设置和读取的都是行内样式无法读取样式表中的样式或者说正在应用的样式,通过style属性设置的样式都是行内样式(优先级较高)
元素.currentStyle.样式:读取当前正在应用的样式属性,用来读取当前元素正在显示的样式,
  如果当前元素没有设置该样式,则获取它的默认值,但是currentStyle只有IE浏览器支持
getComputedStyle():在其它浏览器中可以使用这个方法来获取元素当前的样式,这个方法是window的方法,可以直接使用
  需要两个参数:
    第一个参数:要获取样式的元素
    第二个参数:可以传递一个伪元素,一般都传null
  该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过 对象.样式名 来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值,该方法不支持IE8及以下的浏览器。

通过currentStylegetComputedStyle()读取到的样式都是只读的,不能修改
如果要修改必须通过style属性,因此,可以写一个适配各个浏览器的读取元素样式的方法,参照以下代码

CSS的样式名中有些名称含有"-",这种名称在JS中是不合法的比如background-color,需要将这种样式名去掉-,修改为驼峰命名法

<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        /*样式表的样式*/
        #box {
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div style="width: 100px;background-color: green;" id="box"></div>

    <script>

        var box = document.getElementById("box");

        console.log(box.style.width);               //100px 取得行内样式 width: 100px;
        console.log(box.style.height);              //      行内样式不存在
        console.log(box.style.backgroundColor);     //green 转换驼峰名字
        
        box.style.width = "150px";      //变更行内样式 width: 150px;

        /*通用的获取元素样式的方法*/
        function getStyle(obj, name) {

            if (window.getComputedStyle) {
                //正常浏览器的方式,具有getComputedStyle()方法
                return getComputedStyle(obj, null)[name];
            } else {
                //IE8的方式,没有getComputedStyle()方法
                return obj.currentStyle[name];
            }
        }

        console.log(getStyle(box, "width"));
        console.log(getStyle(box, "height"));
        console.log(getStyle(box, "background-color"));
    </script>
</body>

2.3 节点

2.3.1 节点类型

节点常量名常量值节点类型
元素节点Node.ELEMENT_NODE1Element
属性节点Node.ATTRIBUTE_NODE2Attr
文本节点Node.TEXT_NODE3Text
CDATA节点Node.CDATA_SECTION_NODE4CDATASection
实体引用名称节点Node.ENTRY_REFERENCE_NODE5EntityReference
实体名称节点Node.ENTITY_NODE6Entity
处理指令节点Node.PROCESSING_INSTRUCTION_NODE7ProcessingInstruction
注释节点Node.COMMENT_NODE8Comment
文档节点Node.DOCUMENT_NODE9Document
文档类型节点Node.DOCUMENT_TYPE_NODE10DocumentType
文档片段节点Node.DOCUMENT_FRAGMENT_NODE11DocumentFragment
DTD声明节点Node.NOTATION_NODE12Notation

红色为常用的节点类型

<body>
    <ul id="ul1">
        <li id="li1">L1</li>
    </ul>
    
    <script>
        var ul1 = document.getElementById("ul1");
        console.log(ul1);                   // <ul id="ul1">...</ul> 
        console.log(ul1.nodeType);          // 1
        console.log(ul1.nodeName);          // UL
        console.log(ul1.nodeValue);         // null
        console.log("=================");

        var ul1_attr = ul1.getAttributeNode('id');
        console.log(ul1_attr);              // id="ul1"
        console.log(ul1_attr.nodeType);     // 2
        console.log(ul1_attr.nodeName);     // id
        console.log(ul1_attr.nodeValue);    // ul1
        console.log("=================");

        var ul1_fc = ul1.firstChild;
        console.log(ul1_fc);                // #text
        console.log(ul1_fc.nodeType);       // 3
        console.log(ul1_fc.nodeName);       // #text
        console.log(ul1_fc.nodeValue);      // 
        console.log("=================");

        console.log(document);              // #document
        console.log(document.nodeType);     // 9
        console.log(document.nodeName);     // #document
        console.log(document.nodeValue);    // null
        console.log("=================");
    </script>
</body>

2.3.2 节点使用

方法描述
元素节点.parentNode返回元素的父节点。
元素节点.parentElement返回元素的父元素。
元素节点.childNodes返回元素的一个子节点的数组(包含空白文本Text节点)。
元素节点.children返回元素的一个子元素的集合(不包含空白文本Text节点)。
元素节点.firstChild返回元素的第一个子节点(包含空白文本Text节点)。
元素节点.firstElementChild返回元素的第一个子元素(不包含空白文本Text节点)。(IE9以上支持)
元素节点.lastChild返回元素的最后一个子节点(包含空白文本Text节点)。
元素节点.lastElementChild返回元素的最后一个子元素(不包含空白文本Text节点)。(IE9以上支持)
元素节点.previousSibling返回某个元素紧接之前节点(包含空白文本Text节点)。
元素节点.previousElementSibling返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。(IE9以上支持)
元素节点.nextSibling返回某个元素紧接之后节点(包含空白文本Text节点)。
元素节点.nextElementSibling返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)。(IE9以上支持)
document.createElement(‘XXX’)创建’XXX’指定的HTML元素
元素节点.appendChild()将一个节点添加到指定父节点的子节点列表末尾。
元素节点.insertBefore()将一个节点添加到指定父节点的指定子节点前面。
元素节点.removeChild()将一个节点从指定父节点中删除,并返回删除的节点。
元素节点.cloneNode()返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
括号参数:空/ false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
括号参数:true ,则是深度拷贝,会复制节点本身以及里面所有的子节点

2.4 三种动态创建元素的区别

  • document.write() 是直接将内容写入页面的内容流,但是文档流执行完毕,它会导致页面全部重绘
  • innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘,创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
  • createElement()创建多个元素效率稍低一点点,但是结构更清晰

总结:不同浏览器下, innerHTML 效率要比 createElement 高

2.5 DOM文档事件

2.5.1 解决事件对象的兼容性问题

  当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数。
  Event对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标的状态。
  在IE8及以下的浏览器中,响应函数被触发时,浏览器不会传递事件对象,是将事件对象作为window对象的属性保存的。

解决方案: event = event || window.event;

 document.onkeydown = function (event) {
     event = event || window.event;
     //.....
 };

3 todo

JSON
AJAX
Cookie
WebStorage
闭包



版权声明:文章中部分文档参照了CSDN博主「轻松的小希」的原创文章
原文链接:https://blog.csdn.net/qq_38490457/article/details/109257751
版权声明:文章中部分文档参照了CSDN博主「生命是有光的」的原创文章
原文链接:https://blog.csdn.net/Augenstern_QXL/article/details/115219073

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值