• JavaScript中常见问题及解决


    1.基本语法

    1.严谨模式

    use strict

    2.undefined5种情况

    1.变量的默认值:声明未赋值

    2.数组的越界访问,值为undefined

    3.形参的默认值

    4.函数的返回值默认为undefined

    5.访问对象中不存在的属性,返回undefined(如果是方法那就要报错了)

    3.对象

    声明对象1.字面量的方法2.实例化Object() new Object()

    4.break 语句和 continue 语句

    break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行。

    break语句用于跳出代码块或循环。

    var i = 0;
    
    while(i < 100) {
      console.log('i 当前为:' + i);
      i++;
      if (i === 10) break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码只会执行10次循环,一旦i等于10,就会跳出循环。

    for循环也可以使用break语句跳出循环。

    for (var i = 0; i < 5; i++) {
      console.log(i);
      if (i === 3)
        break;
    }
    // 0
    // 1
    // 2
    // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面代码执行到i等于3,就会跳出循环。

    continue语句用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环。

    var i = 0;
    
    while (i < 100){
      i++;
      if (i % 2 === 0) continue;
      console.log('i 当前为:' + i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码只有在i为奇数时,才会输出i的值。如果i为偶数,则直接进入下一轮循环。

    如果存在多重循环,不带参数的break语句和continue语句都只针对最内层循环。

    5.标签(label)

    JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。

    label:
      语句
    
    • 1
    • 2

    标签可以是任意的标识符,但不能是保留字,语句部分可以是任意语句。

    标签通常与break语句和continue语句配合使用,跳出特定的循环。

    top:
      for (var i = 0; i < 3; i++){
        for (var j = 0; j < 3; j++){
          if (i === 1 && j === 1) break top;
          console.log('i=' + i + ', j=' + j);
        }
      }
    // i=0, j=0
    // i=0, j=1
    // i=0, j=2
    // i=1, j=0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    上面代码为一个双重循环区块,break命令后面加上了top标签(注意,top不用加引号),满足条件时,直接跳出双层循环。如果break语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环。

    标签也可以用于跳出代码块。

    foo: {
      console.log(1);
      break foo;
      console.log('本行不会输出');
    }
    console.log(2);
    // 1
    // 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上面代码执行到break foo,就会跳出区块。

    continue语句也可以与标签配合使用。

    top:
      for (var i = 0; i < 3; i++){
        for (var j = 0; j < 3; j++){
          if (i === 1 && j === 1) continue top;
          console.log('i=' + i + ', j=' + j);
        }
      }
    // i=0, j=0
    // i=0, j=1
    // i=0, j=2
    // i=1, j=0
    // i=2, j=0
    // i=2, j=1
    // i=2, j=2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上面代码中,continue命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue语句后面不使用标签,则只能进入下一轮的内层循环。

    2.数据类型

    1.null与undefined

    概述

    nullundefined都可以表示“没有”,含义非常相似。将一个变量赋值为undefinednull,老实说,语法效果几乎没区别。

    var a = undefined;
    // 或者
    var a = null;
    
    • 1
    • 2
    • 3

    上面代码中,变量a分别被赋值为undefinednull,这两种写法的效果几乎等价。

    if语句中,它们都会被自动转为false,相等运算符(==)甚至直接报告两者相等。

    if (!undefined) {
      console.log('undefined is false');
    }
    // undefined is false
    
    if (!null) {
      console.log('null is false');
    }
    // null is false
    
    undefined == null
    // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    从上面代码可见,两者的行为是何等相似!谷歌公司开发的 JavaScript 语言的替代品 Dart 语言,就明确规定只有null,没有undefined

    既然含义与用法都差不多,为什么要同时设置两个这样的值,这不是无端增加复杂度,令初学者困扰吗?这与历史原因有关。

    1995年 JavaScript 诞生时,最初像 Java 一样,只设置了null表示"无"。根据 C 语言的传统,null可以自动转为0

    Number(null) // 0
    5 + null // 5
    
    • 1
    • 2

    上面代码中,null转为数字时,自动变成0。

    但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。首先,第一版的 JavaScript 里面,null就像在 Java 里一样,被当成一个对象,Brendan Eich 觉得表示“无”的值最好不是对象。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果null自动转为0,很不容易发现错误。

    因此,他又设计了一个undefined。区别是这样的:null是一个表示“空”的对象,转为数值时为0undefined是一个表示"此处无定义"的原始值,转为数值时为NaN

    Number(undefined) // NaN
    5 + undefined // NaN
    
    • 1
    • 2

    用法和含义

    对于nullundefined,大致可以像下面这样理解。

    null表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null,表示未发生错误。

    undefined表示“未定义”,下面是返回undefined的典型场景。

    // 变量声明了,但没有赋值
    var i;
    i // undefined
    
    // 调用函数时,应该提供的参数没有提供,该参数等于 undefined
    function f(x) {
      return x;
    }
    f() // undefined
    
    // 对象没有赋值的属性
    var  o = new Object();
    o.p // undefined
    
    // 函数没有返回值时,默认返回 undefined
    function f() {}
    f() // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    对象是什么

    面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

    每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。对象可以复用,通过继承机制还可以定制。因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。

    那么,“对象”(object)到底是什么?我们从两个层次来理解。

    (1)对象是单个实物的抽象。

    一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个远程服务器连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。

    (2)对象是一个容器,封装了属性(property)和方法(method)。

    属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是哪一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。

    构造函数

    面向对象编程的第一步,就是要生成对象。前面说过,对象是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。

    典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

    JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

    构造函数就是一个普通的函数,但具有自己的特征和用法。

    var Vehicle = function () {
      this.price = 1000;
    };
    
    • 1
    • 2
    • 3

    上面代码中,Vehicle就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。

    构造函数的特点有两个。

    • 函数体内部使用了this关键字,代表了所要生成的对象实例。
    • 生成对象的时候,必须使用new命令。

    下面先介绍new命令。

    new 命令

    基本用法

    new命令的作用,就是执行构造函数,返回一个实例对象。

    var Vehicle = function () {
      this.price = 1000;
    };
    
    var v = new Vehicle();
    v.price // 1000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上面代码通过new命令,让构造函数Vehicle生成一个实例对象,保存在变量v中。这个新生成的实例对象,从构造函数Vehicle得到了price属性。new命令执行时,构造函数内部的this,就代表了新生成的实例对象,this.price表示实例对象有一个price属性,值是1000。

    使用new命令时,根据需要,构造函数也可以接受参数。

    var Vehicle = function (p) {
      this.price = p;
    };
    
    var v = new Vehicle(500);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号。

    // 推荐的写法
    var v = new Vehicle();
    // 不推荐的写法
    var v = new Vehicle;
    
    • 1
    • 2
    • 3
    • 4

    一个很自然的问题是,如果忘了使用new命令,直接调用构造函数会发生什么事?

    这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。

    var Vehicle = function (){
      this.price = 1000;
    };
    
    var v = Vehicle();
    v // undefined
    price // 1000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码中,调用Vehicle构造函数时,忘了加上new命令。结果,变量v变成了undefined,而price属性变成了全局变量。因此,应该非常小心,避免不使用new命令、直接调用构造函数。

    为了保证构造函数必须与new命令一起使用,一个解决办法是,构造函数内部使用严格模式,即第一行加上use strict。这样的话,一旦忘了使用new命令,直接调用构造函数就会报错。

    function Fubar(foo, bar){
      'use strict';
      this._foo = foo;
      this._bar = bar;
    }
    
    Fubar()
    // TypeError: Cannot set property '_foo' of undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上面代码的Fubar为构造函数,use strict命令保证了该函数在严格模式下运行。由于严格模式中,函数内部的this不能指向全局对象,默认等于undefined,导致不加new调用会报错(JavaScript 不允许对undefined添加属性)。

    另一个解决办法,构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。

    function Fubar(foo, bar) {
      if (!(this instanceof Fubar)) {
        return new Fubar(foo, bar);
      }
    
      this._foo = foo;
      this._bar = bar;
    }
    
    Fubar(1, 2)._foo // 1
    (new Fubar(1, 2))._foo // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    上面代码中的构造函数,不管加不加new命令,都会得到同样的结果。

    new 命令的原理

    使用new命令时,它后面的函数依次执行下面的步骤。

    1. 创建一个空对象,作为将要返回的对象实例。
    2. 将这个空对象的原型,指向构造函数的prototype属性。
    3. 将这个空对象赋值给函数内部的this关键字。
    4. 开始执行构造函数内部的代码。

    也就是说,构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子。

    如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

    var Vehicle = function () {
      this.price = 1000;
      return 1000;
    };
    
    (new Vehicle()) === 1000
    // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码中,构造函数Vehiclereturn语句返回一个数值。这时,new命令就会忽略这个return语句,返回“构造”后的this对象。

    但是,如果return语句返回的是一个跟this无关的新对象,new命令会返回这个新对象,而不是this对象。这一点需要特别引起注意。

    var Vehicle = function (){
      this.price = 1000;
      return { price: 2000 };
    };
    
    (new Vehicle()).price
    // 2000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上面代码中,构造函数Vehiclereturn语句,返回的是一个新对象。new命令会返回这个对象,而不是this对象。

    另一方面,如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。

    function getMessage() {
      return 'this is a message';
    }
    
    var msg = new getMessage();
    
    msg // {}
    typeof msg // "object"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上面代码中,getMessage是一个普通函数,返回一个字符串。对它使用new命令,会得到一个空对象。这是因为new命令总是返回一个对象,要么是实例对象,要么是return语句指定的对象。本例中,return语句返回的是字符串,所以new命令就忽略了该语句。

    new命令简化的内部流程,可以用下面的代码表示。

    function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
      // 将 arguments 对象转为数组
      var args = [].slice.call(arguments);
      // 取出构造函数
      var constructor = args.shift();
      // 创建一个空对象,继承构造函数的 prototype 属性
      var context = Object.create(constructor.prototype);
      // 执行构造函数
      var result = constructor.apply(context, args);
      // 如果返回结果是对象,就直接返回,否则返回 context 对象
      return (typeof result === 'object' && result != null) ? result : context;
    }
    
    // 实例
    var actor = _new(Person, '张三', 28);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    new.target

    函数内部可以使用new.target属性。如果当前函数是new命令调用,new.target指向当前函数,否则为undefined

    function f() {
      console.log(new.target === f);
    }
    
    f() // false
    new f() // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用这个属性,可以判断函数调用的时候,是否使用new命令。

    function f() {
      if (!new.target) {
        throw new Error('请使用 new 命令调用!');
      }
      // ...
    }
    
    f() // Uncaught Error: 请使用 new 命令调用!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上面代码中,构造函数f调用时,没有使用new命令,就抛出一个错误。

    Object.create() 创建实例对象

    构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.create()方法。

    var person1 = {
      name: '张三',
      age: 38,
      greeting: function() {
        console.log('Hi! I\'m ' + this.name + '.');
      }
    };
    
    var person2 = Object.create(person1);
    
    person2.name // 张三
    person2.greeting() // Hi! I'm 张三.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上面代码中,对象person1person2的模板,后者继承了前者的属性和方法。

    Object.create()的详细介绍,请看后面的相关章节。

    Window掌握:

    属性:innerWidth用来获取浏览器的宽度 innerHeight获取浏览器的高度

    方法:alert(),prompt(),open(),close()

    定时器

    1.获取元素

    2.添加事件

    3.实现功能

    倒计时实现

      var date = new Date();
      console.log(date); //Wed Jun 15 2022 22:42:49 GMT+0800 (香港标准时间)
      date = +new Date();
      date = Date.now(); //h5
      //  var last_date = new Date('2022-6-15 8:0:0')
      var last_date = +new Date('2022-6-15 22:59:0');
      console.log(date); //1655304449126
      console.log(last_date); //1655305140000
      var count = last_date - date;
      console.log(count); //609200  这是毫秒数
      // 时分秒  1时 = 60 分 = 60000ms; 1分 = 1000ms
      // h = count % 60000;
      // console.log(h);
      count = count / 1000;
      d = parseInt(count / 60 / 60 / 24);
      h = parseInt((count / 60 / 60) % 24);
      m = parseInt((count / 60) % 60);
      s = parseInt(count % 60);
      console.log(d, h, m, s);
      setInterval(() => {
        var date = Date.now(); //h5
        //  var last_date = new Date('2022-6-15 8:0:0')
        var last_date = +new Date('2022-6-15 22:59:0');
        console.log(date); //1655304449126
        console.log(last_date); //1655305140000
        var count = last_date - date;
        console.log(count); //609200  这是毫秒数
        // 时分秒  1时 = 60 分 = 60000ms; 1分 = 1000ms
        // h = count % 60000;
        // console.log(h);
        count = count / 1000;
        d = parseInt(count / 60 / 60 / 24);
        h = parseInt((count / 60 / 60) % 24);
        m = parseInt((count / 60) % 60);
        s = parseInt(count % 60);
        // console.log(d, h, m, s);
        console.log(`距离2022-6-15 22:59:0还有: ${d}${h}小时 ${m}${s}`);
        var time = document.querySelector('.count_down');
        time.innerHTML = `距离2022-6-15 22:59:0还有: ${d}${h}小时 ${m}${s}`;
      }, 1000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    事件源.事件=事件处理程序

    div.onclick=()=>{
        
    }
    
    • 1
    • 2
    • 3

    获取元素:

    document.querySelector()

    常用鼠标事件:

     onclick 点击
    
     onmouseover 鼠标进过
    
     onmouseout 鼠标离开
    
     onfocus 获得焦点
    
     onblur 失去焦点
    
     onmousemove 鼠标移动
    
     onmouseup  鼠标弹起
    
     onmousedown 鼠标按下
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    操作元素:

    操作内容:

      var one = document.querySelector('.one');
      // 获取元素内容
      console.log(one.innerHTML);
      // 设置新的内容
      one.innerHTML = '

    文本

    '
    ; one.innerText; console.log(one.innerText); one.innerText = '

    文本

    '
    ; // innerHTML 可以获取元素对象内容 设置元素对象内容 可以识别标签 // innerText 可以获取元素对象内容 设置元素对象内容 不识别标签
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    操作html属性(html上的属性)

      // html常见属性  (标签上的常见属性)
      /* 
      id class ...
      src,href,title,alt...
      表单中: type,placeholder,value,checked,selected
      */
      /* 操作html
     1.获取属性值
     2.操作属性值
     */
      //  获取元素
      var one = document.querySelector('[type=text');
      console.log(one);
      // 1.获取属性值  对象.属性名
      console.log(one.type); //text
      // 2.设置属性值 对象。属性名= 值
      one.placeholder = '请输入用户名';
      one.type = 'password';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    非标准属性(自定义属性)
          <span class="two" two="1"></span>
     
    
    
      var two = document.querySelector('.two');
      console.log(two);
      // 设置自定义属性的值
      two.setAttribute('two', '123');
      console.log(two);
      // 获取自定义属性的值
      two.getAttribute('two');
      console.log(two.getAttribute('two'));
      // 移除自定义属性
      two.removeAttribute('two')
      console.log(two);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    操作CSS样式:

    单独设置:元素.style.css属性名= css属性值(小驼峰)

     // 操作css样式
      // 单独设置
      // 元素.style.css属性名= css属性值(小驼峰)
      var text = document.querySelector('.text');
      console.log(text);
      // 只获取一个元素
      text.style.color = 'red';
      // 如果有多个元素  就得 元素[key]
      var textAll = document.querySelectorAll('.text');
      textAll[0].style.fontSize = '30px';
      textAll.forEach((item, index) => {
        console.log(index);
        console.log(item);
        item.style.backgroundColor = 'pink';
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    批量操作:

    增加类名:classList.add(‘text1’),

    移除类名:classList.remove(‘text1’)

      // 操作css样式
      // 单独设置
      // 元素.style.css属性名= css属性值(小驼峰)
      var text = document.querySelector('.text');
      console.log(text);
      // 只获取一个元素
      text.style.color = 'red';
      // 如果有多个元素  就得 元素[key]
      var textAll = document.querySelectorAll('.text');
      textAll[0].style.fontSize = '30px';
      textAll.forEach((item, index) => {
        console.log(index);
        console.log(item);
        item.style.backgroundColor = 'pink';
      });
      // 批量
      console.log(textAll[0].dir);
      textAll[0].classList;
      console.log(textAll[0].classList);
      textAll[0].classList.add('text1');
      textAll[0].classList.add('text2');
      console.log(textAll[0].classList);
      textAll[0].classList.remove('text1');
      console.log(textAll[0].classList);
    
      textAll.forEach((v, i) => {
        // 添加类
        v.classList.add('one');
        console.log(textAll[i]);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    BOM:浏览器对象模型

    BOM对象;
      innerWidth, innerHeight;
      // 定时器
    
      setInterval(() => {
        // 函数  回调函数
      }, 时间);
      clearInterval(定时器名字);
      window.setTimeout(() => {
        回调;
      }, time);
      clearTimeout(定时器名字);
      window.document;
      window.history;
      indow.location; //(地址对象)
      window.screen; //屏幕对象
      window.console; //控制台对象
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    仿JD密码框
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
          .box {
            position: relative;
            width: 400px;
            border-bottom: 1px solid #ccc;
            margin: 100px auto;
          }
          .box img {
            position: absolute;
            top: 2px;
            right: 2px;
          }
          .box input {
            width: 370px;
            height: 30px;
            border: 0;
            /* 鼠标点击的时候没有边框 */
            outline: none;
          }
        </style>
      </head>
      <body>
        <div class="box">
          <input type="password" placeholder="请输入密码" />
          <img src="./img/close.png" alt="" width="20px" />
        </div>
    
        <!-- <img src="./img/open.png" alt="" /> -->
      </body>
    </html>
    <script>
      // 获取元素
      var ipt = document.querySelector('input');
      var img = document.querySelector('img');
      var focus = 1;
      // 添加事件
      img.onclick = () => {
        if (focus == 1) {
          img.src = './img/open.png';
          ipt.type = 'text';
          focus = 0;
        } else if (focus == 0) {
          img.src = './img/close.png';
          ipt.type = 'password';
          focus = 1;
        }
      };
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    排他思想

      var lis = document.querySelectorAll('li');
      // 用let声明变量 let有局部作用域
      // 或者使用forEach
      for (let i = 0; i < lis.length; i++) {
        console.log(i);
        lis[i].onclick = function () {
          // 让所有人的元素都恢复为默认状态  干掉其他人
          // console.log(lis[i]);
          for (let j = 0; j < lis.length; j++) {
            // const element = lis[j];
            lis[j].classList.remove('item');
            // lis[j].style.backgroundColor = '#000';
            // lis[j].style.color = '#fff';
          }
          console.log(i);
          // lis[i].style.backgroundColor = '#ff6700';
          // lis[i].style.color = 'blue';
          // 给当前元素添加选中状态   留下我自己
          lis[i].classList.add('item');
        };
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
      var lis = document.querySelectorAll('li');
      console.log(lis);
    
      for (let i = 0; i < lis.length; i++) {
        lis[i].onmouseover = () => {
          for (let j = 0; j < lis.length; j++) {
            lis[j].classList.remove('pink');
          }
          lis[i].classList.add('pink');
        };
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    DOM节点操作

     var h1 = document.querySelector('h1')
      console.log(h1);
      // 属性
      
      var one = h1.parentNode
      console.log(one);
      console.log();
      var all = one.childNodes
      console.log(all);
      console.log(one.childNodes[1]);
      console.log(one.children);//HTMLCollection(7) [h1, p, span, a, ul, script, script]   *****
      console.log(one.firstChild);
      console.log(one.firstElementChild);//返回第一个子元素节点  找不到 就返回 null     ******  这俩有兼容性 IE9+
      console.log(one.lastElementChild);//返回最后一个子元素节点  找不到返回 null       ******
      console.log(one.children[0]);
      console.log(one.children[one.length - 1]);
      
      one.nextSibling  //下一个兄弟 所有节点
      
      console.log(h1.nextElementSibling);//h1的下一个兄弟元素节点
      var h2 = document.createElement('h2')  //动态创建元素节点   参数是'标签名'
      console.log(h2);
      // 添加内容 属性  样式 等
      h2.innerHTML = '我是h2'
      h2.style.color = 'red'
      document.body.appendChild(h2)   //  在某个节点中 插入节点 在末尾插入
      document.body.insertBefore(h2,h1) // insertBefore(插入内容,指定元素)  把插入内容  插入到 指定元素之前  ***********************
        // 创建元素之后并没有插入到页面中
                        // 节点包括  元素节点 属性节点 文本节点 注释节点
      /*
      父节点  h1.parentNode
      对象.parentNode (最近的父节点)
      子节点   父节点.parentNodes
      返回所有的子节点 包括元素节点和文本节点等
      父节点.children  获取所有的元素节点
      one.children
      父节点.firstElementChild  获得第一个子元素节点
      兄弟节点
      */
                          // 方法
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    事件委派

      /* 
      事件三要素 事件 事件源 事件处理函数
      面试题 new关键字  作用域连 js事件监听的兼容性问题
      注册事假你的方式 on+type,事件监听(兼容性问题)
      事件流  捕获阶段(从顶向上 )div.addEventListener('click',function name(params) {
      
    },true)
      处理阶段 
      冒泡阶段 on+type  add true
      事件对象 鼠标  键盘 
      事件委派:冒泡 的应用  
      // 事件委派 操作dom一次 添加到ul(父元素)中
        将事件添加到父元素身上,通过e.target判断
        事件委派 应用场景:()
        1.大量元素添加事件 你就要进行若干次的dom操作  为了提高性能减少DOM操作  就要委派
        2.动态创建的元素   如果不刷新就不重新获取元素  就获取不到元素   
      */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    事件流的三个阶段 :捕获阶段,目标阶段,冒泡阶段

    捕获型事件流:从顶层元素开始,逐级向下,直到最具体的元素

    addEVentListener(‘‘事件’’,函数,true)

    冒泡型事件流:从最具体的元素开始 逐级向上执行 直到顶层元素

    on+Type,addEVentListener(‘‘事件’’,函数,false)

    阻止冒泡

      var father = document.querySelector('.father')
      var son = document.querySelector('.son')
      father.addEventListener('click', () => {
        console.log(father);
        console.log('father');
      })
      // son.onclick = () => {
      //   console.log(son);
      //   console.log('son');
      // }
      son.addEventListener('click', (e) => {
        e.stopPropagation() //阻止冒泡
        console.log('son');
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skHQ5Do4-1658243579335)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20220618105247690.png)]

    this指向

    * 1.任何情况下直接在script中写入的this都是window。 
    * 2.函数中的this  非严格模式:this指向window,  严格模式时:this指向undefined。
    * 3.箭头函数的this
     this都指向箭头函数外上下文环境的this指向
    * 4.对象中this
     对象属性的this 指向对象外上下文环境的this
      对象方法(普通函数)中的this,指向当前对象(谁执行该方法,this就指向谁)
    * 5.回调函数的this指向
        * 1)、 setTimeout,setInterval回调函数不管是否是严格模式都会指向window。  
        * 2)、通过在函数内执行当前回调函数  	 非严格模式:this指向window,  	 严格模式时:this指向undefined。 
        * 3)递归函数中的this  	 非严格模式:this指向window,  	 严格模式时:this指向undefined。 
        * 4)   使用arguments[0]()执行函数时  	 	 this指向arguments。
        * 5)事件中的回调函数,this指向事件侦听的对象(e.currentTarget);
    * 6、call,apply,bind方法执行时this的指向 
        * 如果call,apply,bind传参时,第一个参数传入的不是null或者undefined,传入什么this指向什么
        * 如果第一个参数传入的是null或者undefined ,非严格模式下指向window   
    
    * 7、在ES6的类中this的指向
        * 构造函数中的this指向实例当前类所产生的新的实例对象      
        * 类中实例化方法中this指向谁执行该方法,this指向谁      
        * 类中静态方法中this执行该类或者该类的构造函数      
        * 类中实例化箭头方法,this仍然指向当前类实例化的实例对象
    * 8、ES5的原型对象中this的指向
         * 在原型的方法中,this指向实例化当前构造函数的实例化对象(谁执行该方法,this指向谁); 
         * 三种改变this指向的方式  
            * 函数名.call(this,....)this写谁就指谁。
            * 函数名.apply(this,[参数1,参数2,...]) this写谁就指谁。
            * 函数名. bind (this,1,2,3) this写谁就指谁。 
     * 构造函数中的this指向实例当前类所产生的新的实例对象      
        * 类中实例化方法中this指向谁执行该方法,this指向谁      
        * 类中静态方法中this执行该类或者该类的构造函数      
        * 类中实例化箭头方法,this仍然指向当前类实例化的实例对象、
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
      // 1.全局作用域 普通函数
      console.log(this);
    
      function fn() {
        console.log(this);
    
      }
      fn()
      // 在方法调用中 谁使用就指向谁
      div = document.querySelector('div')
      div.onclick = function () {
        console.log(this); //
    点击
    } // 3.构造函数 this 指向构造函数的实例化的那个对象 function Cup(size) { this.size = size console.log(this); //Cup {size: '1000'} } var myCup = new Cup('1000')
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Ajax发送请求

    1.get请求

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Ajax
    
      </title>
      <style>
        div {
          width: 200px;
          height: 200px;
          border: 1px solid #000;
          background-color: pink;
        }
      </style>
    </head>
    
    <body>
      <button>点击</button>
      <div>
    
      </div>
    </body>
    
    </html>
    <script>
      var btn = document.querySelector('button')
      var div = document.querySelector('div')
      btn.onclick = function () {
        // console.log(1);
        // 1.穿件对象
        var xhr = new XMLHttpRequest()
        // 2.初始化 设置请求类型和请求地址
        // 如果有参数
        xhr.open('GET', 'http://127.0.0.1:8080/server?username=123')
        // xhr.open('GET', 'http://127.0.0.1:8080/server')
        // 3.发送请求
        xhr.send()
        // 4.绑定事件进行监听  处理服务端返回的结果(响应报文)
        // readystate 是xhr身上的一个属性,记录了客户端向服务器发送请求的状态
        // 0 为初始化 1 完成open 2send  3服务器数据部分返回  4服务器数据全部返回
        xhr.onreadystatechange = function () {
          // 服务器全部返回了结果
          if (xhr.readyState == 4) {
            // 判断响应的状态码status
            if (xhr.status == 200) {
              // 响应报文  响应行(状态码  状态描述) 响应头 响应体
              console.log(xhr.status); //状态码
              console.log(xhr.statusText); //状态描述
              xhr.response
              console.log(xhr.response); //响应体
              // 发生了跨越问题(同源策略:协议域名端口号全部一致)  解决跨域
    
              div.innerHTML = xhr.response
            }
          }
        }
    
      }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    Ajax解决跨域问题

    app.get('/server', (req, res) => {
      /* 解决跨域问题 设置响应头允许跨域访问 */
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.send('server-get');
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.post请求

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        div {
          height: 200px;
          width: 200px;
          background-color: pink;
        }
      </style>
    </head>
    
    <body>
      <button>post</button>
      <div></div>
    </body>
    
    </html>
    <script>
      var btn = document.querySelector('button')
      var div = document.querySelector('div')
      // onmouseenter
      btn.onclick = function () {
        // 穿件对象
        var xhr = new XMLHttpRequest()
        xhr.open('post', 'http://127.0.0.1:8080/server')
    
        // 设置请求头  客户端告诉浏览器实际发送的内容
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    
        // 通过xhr.send发送数据
        xhr.send('username="zs"&password=12456')
        xhr.onreadystatechange = function () {
          // 传完数据
          if (xhr.readyState == 4) {
            // 服务器响应成功
            if (xhr.status == 200) {
              div.innerHTML = xhr.response
              var res = JSON.parse(xhr.response)
              console.log(res.code);
              console.log(res.msg);
            }
          }
        }
      }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    index.js

    const express = require('express');
    const app = express();
    // 配置内置中间件解析post的请求数据
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.get('/server', (req, res) => {
      /* 解决跨域问题 设置响应头允许跨域访问 */
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.send('server-get');
    });
    app.post('/server', (req, res) => {
      console.log(req.body);
      /* 解决跨域问题 设置响应头允许跨域访问 */
      res.setHeader('Access-Control-Allow-Origin', '*');
    
      //我想返回一个数据
      var data = { code: 1, msg: '请求成功' };
      JSON.stringify(data);
      res.send(JSON.stringify(data));
      // res.send('server-post');
      // 配置post解析数据之后    返魂一个空对象 ,需要给他一个请求头信息
      // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
      //
    });
    app.listen(8080, () => {
      console.log('http://127.0.0.1:8080');
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    post请求注意事项

    /*
      post请求注意事项 
      1.所请求的路由必须在路由中注册才可以
      2.要解决跨域问题  
      res.setHeader('Access-Control-Allow-Origin', '*');
      3.在html页面中 请求的数据要存在 xhr.send('username="admin"&password=12456')
      4.在html要设置请求头部信息  一般是xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
      5.用Ajax异步发请求   
       xhr.onreadystatechange = function () {
          if (xhr.readyState == 4) {
            if (xhr.status == 200) {
              div.innerHTML = xhr.response
              var res = JSON.parse(xhr.response)
              console.log(res);
              console.log(res.code);
              console.log(res.msg);
            }
          }
        }
        6.readyState
        ajax.readyState:
        0 - (未初始化)还没有调用send()方法
        1 - (载入)已调用send()方法,正在发送请求
        2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
        3 - (交互)正在解析响应内容
        4 - (完成)响应内容解析完成,可以在客户端调用了
        7.HTTP 状态码 ajax.status
        101——客户要求服务器根据请求转换HTTP协议版本
        200——交易成功
        304——客户端已经执行了GET,但文件未变化
        306——前一版本HTTP中使用的代码,现行版本中不再使用
        400——错误请求,如语法错误
        404——没有发现文件、查询或UR
        405——用户在Request-Line字段定义的方法不允许
        500——服务器产生内部错误
        505——服务器不支持或拒绝支请求头中指定的HTTP版本
        7.JSON数据的传输  服务器传给页面要传字符串格式的JSON数据  
        然后页面反序列为对象格式数据从而使用
    */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    路由中配置静态文件和模板引擎 配置路由body

    //导入ejs和
    const ejs = require('ejs');
    const path = require('path');
    
    
    // 配置静态文件
    app.use(express.static('static'));
    // 配置模板引擎
    // 设置模板存储的位置
    app.set('views', path.join(__dirname, 'views'));
    // 设置模板存储位置
    app.set('view engine', 'html');
    // 使用ejs模板引擎解析
    app.engine('html', require('ejs').renderFile);
    
    
    // 配置路由body
    app.use(express.urlencoded({ extended: false }));
    app.use(express.json());
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    本科阶段学习方向的建议
    谈谈数据分析晓知识
    Xxl-job安装部署以及SpringBoot集成Xxl-job使用
    机器学习算法(1) 基础入门
    C#11 file关键字
    Kong:高性能、插件化的云原生 API 网关 | 开源日报 No.62
    《中国垒球》:跨界互动·全明星赛
    什么是 CSRF 、原理及其解决方式
    【银河麒麟V10】【桌面】火狐浏览器设置主页不生效
    各种文件后缀的意义(持续更新中)
  • 原文地址:https://blog.csdn.net/w1404273025/article/details/125883077