20:JavaScript详解 || 足够好的雕塑仍需要注入灵魂

JavaScript详解


一、什么是JavaScript

JavaScript:是一种弱类型脚本语言,其源代码不需要经过编译,是一门世界上最流行的脚本语言。和Java没有半毛钱关系。是一个大牛因为不喜欢Java,所以用了10天设计出来的。

一个合格的后端人员,必须要精通JavaScript,了解<熟悉<掌握<精通

ECMAScript可以理解为是JavaScript的一个标准,最新版本已经到es6版本,但是大部分浏览器还只停留在支持es5的版本。所以开发环境和线上环境是版本不一致的。


二、快速入门

1. 引入JavaScript

  1. 内部标签

    <script>
        //注释跟java的一样
    </script>
    
  2. 外部引入

    abc.js文件

    alert("Hello,World!")
    

    test.html文件

    <script src="abc.js"></script>
    
  3. 测试代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    <!--script标签内,写JavaScript代码,后面简称JS-->
    </head>
    <body>
    
    <!--放在body最底部最好,这是内部引入-->
    <!--    <script>-->
    <!--        alert("hello,world");-->
    <!--    </script>-->
    <!--外部引入,切记不要自闭合标签,成对闭合,不然容易出问题-->
    <script src="js/qj.js"></script>
    <!--不用显示定义type,默认就是JavaScript-->
    <script type="text/javascript">
    
    </script>
    </body>
    </html>
    

2. 基本语法入门

  1. 浏览器必备调试须知(中英对照,F12一键打开审查元素):

    image-20220307214843126

    image-20220307214921572

    • element:元素审查,常用来查看html源代码或调颜色间距等等

    • Console:常用来打印一些数据的值,查看代码运行过程中值的变化

    • Sources:有代码存放的目录,可以打断点,用来一步步调试代码

    • Network:用来抓包等等

    • 其他的后边用到再说

  2. 基本语法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<!--    但是 JS 严格区分大小写-->
  <script>
    // 1. 定义变量  一切的变量都叫var
    var name = "dearliu";
    var age = 21;
    // alert(name);
    var score = 85;
    "1234545";// 这都是一条完整的语句,离谱!
    if (score > 90){
       alert("优秀");
    }else if (score > 60 && score <= 90){
        alert("及格");
    }else if (score < 60){
        alert("不及格");
    }

    //console.log(score) 在浏览器的控制台打印变量! 相当于Java中的System.out.println();
  </script>
</head>
<body>
</body>
</html>

3. 数据类型简述

数值、文本、图形、音频、视频...

变量

不能以数字开头,可以使用美元符 字母 下划线开头,中文也可以 但不建议

 	//不加var,不管是定义在函数内还是定义在函数外都 默认是全局变量
    i = 1;
    //加上var之后,定义在函数外就是全局变量,定义在函数内就是局部变量
    var i = 1;
    //局部变量   ES6之后  使用let声明局部变量  严格检查模式
    let i = 1;

number:js不区分小数和整数,统一用Number

123//整数123
123.1//浮点数123.1
1.123e3//科学计数法
NaN //not a number
Infinity //表示无限大

字符串

‘abc’ “abc”

布尔值

true false

逻辑运算

&&  两个都为真,结果为真
||  一个为真,结果为真
! 真变假,假变真

比较运算符

=
== 等于(类型不一样,值一样,也会判断为true)
=== 绝对等于(类型一样,值一样,结果为true) 坚持使用===

需要知道:

  • NaN===NaN,返回值为false,NaN与所有的数值都不相等,包括自己
  • 只能通过isNaN(NaN)来判断这个数是否是NaN

浮点数问题:

console.log((1/3) === (1-(2/3)));

尽量避免使用浮点数进行运算,存在精度

console.log(Math.abs(1/3 - (1-(2/3)) < 0.00000001));

null和undefined

  • null 空
  • undefined 未定义

数组

Java中数组必须是一系列相同类型的对象,js中不需要这样

var arr = [1,2,3,4,5,'hello',null,true]

new Array(1,12,3,4,5,'hello')

取数组下标:如果越界了,就会undefined

对象

对象是大括号,数组是中括号

每个属性之间使用逗号隔开,最后一个不需要添加逗号

//Person person = new Person(1,2,3,4,5);
var person = {
    name:"liu",
    age:3,
    tags:['js','java','web','...']
};

取对象的值:

image-20220320151925841

4. 严格检查模式

必须要保证IDEA支持ES6 语法image-20220320154211035

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script>
      //前提:IDEA需要设置支持ES6 语法
      //'use strict' 严格检查模式,预防js的随意性导致产生的一些问题
      //必须写在JavaScript的第一行,写在其他地方是没有用的
      // 局部变量建立使用let去定义
      'use strict';
    //不加var,不管是定义在函数内还是定义在函数外都 默认是全局变量
    i = 1;
    //加上var之后,定义在函数外就是全局变量,定义在函数内就是局部变量
    var i = 1;
    //局部变量   ES6之后  使用let声明局部变量
    let i = 1;

  </script>
</head>
<body>

</body>
</html>

三、数据类型详细讲解

1. 字符串

  1. 正常字符串,我们使用单引号''或者双引号""包裹

  2. 注意使用转义字符,比如要打印单引号或者双引号 ,转义字符必须在字符串包裹内

    \'
    \n
    \t
    \u4e2d  unicode字符 \u####
    \x41 AscII字符
    
  3. 多行字符串编写

    tab键上边的反引号``

    var msg = `hello 
            world
            nihao
            你好
            `
    
  4. 模板字符串

    let name = "liu";
    let age = 3;
    let msg = `你好呀,${name},${age}`
    
  5. 字符串长度

    var student = "this is a student";
    student.length;
    student[0];
    student[0] = 1; //赋值失败 String字符串是不可变的
    student.toUpperCase()
    
  6. 字符串的可变性 不可变

    var student = "this is a student";
    student[0];
    student[0] = 1; //赋值失败 String字符串是不可变的
    
  7. 大小写转换

    //这里是方法不是属性
    student.toUpperCase()
    student.toLowerCase()
    
  8. 获取指定字符的下标

    student.indexOf('u')
    
  9. 截取两个下标之间的字符串,含头不含尾

    student.substring(1,3) //截取第一个字符串和第三个字符串之间的内容 不包含第三个
    student.substring(0) //从第0个字符串截取到最后一个字符串   
    

2. 数组

Array可以包含任意的数据类型

var arr = [1,3,4,5,6];
//通过下标取值和赋值
arr[0];
arr[0] = 1;

  1. 长度

    arr.length
    

    注意:假如给arr.length 赋值,数组的大小就会发生变化,如果赋值过小,会导致后边的元素丢失,如果赋值大了,会在后边出现很多undefined元素。

  2. indexOf

    arr.indexOf(2)  //获得2这个元素的下标
    

    字符串的“1” 和数字1返回值是不同的

  3. slice() 截取Array的一部分,返回一个新数组,类似于String中的substring

    arr.slice(3)  //从下标为3的值截取到最后一个
    arr.slice(2,5) //包头不包尾的截取下标为2到下标为5之间的值
    
  4. push() , pop() 尾部操作

    arr.push('a','b') //在最后面添加元素,压入到尾部
    arr.pop() //从最后往外弹出元素 ,从尾部弹出
    
  5. unshift() , shift() 头部操作

    arr.unshift() //压入到头部
    arr.shift() //弹出头部的一个元素
    
  6. 排序 sort()

    arr.sort() //对数组中的元素进行排序
    
  7. 元素反转

    arr.reverse()  //将元素进行反转 第一个换到最后一个,最后一个换到第一个 以此类推
    
  8. concat() 拼接

    arr.concat()  //返回一个新数组 原来的arr数组并没有发生修改,参数为一个数组  返回值为两个数组凭借的新数组
    
  9. 连接符 join

    arr.join('-') // 使用小短线- 将arr数组中的值连接起来
    
  10. 多维数组

    arr1 = [[1,2],[2,4],['d','v']];
    arr1[1][1]  //4
    
  11. fill() 填充

  12. find() 比如一个1-10的数组a,可以a.find(函数名),而这个函数式判断大于5的,会返回该数组中大于5的值

数组:存储数据(如何存,如何取,方法都可以自己实现!)

3. 对象

若干个键值对

var person = {
    属性名:属性值,
    属性名:属性值,
    属性名:属性值
}

定义了一个person对象,有四个属性

var person = {
    name:"liu",
    age: 3,
    email:"laxsilence@vip.qq.com",
    score:99
}

js中的对象,使用{}包裹起来,键值对描述属性,多个属性之间使用逗号隔开,最后一个属性不加逗号!

js中的所有的键都是字符串,值是任意的对象!

person["age"]  //会打印出来age的值
  1. 赋值

    person.name = "dearLiu"
    
  2. 使用一个不存在的对象属性,不会报错!undefined

    person.haha //haha是不存在的属性
    
  3. 动态的删减属性,使用delete删除对象的属性

    delete person.name
    
  4. 动态的添加 直接给新的属性添加值就可以了

    person.haha = "haha"
    
  5. 判断属性值是否在这个对象中 xxx in xxx!

    'age' in person  //会打印出true
    'toString' in person //会打印出true  继承 找到父类的方法
    
  6. 判断一个属性是否是对象自身拥有的 hasOwnProperty()

    person.hasOwnProperty('toString') //false
    person.hasOwnProperty('age')//true
    

4. 流程控制

  1. if 判断

    'use strict';
    var age = 3;
    if (age > 3){
        alert("haha");
    }else if(age < 5){
        alert("kuwa");
    }else{
        alert("heihei");
    }
    
  2. 循环,避免程序死循环

    var li = 5;
    while (li<100){
        li = li + 1;
        console.log(li)
    }
    
    //死循环
    while(true){
        alert("就是关不掉!");
    }
    
    //do while
    do{
        age = age + 1;
        console.log(age);
    }while(age < 100)
    
  3. for循环

    for (let i = 0; i < 100; i++) {
        console.log(i);
    }
    
  4. 遍历数组forEach循环 ES 5.1

    var arr = [12,23,3,54,65,67,67,123];
    arr.forEach(function (value){
        console.log(value);
    })
    
  5. for ... in ...

    for(var num in arr){//这里num是索引
        console.log(num)//打印出索引,要打印值得话:age[num]
    }
    
    for(var num of arr){//这里num是值
        console.log(num)//打印出值
    }
    

5. Map 和 Set

ES6 的 新特性。

  1. Map

    'use strict';
    //ES6
    //学生的成绩,学生的名字
    var names = ["tom","jack","haha"];
    var scores = [100,90,80];
    // ES6 Map集合
    var map = new Map([['Tom',100],['Jack',90],['haha',80]]);
    var name = map.get('Tom');//通过key获得value
    map.set('admin',123456);//新增或修改
    map.delete('Tom');//删除
    console.log(name);
    
  2. Set,无序不重复

    var set = new Set([3,1,1,1,1]);//set 可以去重
    set.add(2);//添加
    set.delete(1);//删除
    console.log(set.has(3))//是否包含某个元素
    

6. Iterator 迭代器

对象的成员可以遍历,是因为该对象实现了Iterator 接口。

迭代器对象本质上,就是一个指针对象。通过指针对象的next(),用来移动指针。

【迭代器协议】对象必须提供一个next(),执行该方法要么返回迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代。

next()返回一个对象,表示当前数据成员的信息。这个对象具有value和done两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next()。对于遍历器对象来说,done: false和value: undefined属性都是可以省略的。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性上。

原生具备 Iterator 接口的数据结构如下。

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象
  1. 遍历数组:

    //通过for of实现,for in 是下标,还支持set和map 不光是数组
    var array1 = [3,4,5];
    for (var x of array1){
        console.log(x);
    }
    
  2. 遍历Map:

    var map1 = new Map([['Tom',100],['Jack',90],['haha',80]]);
    for (let x of map1){
        console.log(x);
    }
    
  3. 遍历Set

    var set = new Set([5,6,7]);
    for(let x of set){
        console.log(x);
    }
    

四、函数

1. 定义函数

假设定义一个绝对值函数

定义方式1:

function abs(x){
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

一旦执行到return,代表函数结束,返回结果!如果不传参数或者没有执行return,函数执行完也会返回结果,结果就是undefined或者NaN。

定义方式2:

var abs = function(x){
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

这是一个匿名函数,但是可以把结果复制给abs,通过abs就可以调用函数!方式一和方式二等价。

还可以发现:方法也可以当做一个对象,即后面这个方法是名为abs的对象。

2. 调用函数

abs(10) //10
abs(-10) //10

参数问题:js可以传任意个参数,但是会看形式参数的个数,只写了一个就只执行一个实参,即第一个参数。js也可以不传递参数。

假设参数没有传递进去,要怎么解决不报错问题:

var abs = function(x){
    if(typeof x != "number"){
        throw "not a Number";
    }
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

手动判断参数是否是一个数字,如果不是就抛出异常。

假如存在多个参数,如何解决:

arguments是一个js自带的关键词,代表传递进来的所有参数,是一个数组。

var abs = function(x){
    console.log("x=>" + x);
    for(var i = 0;i < arguments.length;i++){
        console.log(arguments[i]);
    }
    if(arguments.length > 1){
        arguments[1];//可以拿到第二个参数
    }
    //或者
    if(arguments.length == 2){
        
    }else if (arguments.length == 3){
        
    }
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

但是仍然有一个问题:arguments包含所有传进来的参数,我们有时候想使用多余的,未被定义为形式参数的参数来进行附加操作,需要排除已有的参数。比如我是这个函数的调用者,我在调用的时候传递了6个参数进去,但是这个函数的开发者定义的形式参数有几个我是不知道的,所以我想用除了他定义的形式参数外的其他几个参数,但是这样的参数到底有几个是不确定的。

以前:

function aaa(a,b){
    console.log("a=>" + a);
    console.log("b=>" + b);
    if(arguments.length > 2){
        for (var i = 2;i<arguments.length;i++){
            
        }
    }
}

ES6 参数 rest

获取除了已经定义的参数之外的所有参数。

function aaa(a,b,...rest){
    console.log("a=>" + a);
    console.log("b=>" + b);
    console.log(rest);
    if(arguments.length > 2){
        for (var i = 2;i<arguments.length;i++){
            
        }
    }
}

会发现这部分参数,全部被放到了rest这个数组中。需要将...rest写在参数的最后。

3. 变量的作用域

在js中,var定义的变量实际是由作用域的。假设在函数体中声明,则在函数体外不可以使用,那假设我非要在函数体外使用呢,需要用到(闭包),后续再说。

    "use strict";
  function qj(){
      var x = 1;
      x = x + 1;
  }
  x = x + 2;//js这个随意的语言第一次报错:Uncaught ReferenceError : x is not defined
  1. 如果两个函数使用了相同的变量名,只要在函数内部,就不冲突。

    function qj(){
        var x = 1;
        x = x +1;
    }
    function qj(){
        var x = 'A';
        x = x + 1;
    }
    
  2. 内部函数可以访问外部函数的成员,反之则不行。

    function qj(){
        var x = 1;
        //内部函数可以访问外部函数的成员,反之则不行
        function qj2(){
            var y = x + 1;
        }
        var z = y + 1; //Uncaught ReferenceError : y is not defined
    }
    
  3. 假设内部函数变量和外部函数变量重名:在js中,遵循就近原则,函数查找变量从自身函数开始,由内向外查找。里面找到了直接用,里面没找到就从外面找。

    function qj(){
        var x = 1;
        function qj2(){
            var x = 'A';
            console.log('inner' + x); //inner A
        }
        console.log('outer' + x); //outer 1
        qj2();
    }
    qj();
    
  4. 提升变量的作用域:

    function qj(){
        var x = "x" + y;
        console.log(x);//y undefined。
        var y = 'y';
    }
    //这段代码等价于下面这段
    function qj2(){
        var y;
        var x = 'x' + y;  
        console.log(x);//所以说y是undefined
        y = 'y';
    }
    

    运行结果:xundefined注意:这里代码是‘x’+y,所以是y is undefined,而不是x is undefined说明:js执行引擎,自动提升了y的声明,但是不会提升变量y的赋值!所以写js的时候有多少个变量直接全部写在最前面:

    var x,y,z,...;//会把所有变量提到最前面写,只有var可以,在js建立之初就存在
    
  5. 全局变量:

    var x = 1;
    function f(){
        console.log(x);
    }
    f();
    console.log(x);
    
  6. 全局作用域 window

    var x = 'xxx';
    alert(x);
    window.alert(x);//等价于上边的
    alert(window.x);//默认所有的全局变量,都会自动绑定在window对象下
    

    发现alert()这个函数本身也是一个window变量

    var x = "xxx";
    window.alert(x);
    var old_alert = window.alert; 
    old_alert(x);
    //弹窗弹两次
    
    window.alert = function(){
    };
    window.alert(123);
    //发现弹窗失效了,因为alert被重写了
    //恢复
    window.alert = old_alert;
    window.alert(123);
    

    js实际上只有一个全局作用域,都被绑定在window下,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,最终查找到window下。如果在全局作用域都没有找到,就会报错RefrenceError

    由于我们所有的全局变量都会绑定在我们的window上,如果不同的js文件,使用了相同的全局变量,就会发生冲突。那么如何减少冲突。所以会写一个只属于自己的全局变量,凡是自己用到的,想当做全局变量的,都绑定在这个变量下面!

    //唯一全局变量
    var Laxsilence = {
        //定义一个全局变量
        Laxsilence.name = "liu";
        Laxsilence.add = function(a,b){
            return a + b;
        }
    };
    

    即把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突的问题。jQuery就是这样干的,甚至他为了写jQuery更简单,直接让jQuery.等价于$()

  7. 局部作用域 let

    function aaa(){
        for(var i = 0;i<100;i++){
            console.log(i);
        }
        console.log(i + 1);//i 出了作用域 还是可以实现
    }
    

    ES6 let 关键字,解决局部作用域冲突问题,所以建议使用let

    function aaa(){
        for(let i = 0;i<100;i++){
            console.log(i);
        }
        console.log(i + 1);//i 会显示 undefined
    }
    
  8. 常量 const

    在ES6 之前,怎么定义常量:只有用全部大写字母命名的变量就是常量;建议不要修改这样命名的变量,这就很扯淡。就是说常量的值可以改变。。。

    所以在ES6引入了常量关键字const

    const PI = '3.14';//只读变量
    console.log(PI);
    PI = '123';//会报错,不允许修改  TypeError:Assignment to constant variable
    

4. 方法

对象里面的函数就叫做方法。对象只有两个东西:属性和方法

var Laxsilence = {
    //属性
    name:'liu',
    birth:'2001',
    //方法
    age:function(){
        //今年 - 出生年份
        var now = new Date().getFullYear();
        return now - this.birth;
    }
}
//调属性
Laxsilence.name;
//调方法 要带()
Laxsilence.age();

或者第二种写法:

function getAge(){
    var now  = new Date().getFullYear();
    return now - this.birth;
}
var Laxsilence = {
    name:'liu',
    birth:2001,
    age:getAge
}

//调用
Laxsilence.age();//正确
getAge();//NaN

可以知道this是指向当前调用该方法的对象,比如在Laxsilence.age()中,指向Laxsilence对象,而getAge()则默认是window对象,但是window对象没有birth属性。

在Java中this是无法指向的,是默认指向调用它的那个对象。

但在js中,apply可以控制this指向。可以理解为将这个方法应用到了某个对象上。

function getAge(){
    var now  = new Date().getFullYear();
    return now - this.birth;
}
var Laxsilence = {
    name:'liu',
    birth:2001,
    age:getAge
}

var Laxsilence = {
    name:'xiaoming',
    birth:2001,
    age:getAge
}

//调用
Laxsilence.age();//正确
getAge();//NaN
getAge.apply(Laxsilence,[]);//代表this指向了这个对象,参数为空,可以实现!!!
getAge.apply(xiaoming,[]);

五、内部对象

标准对象,可以使用typeof 判断一个对象属于什么类型

typeof 123 //"number"
typeof '123' //"string"
typeof true //boolean
typeof [] //"object"
typeof {} //"object"
typeof NaN //"number"
typeof Math.abs  //"function"
typeof undefined //"undefined"
...

1. Date

  1. 基本使用

    var now = new Date();//Tue Mar 22 2022 20:33:54 GMT+0800 (中国标准时间)
    now.getFullYear();//年
    now.getMonth();//月  0~11 代表月
    now.getDate();//日
    now.getDay();//星期几
    now.getHours();//时
    now.getMinutes();//分
    now.getSeconds();//秒
    now.getTime();//时间戳  全世界统一   1970.1.1 0:00:00 毫秒数  格林尼治时间的零点 北京时间的八点  647952955697
    
  2. 转换

    注意:调用的是一个方法,记得加上括号

    console.log(new Date(647952955697)) //时间戳转换为时间
    
    now.toLocaleString();//转换为当地时间
    
    now.toGMTString();
    

2.JSON(后续会讲)

json是什么?

早期,所有数据传输习惯都使用xml文件,但是xml的定义语法太过于繁琐,所以json出现了。

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。

它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。

易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

在JS中一切皆为对象,任何js支持的类型都可以 用JSON来表示;

格式:

  • 对象都用{}
  • 数组都用[]
  • 所有的键值对都是用key:value
var user = {
    name:"liu",
    age:13,
    sex:"男"
}
//对象转换为json字符串    {"name":"liu","age":13,"sex":"男"}
 var jsonUser = JSON.stringify(user);
console.log(jsonUser)
//json字符串转换为对象  参数为json字符串
var jsonUSerO = JSON.parse(jsonUser);
var jsonUSerO1 = JSON.parse('{"name":"liu","age":13,"sex":"男"}');
console.log(jsonUSerO);
console.log(jsonUSerO1);

JSON和js对象的区别:

var obj = {
    a:"hello",
    b:"hellob"
};

var json = '{"a":"hello","b":"hellob"}';

可以发现对象中的属性名是不需要双引号的,但是json中的键必须要用双引号括起来。

3. Ajax(后续会讲)

  • 原生的js写法 xhr异步请求
  • JQuery封装好的 方法 $(“#name”).ajex(“”)
  • axios 请求

六、面向对象编程

1. 什么是面向对象

js、java、C# ... 面向对象;

面向对象:

  • 类:模板
  • 对象:具体的实例

js有一些区别,需要换个思路:

  • 原型:

    var user = {
        name:"liu",
        age:3,
        run:function(){
            console.log(this.name + "run...");
        }
    };
    
    var xiaoming = {
        name:"xiaoming"  //跑不起来
    };
    
    var bird = {
        fly:function(){
            console.log(this.name + "fly...")
        }
    };
    
    //小明的原型  是 user
    xiaoming.__proto__ = user;
    xiaoming.__proto__ = bird;
    

2. class继承

class关键字 是在ES6引入的

定义一个类,属性,方法

function Student(name){
    this.name = name;
}

//给Student 新增一个方法
Student.prototype.hello = function(){
    alert('hello')
}

//ES6之后
//定义一个学生的类
class Student{
    constructor(name){
        this.name = name;
    }
    hello(){
        alert('hello')
    }
}

var xiaoming = new Student("xiaoming");
xiaoming.hello();
var xiaohong = new Student("xiaohong");
xiaohong.hello();


//继承
class XiaoStudent extends Student{
    constructor(name,grade){
        super(name);
        this.grade = grade;
    }
    myGrade(){
        alert('我是一个小学生')
    }
}

var xiaojun = new XiaoStudent("xiaojun","三")

本质:还是一个原型

image-20220324143629249

原型链:

在js中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。

_proto_:最终都会指向Object

简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》

image-20220324145355196

图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。


七、操作BOM对象(重点)

浏览器介绍:

js的诞生就是为了能够让他在浏览器中运行!

BOM:浏览器的对象模型

内核:

  • IE 6~11
  • Chrome,
  • Safari
  • FireFox (Linux)

三方(可以换内核):

  • QQ浏览器
  • 360浏览器

Window

window代表浏览器窗口

比如获取浏览器的高度跟宽度,可以更改浏览器的大小尝试

image-20220324150720229

Navigator

Navigator,封装了浏览器的信息,大多数时候我们不会使用这个对象,因为会被人为修改,不建议使用这些属性来判断和编写代码,不能说通过这个代码判断出浏览器是window的就开始写代码,这个window可能是被人为修改的。

navigator.appName
navigator.appVersion

screen

代表屏幕尺寸

screen.width//1920px
screen.height//1080px

location(重点)

localtion 代表当前页面的URL信息

location

host:"www.baidu.com"
href:"https://www.baidu.com/"
protocol:"https"
reload:f reload()  //刷新网页
//设置新的地址
localtion.assign("https://cnblogs.com/")

image-20220324151802458

document(内容 ,在DOM中详细讲解)

document 代表当前的页面,HTML DOM 文档树

document.title //"百度一下,你就知道"
document.title="laxsilence" //"laxsilence"

获取具体的文档树节点

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<dl id="app">
    <dt>Java</dt>
    <dd>JavaSE</dd>
    <dd>JavaEE</dd>
</dl>
<script>
    let app = document.getElementById("app");
</script>
</body>
</html>

获取cookie

document.cookie

劫持cookie原理

www.taobao.com

<script src = "aa.js"></script>
<!-- 恶意人员,获取你的cookie上传到它的服务器,就知道了你的个人隐私信息 -->

服务器端可以设置cookie:httpOnly,保护我们的cookie不被劫持

history(不建议使用)

history代表浏览器的历史记录

history.back() //后退
history.forward() //前进

八、操作DOM对象(重点)

DOM:文档对象模型

使用js动态的操作节点。

image-20220324154150498

1. 核心

浏览器网页就是一个DOM树形结构!

  • 更新:更新Dom节点
  • 遍历DOM节点:得到DOM节点
  • 删除:删除一个DOM节点
  • 添加:添加一个新的节点

2. 获得Dom节点

要操作一个DOM节点,就必须要先获得这个DOM节点

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="father">
    <h1>标题一</h1>
    <p id="p1">p1</p>
    <p class="p2">p2</p>
</div>

<script>
    let h1 = document.getElementsByTagName('h1');
    let p1 = document.getElementById('p1');
    let p2 = document.getElementsByClassName('p2');
    var father = document.getElementById('father');

    var children = father.children; //获取父节点下的所有子节点
    var children = father.children[index]; //获取父节点下的指定子节点
</script>
</body>
</html>

这是原生代码,之后都是用jQuery();

3. 更新Dom节点

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="id1">

</div>

<script>
    let id1 = document.getElementById('id1');
    id1.innerText = '123'; //修改文本的值
    id1.innerHTML = '<strong>123</strong>>' //可以解析HTML文本标签
    id1.innerText = 'abc';
    id1.style.color = 'red';
    id1.style.fontSize = '50px';
    id1.style.padding = '2em';
</script>
</body>
</html>

4. 删除DOM节点

删除节点的步骤:先获取父节点,再通过父节点删除自己

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="father">
    <h1>标题一</h1>
    <p id="p1">p1</p>
    <p class="p2">p2</p>
</div>

<script>
    
    //方式1
    let self = document.getElementById('p1');
    let father = self.parentElment;   
    father.removeChild(self);
    
    //方式2
    father.removeChile(father.children[0]);
    //father.removeChile(father.children[1]);//会报错,删除是一个动态的过程,下标会一直变,当children[0]删除后,children[1]就会变成children[0],所以这样写是不对的
    //father.removeChile(father.children[2]);
</script>
</body>
</html>

注意:删除多个节点的时候,一定要注意children是时刻在变化的

5. 插入节点

我们获得了某个DOM节点,假设这个DOM节点是空的,我们通过innerHTML就可以增加一个元素了,但是这个DOM节点已经存在元素了,我们就不能这么干了,因为会产生覆盖。

所以我们选择追加操作

  1. 追加已经存在的节点

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <p id="js">JavaScript</p>
    <div id="list">
        <p id="se">JavaSE</p>
        <p id="ee">JavaEE</p>
        <p id="me">JavaME</p>
    </div>
    
    <script>
        let js = document.getElementById('js');
        let list = document.getElementById('list');
    
        list.appendChild(js); //
    
    </script>
    </body>
    </html>
    
    

    追加后的效果:

    image-20220324163107242

    发现原来代码中的id为list的标签已经移动到div中了。

  2. 追加一个不存在的节点,即创建一个新的标签

    //通过JS创建一个新节点
    var newP = document.createElement('P');//创建一个P标签
    newP.id = 'new P';
    //或者
    newP.setAttribute("id","new P")
    newP.innerText = "hello,world";
    list.appendChild(newP);
    

    同样的,插入之后,代码会发生变化,会追加到div中。

    创建一个标签节点

    //通过这个属性可以设置任意的值
    var myScript = document.createElement('script');
    myScript.setAttribute('type',"text/javascript"); 
    list.appendChild(myScript);
    
    var body = document.getElementsByTagName('body');
    body[0].style.backgroundColor = "red";//通过标签或者类名获取到的是一个数组,需要选定,只有ID获得的不是数组,可以直接用
    
    //或者
    var myStyle = document.createElement('style');//创建一个空style标签
    myStyle.setAttribute('type','text/css');
    myStyle.innerHTML = "body{background-color:blue;}"//设置标签内容
    document.getElementsByTagName('head')[0].appendChild(myStyle);
    
  3. 插入到想插入的位置前面 insert

    var ee = document.getElementById('ee');
    var js = document.getElementById('js');
    var list = document.getElementById('list');
    //父节点.insertBefore(newNode,targetNode);在父节点下的目标节点前插入新节点,如果不指定的话,默认插入到最后面
    list.insertBefore(js,ee)
    

九、操作表单(验证)

1. 表单是什么

form input 标签 也是DOM树中的节点

常见的表单:

  1. 文本框 text
  2. 下拉框 <select>
  3. 复选框 checkbox
  4. 单选框 redio
  5. 隐藏域 hidden
  6. 密码框 password
  7. ...

表单的目的:提交信息

2. 获得要提交的信息

image-20220326010107262

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="#" method="post">
    <p>
        <span>用户名:</span><input type="text" id="username">
    </p>

<!--    多选框的值就是定义好的value值-->
    <p>
        <span>性别:</span>
        <input type="radio" name="sex" value="man" id="boy">男
        <input type="radio" name="sex" value="woman" id="girl">女
    </p>

</form>


<script>
    let input_text = document.getElementById("username");
    let boy_radio = document.getElementById("boy");
    let girl_radio = document.getElementById("girl");
    //得到输入框的值
    console.log(input_text.value);
    //修改输入框的值
    input_text.value = '123';

    //对于单选框和多选框使用boy_radio.value只能取到当前的值
    boy_radio.value;//返回 man
    girl_radio.value;//返回 woman

    //那么怎么拿到单选选择的值呢,使用checked方法 选中什么 什么为true
    boy_radio.checked;//如果单选框选择的是男 那么该值为true
    girl_radio.checked;//同上

    //如果想直接用代码实现选中,怎么实现
    boy_radio.checked = true; //这样选中的就是男 赋值操作
</script>
</body>
</html>

3. 提交表单及前端加密

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<!--    MD5工具类-->
    <script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>
</head>
<body>

<!--
表单绑定提交事件
onsubmit=  绑定一个提交检测的函数 true  false
将这个结果返回给表单,使用onsubmit接收

-->
<form action="https://www.baidu.com/" method="post" onsubmit="return aaa()">
    <p>
        <span>用户名:</span><input type="text" id="username" name="username">
    </p>
    <p>
        <span>密码:</span><input type="password" id="password" name="password"> <!-- 普通的密码框 可以抓包获取到值 但是可以用md5加密  -->
    </p>
    <p>
        <span>不走密码框密码:</span><input type="password" id="input-password"> <!--  高级一点的方法,这个是用来输入密码的框,但不用来提交,所以不能加name属性(post提交,没有name属性的不会被提交) -->
    </p>

    <input type="hidden" id="md5-password" name="password2">  <!-- 这个才是真的密码框,但是是被隐藏的 -->

    <!--绑定事件,被点击-->
    <button type="submit" >提交</button><!-- onclick="aaa()"-->

</form>


<script>
    function aaa(){
        let username = document.getElementById('username');
        let password = document.getElementById('password');
        let inputPassword = document.getElementById('input-password');
        let md5Password = document.getElementById('md5-password');
        // console.log(username.value);
        // console.log(password.value);
        //MD5算法
        // password.value = md5(password.value); //加密密码框中的值 ,但是会发现提交的一瞬间密码框中的值不再是输入的值,而是变成了加密后的一串东西,体验很差
        // console.log(username.value);
        // console.log(password.value);

        md5Password.value = md5(inputPassword.value); //把用来输入的密码框中的值,用md5加密后传给真正的密码框,这样的话提交后,密码框中的值还是你输入的值

        //false 表单提交不通过,return 表单提交通过 ,这里配合if-else 来决定返回true还是false,用来验证 表单填写是否合法
        return true;
    }
</script>
</body>
</html>

使用审查元素,network抓包

image-20220328012220166


十、JQuery

js 和 JQuery : JQuery库,里面存在大量的JS函数。

JQuery工具站:https://jquery.cuishifeng.cn/

jQuery操作公式: $(selector).action()

1. 获取JQuery

可以前往JQUuery官网下载使用,也可以搜索JQuery CDN 加速链接引用。

但是建议下载导入,CDN引入不可靠

  1. 直接下载导入

  2. 在线CDN

    <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>
    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<!--    CDN引入-->
<!--    <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>-->
<!--    下载导入-->
    <script src="lib/jquery-3.6.0.js"></script>
</head>
<body>
<!--
jQuery操作公式: $(selector).action()
-->

<a href="" id="test-jquery">点我</a>

<script>
    //selector选择器就是CSS的选择器
    $('#test-jquery').click(function (){
        alert('Hello,JQuery');
    })
</script>
</body>
</html>

2. JQuery选择器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script>
    //原生js,选择器少,不好用
    //标签
    document.getElementsByTagName();
    //id
    document.getElementById();
    //类
    document.getElementsByClassName();

    //jQuery
    $('p').click();//标签选择器
    $('#id1').click();//id选择器
    $('.class1').click();//类选择器
    //CSS中的选择器都可以使用
    
</script>
</body>
</html>

3. JQuery 事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>
    <style>
        #divMove{
            width: 500px;
            height: 500px;
            border: 1px solid red;
        }
    </style>
</head>
<body>
<!--获取鼠标当前的坐标-->
mouse: <span id="mouseMove"></span>
<div id="divMove">
在这里移动鼠标试试
</div>

<script>
    //当网页元素加载完毕之后,响应事件
    // $(document).ready(function (){
    //
    // })
    //简写:
    $(function (){
        $('#divMove').mousemove(function (e){
            $('#mouseMove').text('x:'+e.pageX + 'y:'+e.pageY)
        })
    });
</script>
</body>
</html>

image-20220329175320998

image-20220329180330756

4. JQuery操作DOM元素

  1. 节点文本操作

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>
    </head>
    <body>
    <ul id="test-ul">
        <li class="js">JavaScript</li>
        <li name="python">Python</li>
    </ul>
    
    
    <script>
        $('#test-ul li[name = python]').text();//获得值
        $('#test-ul li[name = python]').text('this is python');//设置值
        $('#test-ul').html();
        $('#test-ul').html('<strong>JavaScript</strong>');
    </script>
    </body>
    </html>
    
  2. CSS的操作

    $('#test-ul li[name = python]').css({"color":"red"});
    
  3. 元素的显示和隐藏(本质:display = none)

    $('#test-ul li[name = python]').show()  //元素显示
    $('#test-ul li[name = python]').hide()  //元素隐藏
    
  4. 娱乐测试

    $(window).width();
    $(window).height();
    $(document).width();
    ...
    
  5. 未来 Ajax(); 重点

    $('#form').ajax();
    

十一、前端的小技巧

  1. 如何巩固JS
    • 看框架源码(JQuery)
    • 看游戏源码!(前端游戏)
  2. 巩固HTML和CSS
    • 扒网站,下载下来,对应修改查看效果
  3. 为自己的博客前端做准备
posted @ 2022-03-30 15:34  Laxsilence  阅读(62)  评论(1)    收藏  举报