对象的继承

JavaScript语言是通过一种叫做原型prototype的方式实现继承。

原型链继承

借用构造函数继承

组合继承

原型式继承

寄生继承

寄生组合继承

原型链继承

核心逻辑:子类型的原型为父类型的一个实例对象

/**
 * 1.创建父类型的函数
 * 2.给父类型的原型添加方法
 * 3.定义子类型的构造函数
 * 4.创建父类型的对象设置给子类型的原型
 * 5.将子类型的原型构造函数设置为子类型
 * 6.给子类型的原型添加方法
 * 7.创建子类型的实例,测试调用自身方法与父类型的方法
 */
//定义父类型的构造函数
function SupperType(msg) {
    this.supProp = "我是父类型的构造函数" + msg;
}

//给父类型的原型添加方法或者属性
SupperType.prototype.showSupperProp = function () {
    console.log("父类型的属性:", this.supProp);
}

// 定义子类型的构造函数
function SubType() {
    this.subProp = "我是子类型的构造函数";
}

//设置子类型的原型为 父类型
SubType.prototype = new SupperType();
//设置子类型的原型的构造函数 为子类型自己
SubType.prototype.constructor = SubType;

//给子类型的原型添加方法或属性
SubType.prototype.showSubProp = function () {
    console.log("子类型的属性", this.subProp);
}


//子类型创建  实体对象
let subType = new SubType();
console.log(subType);
// 通过子类类型实例对象  调用自身的属性
console.log(subType.subProp)
// 通过子类型实例对象  调用父类型的属性
console.log(subType.supProp)
// 通过子类型实例对象  调用子类型的原型中的方法
subType.showSubProp();
// 通过子类型实例对象  调用父类型的原型中的方法
subType.showSupperProp();
console.log("-----------------------------");
//获取 创建子类型的构造函数
console.log(subType.constructor);

缺点:1.继承单一  2.不能传递参数

借用构造函数继承

/**
 * 1.定义父类型的构造函数
 * 2.定义子类型的构造函数
 * 3.给子类型的原型添加方法
 * 4.创建子类型的实例
 */
//定义父类型的构造函数
function SupperType(name) {
    // 为当前对象属性 设置name属性
    this.name = name;
    //为当前对象 设置方法
    this.showSupperProp = function () {
        console.log("我是父类型中的方法:" + this.name)
    }
}

//给父类 的原型设置属性
SupperType.prototype.msg = "我是父类原型中的属性";


// 定义子类型的构造函数
function SubType(name, age) {
    // call 复制 父类的属性和方法(无法复制原型中的内容)
    SupperType.call(this, name);
    //为当前对象设置  属性
    this.age = age;
}

//给子类 的原型设置方法
SubType.prototype.showSubName = function () {
    console.log("我是子类的原型中方法:" + this.name, this.age);
}
//创建子类的实例
let subType = new SubType("张三", 20);
//子类自己的原型中的方法
subType.showSubName();
//调用父类的方法
subType.showSupperProp();
//调用父类的原型属性(借用构造函数继承   》》无法 调用父类的原型的属性和方法的)
console.log(subType.msg);
console.log(subType)

缺点:1.只能继承父类实例中的属性和方法,不能继承原型中的属性和方法;

2.无法实现构造函数的复用,每个子类的都有父类实例函数的副本,代码会臃肿。

组合继承

原型链+借用构造函数继承 = 组合继承

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

Person.prototype.setName = function (name) {
    //重置 name属性
    this.name = name;
}

function User(name, age, msg) {
    //借用构造函数继承
    //复制 Person中的name  与 age
    Person.call(this, name, age);

    this.msg = msg;
}

//原型链继承
User.prototype = new Person();

User.prototype.constructor = User;
//子类自身的原型方法
User.prototype.setMsg = function (msg) {
    this.msg = msg;
}

let lisi = new User('李四', 25, "我是李四......");
console.log(lisi)
lisi.setName("赵六");
lisi.setMsg("我是赵六.......")
console.log(lisi)

数组对象

数组是对象的一种,数据是一种用于表达顺序关系的值的集合的结构。

数组的存储的性能会比普通的对象要好,经常使用数组存储数据。

在JS中是支持数据中存储不同类型的数据的。

使用typeof运算符,检查数据的类型,会返回Object

//数组的创建方式1:
    //使用对象创建数组
    /*  let arr = new Array();
      arr[0] = 1;
      arr[1] = '2';
      arr[2] = true;
      arr[3] = null;
      arr[4] = {name: '张三', age: 18};*/
    //使用字面量创建数组
    // let arr = [1,'2',true,null];

    // let arr = [1, 2, 3, 4, 5];
    // console.log("获取数组的长度:", arr.length);
    //遍历数组
    // for (let i = 0; i < arr.length; i++) {
    //     console.log(arr[i]);
    // }
    //获取数组的原型
    // console.log(arr.constructor);
    // 向数组的末尾追加数据
    // arr.push("张三", "王五");

    //删除末尾的数据
    // arr.pop();

    //向数组的开头追加数据
    // arr.unshift("李四", "赵六");
    //删除数组的开头数据
    // arr.shift();

    //遍历数组  item: 数据中的元素  index:下标 value:数组中的所有数据
    // 这个方法只支持IE8以上的浏览器
    // arr.forEach(function (item, index, value) {
    //     console.log(item, index, value);
    // })


    // let arr = ["测试数据A", "测试数据B", "测试数据C", "测试数据D", "测试数据E", "测试数据F"];

    //slice 可以用于从数组中提取指定的元素,该方法不会改变
    //元素数组。而是将截取的元素封装到一个新的数组中
    //参数:1.截取开始的索引,包括开始索引
    //     2.截取结束的索引,不包含结束索引
    //      第二个参数可以不写,从开始索引截取到末尾
    /*
    let newArr = arr.slice(1, 4)
    console.log("新数组:", newArr)
    console.log("原数组:", arr)
    */
    //splice 用于删除数组中指定的元素,该方法会影响到原数组,
    //   会将指定的元素从原数组中删除,并将删除的元素返回。
    //参数 :1.开始位置的索引 2.表示要删除元素的数量
    //      3.第三个参数以及后续参数,可以传入新的元素,插入到开始位置索引的前边
    /*let newArr = arr.splice(3, 2,"新元素1","新元素2");
    console.log("新数组:", newArr)
    console.log("原数组:", arr)*/


    //concat 可以将多个数组 链接到一起并返回新的数组,该方法不会影响原数组
    /*let arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let arr2 = ['a', 'b', 'c', 'd', 'e', 'f'];
    let arr3 = ["测试数据A", "测试数据B", "测试数据C", "测试数据D", "测试数据E", "测试数据F"];

    let result = arr1.concat(arr2, arr3, "我是末尾数据");
    console.log(result);*/

    //将数组转换为字符串 @_@
    // let str = arr.join("@_@");
    // console.log(str)

    //翻转数组 ,会直接修改原数组
    // arr.reverse();
    // console.log(arr);

    //sort 对数组中的元素进行排序,会直接影响原数组
    // 默认会按照Unicode编码进行排序
    // let arr4 = ["测试数据D", "测试数据A", "测试数据C", "测试数据B", "测试数据E", "测试数据F"];
    //即使是纯数字 也会使用 Unicode编码进行排序
    // let arr4 = [1, 2, 58, 65, 12, 87, 52, 3, 4, 99, 55, 66, 88, 89, 5, 6, 7, 8, 9];
    //不满足使用的要求了
    // arr4.sort();
    //重写sort方法
    // arr4.sort(function (a, b) {
    /**
     * 如果返回值大于0 ,则元素交换位置
     * 如果返回值小于0,则元素位置不变
     * 如果返回值等于0 则不交换位置
     */
    // return b - a;
    // })
    // console.log(arr4);

    //如果数组中是对象  进行排序
    /*let arr = [{name: 'A', age: 22}, {name: 'B', age: 19}, {name: 'C', age: 20}]
    arr.sort(function (a, b) {
        return a.age - b.age;
    })
    console.log(arr)*/

    // let arr = [1,2,3,4,5];
    // console.log(arr.toString());// 将内转转换为字符串 1,2,3,4,5

    // let arr = [1,2,3,4,5];
    //valueOf() 返回数组的原始数据
    // console.log(arr.valueOf())
    // console.log(arr)

    // let arr = ['a', 'b', 'c', 'd', 'e', 'd', 'f', 'g', 'h', 'i', 'j'];
    //查询数据中 是否存在一个元素并返回下标(第一个遇到的),如果没有则返回-1
    // let index = arr.indexOf('d');
    // console.log("d:", index)
    //查询d在数组中最后一次出现的位置
    // let index = arr.lastIndexOf("d");
    // console.log("d:", index)
    //判断数组中是否存在g
    // console.log('t是否存在:',arr.includes('t'))

    //map() 遍历数组,每次循环时传入回调函数,根据回调函数返回的值,生成一个新的数组
    // let arr = [6, 9, 87, 45, 45, 2, 4, 78, 123, 79, 6, 1, 223, 365, 66];
    // item:元素  index:下标 value:数组本身
    /*  let res = arr.map(function (item, index, value) {
          if (item < 70) {
              return item * 2;
          } else {
              return item;
          }
      })
      console.log("原数组:",arr)
      console.log("新数组:",res)*/


    /* let arr = [6, 9, 87, 45, 45, 2, 4, 78, 123, 79, 6, 1, 223, 365, 66];
     //过滤数组中大于60的数据/
     // 过滤器 把满足条件的元素返回并存入新的数组中
     let res = arr.filter(function (item) {
         return item >= 60;
     })
     console.log("原数组:",arr)
     console.log("新数组:",res)*/

    /*    let arr = [87, 78, 123, 79, 223, 365, 66];
        //判断数组中所有的元素是否符合某个条件
        let result = arr.every(function (item) {
            return item >= 60;
        })
        console.log("数值中的元素是否都大于80:", result);*/



    // 判断数组中是否存在,满足某个条件的元素
    /*  let arr = [87, 78, 123, 79, 223, 365, 66];
      let result = arr.some(function (item) {
          return item >= 3000;
      })
      console.log("数组中是否有数据大于3000:", result)*/

    /*    let arr = [2, 3, 4, 5];
        /!**
         * reduce 遍历数组,每次循环执行时传入的回到函数,
         * 将会返回一个值,该值会作为初始值prev,传入到下一次的循环中
         *!/
        let sum = arr.reduce(function (prev, item, index, value) {
            console.log(prev, item);
            return prev + item;
        })
        console.log("和:", sum)*/

    //给定值 填充到数组中
     value 值(必填 默认填充所有)  开始位置  结束位置
     let arr = ['a', 'b', 'c', 'd'].fill("填充的值", 1, 2);
     console.log(arr)

内置对象

/**
* 时间
*/
//获取 当前时间
// Date 时间内置对象  用来表示一个时间
// let date = new Date();
/* console.log(date.getFullYear());
 //从0开始计算的月份
 console.log(date.getMonth());
 console.log(date.getDate())
 console.log(date.getHours())
 console.log(date.getMinutes())
 console.log(date.getSeconds())
 console.log(date.getMilliseconds())*/
//Math对象
// console.log(Math.PI);
// console.log(Math.E);
//正数
//用于计算一个数的绝对值
// console.log(Math.abs(1))
//向上去取整
/* console.log(Math.ceil(1.1))
 //向下去取整
 console.log(Math.floor(1.9))
 //四舍五入
 console.log(Math.round(5.5))
 //随机数  0-1
 console.log(Math.random())*/
//字符串
let str = "Hello,World!";
//获取长度
console.log(str.length)
//通过下标获取字符
console.log(str.charAt(0))
//拼接字符串
console.log(str.concat("你好", ",世界"))
console.log(str.indexOf(","));
console.log(str.lastIndexOf(","));
//是否包含一个字符串
console.log("是否包含Y:", str.includes("H"));
//截取字符串
//参数1.开始截取的索引 2.结束位置的索引 (可以省略,截取到末尾)
// console.log(str.substring(1,2));
// 注意:如果第二个参数小于第一个参数,则会交换参数的位置
// console.log(str.substring(2,1));

//截取字符串
//参数:1.截取开始位置的索引 2.截取的长度
// console.log(str.substr(1,2))

//将字符串 通过字符串 拆分为数组
// let arr = str.split(",");
// console.log(arr)

// console.log(str.toLowerCase())
// console.log(str.toUpperCase())

正则表达式

正则表达式 用于定义一些字符串的规则,可以根据正则表达式来检查一个字符串是否符合规则。(通过规则将符合规则的内容提取出来)

使用对象创建

 let 变量名 = new RegExp('正则表达式','匹配模式');

匹配模式

let 变量名 = /正则表达式/匹配模式

i:忽略大小写

g:全局匹配

ig:忽略大小写全局匹配

let str = "Aebc";
let reg = new RegExp("ae","i");
// 通过正则 验证 字符串是否符合要求
console.log(reg.test(str));

使用字面量创建

let 变量名 = /正则表达式/匹配模式
//使用字面量创建
let str = "Abc";
let reg = /ab/i;
//通过正则表达式 验证 字符串是否符合要求
console.log(reg.test(str));

需求:检查一个字符串中是否包含有a或者b

语法格式 :使用|表示或者的含义

//检查字符串中是否包含a或者b或者c、d、e
let str = "uiop";
let reg = /a|b|c|d|e/;
console.log(reg.test(str))

需求:检查一个字符串中是否有字母

 let str = "fd9sa";
 // [afg]  a、f、g是或者关系
 // let reg = /[afg]/;
 // [a-z] 小写字母 a到z之间的内容
 // [A-Z] 大写字母 A到Z之间的内容
 // [A-z] 忽略大小写字母 A到z之间的内容
 // [0-9]  任意的数字
 let reg = /[0-9]/;
 console.log(reg.test(str));
    
 //需求:检查一个字符串中是否除了数字还有其他字母
 // [^0-9]  除了任意的数字
 // [^A-Z]  除了任意的大写字母
 // [^a-z]  除了任意的小写字母
 // [^A-z]  除了任意字母
 let reg = /[^0-9]/;
 console.log(reg.test(str));

正则方法

// let str = "1a2b3C4D5e6R7t8y9u0";
//参数为正则表达式
// 将字符拆分为一个数组
// let result = str.split(/[A-z]/);
// let result = str.split(/[0-9]/);
// console.log(result)

//搜索字符串中是否包含指定的内容
// let str = "hello abc hello aec afc";
//如果搜索到了指定的内容,则返回第一个遇到的元素的索引
//如果没有搜索到指定的内容 则返回-1
// let result = str.search(/a[bef]c/);
// console.log(result)


/*let str = "1a2b3C4D5e6R7t8y9u0";
//需求:从字符串中将符合条件的内容提取出来
let result = str.match(/[a-z]/ig);
console.log(result)*/

let str = "1a2b3C4D5e6R7t8y9u0";
//将字符串中指定的内容替换成新的内容
let result = str.replace(/[a-z]/gi,'@_@');
console.log(result)

正则量词

通过量词可以设置一个内容出现的次数。

{n} 正好出现n次

{m,}最少m次最多没有上限

{m,n} 最少m次最多n次

+:至少一个 类似{1,}

*:0个或者多个{0,}

?:0个或者1个 类似:{0,1}

let str = "abbc";
//如果有多个内容可以使用()括号
// 需要字符串中有ababab
// let reg = /(ab){3}/;
//正则量词 : {} 只对它前边的一个内容生效
//{n} 正好出现n次
// let reg = /ab{3}/;
//{m,} 最少出现m次最多没有上限
// let reg = /ab{3,}/;
//{m,n} 出现m-n次之间
// let reg = /ab{3,5}c/;
// + :至少一个,类似{1,}
// let reg = /ab+c/;
// *: 0个或者多个 {0,}
// let reg = /ab*c/;
//  ?:0个或者1个 类似于:{0,1}
let reg = /ab?c/;
console.log(reg.test(str));

正则表达式高阶

/**
 * \w 一个任意的字母、数字、_ 相当于:[A-z0-9_]
 * \W 除了任意的字母、数字、_ 相当于:[^A-z0-9_]
 * \d 一个任意的数字 相当于:[0-9]
 * \D 除了任意的数字 相当于:[^0-9]
 * \s 空格
 * \S 除了空格
 * \b 单词边界
 * \B 除了单词的边界
 */
 
 // let str = 'assssvv';
    //如果我们要检查或者判断一个字符串的开头和结尾^:开头 $:结尾
    //如果字符中包含有 特殊字符  .  \
    //需要使用转义符:  \. :表示 .  \\表示 \
    // let reg = /^v$/;
    // console.log(reg.test(str));
    // let str = "1";
    // let reg = /^\D$/;
    // console.log(reg.test(str));
    /**
     * \w 一个任意的字母、数字、_ 相当于:[A-z0-9_]
     * \W 除了任意的字母、数字、_ 相当于:[^A-z0-9_]
     * \d 一个任意的数字 相当于:[0-9]
     * \D 除了任意的数字 相当于:[^0-9]
     * \s 空格
     * \S 除了空格
     * \b 单词边界
     * \B 除了单词的边界
     */
    //需求:去除字符串中的前后空格
    // let str = " Hello World ";
    // console.log(str)
    // let reg = /^\s*|\s*$/;
    // console.log(str.replace(reg, ""));

    //检查一个字符串中是否包含zhangsan
    // let str = "hello zhangsan xxx";
    // let reg = /\bzhangsan\b/
    // console.log(reg.test(str));

DOM

Document Object Model 文档对象模型

当页面被加载时,浏览器就会号才能构建文档对象模型

HTML DOM模型会被结构化为对象树

                                                                文档

                                                             根元素< html>

                                                </ head>                         body>

                title .....                                                         <a  <h1  <table

        <p         <div

                                                                                        属性        href         文本

        子标签

通过这个对象模型,动态的获取HTML的元素 属性

改变页面的html元素

改变页面的html属性

改变页面的css样式

删除页面的元素和属性

添加新的HTML元素和属性

节点

文档节点:整个HTML文档

元素节点:HTML文档中的HTML标签

属性节点:元素的属性 < img src="元素的属性">

文本节点:HTML标签中的内容 < p>文本节点< /p>

事件

HTML事件可以出发浏览器的行为,比如点击了某个HTML的标签,会执行一段js代码。

窗口事件

/**
 *  窗口事件
 *  由窗口触发的事件
 */
//失去焦点事件
window.onblur = function () {
    console.log("窗口失去了焦点")
}
//获得焦点事件
window.onfocus = function () {
    console.log("窗口获得了焦点")
}
/**
 * 当页面加载完成后 执行该事件
 */
window.onload = function () {
    console.log("页面加载完成!")
}

window.onresize = function () {
    console.log("窗口的大小正在发生改变")
}

表单事件

<form action="#" method="post" id="myForm">
    <input id="userCode" type="text" value="我是默认值" placeholder="请输入账号"/>
<!--    <button type="submit"></button>-->
    <input type="submit"/>
</form>

<script>

    let userCode = document.getElementById("userCode");

    //为userCode元素绑定 事件
    /* userCode.onfocus = function () {
         console.log("光标在input中");
         //this  当前对象 (userCode 对象 )
         // console.log(this.value)
         this.style.backgroundColor = "red";
     }*/
    //为userCode 绑定失去焦点事件
    /*userCode.onblur = function () {
        this.style.backgroundColor = "green";
    }*/
    //需求:当文本框中的内容改变时并且鼠标离开文本框时....
     userCode.onchange = function () {
         console.log(this.value)
     }
    //需求:当文本框中的内容改变时,立即执行回调函数
   /* userCode.oninput = function () {
        console.log(this.value);
    }*/

    //当文本框中的内容 ,被选中时执行
    userCode.onselect = function () {
        console.log("您已经选择了文本框中的内容")
    }

    let myForm = document.getElementById("myForm");
    //当表单被提交时执行
    myForm.onsubmit = function () {
        console.log(" 当前表单被提交了")

        //返回值为:false:阻止表单提交
        //        true :允许表单提交
        return false;

    }

</script>

键盘事件

onkeydown 键盘按下时执行
 onkeyup  键盘松开时执行
 onkeypress  当按下并松开时执行

// 当键盘按下时判断按下的按键是否是a
/* window.onkeydown = function (event) {
   console.log("key:",event.key)
   console.log("code",event.code)
   console.log("keyCode:",event.keyCode)
   //兼容处理
   event = event || window.event;

   if (event.keyCode == 65) {
     console.log("用户按下了a")
   }
 }*/
/* window.onkeyup = function (event) {
   console.log("key:",event.key)
   console.log("code",event.code)
   console.log("keyCode:",event.keyCode)
   //兼容处理
   event = event || window.event;

   if (event.keyCode == 65) {
     console.log("用户按下了a")
   }
 }*/

当事件的响应函数 被触发时,浏览器每次都会将一个事件对象作为实参传入响应的函数中。

Evetn对象,代表事件的状态,比如事件发生的元素,键盘按键的状态,鼠标的位置。

在IE8中,响应的函数被触发时,浏览器不会传递事件对象,到响应的函数中。

进行兼容处理 event = event || window.event;

鼠标事件

<style>
        #box {
            width: 200px;
            height: 200px;
            background-color: pink;
            /*溢出处理*/
            overflow: auto;
        }

        #box2 {
            width: 100px;
            height: 100px;
            background-color: orange;
        }
    </style>
</head>
<body>
<div id="box">

    <div id="box2">

    </div>
    内容
    内容
    内容
    内容
    内容
    内容
    内容
    内容
    内容
    内容
    内容
    内容
</div>
<script>
    // 鼠标事件:通过鼠标触发的事件
    let box = document.getElementById("box");
    let box2 = document.getElementById("box2");
    //鼠标单击事件
    // box.onclick = function () {
    //     console.log("单击了div")
    // }
    // 鼠标双击事件
    /*box.ondblclick = function () {
        console.log("双击了div")
    }*/

    /*    box.onmousedown = function (event) {
            event = event || window.event;
            //当鼠标按钮被按下时执行
            console.log("鼠标按下时",event);
        }*/

    /*box.onmouseup = function () {
        //鼠标的按键 松开时执行
        console.log("松开了鼠标按键")
    }*/
    /**
     * 鼠标移动时执行
     * @param event
     */
    /*  box.onmousemove = function (event) {
          event = event || window.event;
          console.log("鼠标移动中:", event.x, event.y)
      }*/

    //鼠标移动到元素上时执行  不可以阻止冒泡
    /*  box.onmouseover = function () {
          console.log("鼠标移动到当前元素上时执行A")
      }
      box2.onmouseover = function () {
          console.log("鼠标移动到当前元素上时执行B")
      }*/

    //当鼠标移出元素时执行 不可以阻止冒泡
    /*box.onmouseout = function () {
        console.log("鼠标移动出了当前元素A")
    }
    box2.onmouseout = function () {
        console.log("鼠标移动出了当前元素B")
    }*/
    //当鼠标指针移动到元素上时执行 可以阻止冒泡
    /* box.onmouseenter = function () {
         console.log("鼠标移动到了当前元素A")
     }
    */
    // 当鼠标移出元素时执行 可以阻止m冒泡
    /*box.onmouseleave  = function () {
        console.log("当鼠标移出元素时执行")
    }*/
    //当滚轮滚动时执行  有无内容 都执行
    /*box.onmousewheel = function (event) {
        console.log("当鼠标的滚轮滚动时执行")
    }*/
    box.onscroll = function () {
        console.log("当滚动条滚动时执行")
    }
</script>

事件冒泡

事件冒泡(Bubble)是指事件向上传到,当后代元素上的事件被触发,其祖先元素上相同事件也被触发。

 <style>
        #div1 {
            width: 200px;
            height: 200px;
            background-color: pink;
        }

        #div2 {
            width: 100px;
            height: 100px;
            background-color: coral;
        }

    </style>
</head>
<body>
<div id="div1">
    我是DIV1
    <div id="div2">
        我是DIV2
    </div>
</div>
<script>
    let div1 = document.getElementById("div1");
    let div2 = document.getElementById("div2");
    div1.onclick = function () {
        //绑定单机事件
        console.log("div1 我的单机事件被触发了")
        stopBubble();
    }
    div2.onclick = function () {
        //绑定单机事件
        console.log("div2 我的单机事件被触发了")
        stopBubble();
    }

    function stopBubble(event) {
        event = event || window.event;

        if (event && event.stopPropagation) {
            // 阻止事件的冒泡
            event.stopPropagation();
        } else {
            //阻止事件的冒泡
            window.event.cancelBubble = true;
        }
    }

</script>

阻止默认行为
<a id="a" href="https://www.baidu.com">点我打开百度</a>
<script>

    let a = document.getElementById("a");
    a.onclick = function () {

        console.log("执行了a标签的单击事件")
        stopDefault();
    }

    //阻止默认行为
    function stopDefault(event) {
        event = event || window.event;

        if(event && event.preventDefault){
            event.preventDefault();
        }else{
            window.event.returnValue = false;
        }
    }

</script>

事件的传播

事件的传播:网景和微软有不同的理解

微软认为事件应该由内向外传播,应该是先触发当前元素上的事件,在向祖先元素上传播。

网景认为应该是由外向内传播,当前事件触发时,应该是先触发当前元素最外层的祖先元素上的事件,然后在向内传播给后代元素。

W3C综合了两个方案。将事件传播分成了三个阶段:

1.捕获阶段:从最外层的祖先元素,向目标元素进行事件捕获,默认从事是不触发事件的。

2.目标阶段:事件的捕获到目标元素,捕获结束,开始在目标元素上触发事件。

3.冒泡阶段:事件从目标元素上向它的祖先元素上传递,依次触发。

BOM(浏览器对象模型)

Browser Object Model 可以让JS开操作浏览器。

window: 代表整个浏览器窗口,同时也是页面中的全局对象
Navigator: 代表浏览器的信息,可以用来识别不同的浏览器
Location:代表当前浏览器的地址栏信息
History:表示浏览器的历史记录
Screen:表示用户的屏幕信息

AJAX

XMLHTTPRequest对象

XMLHTTPRequest是Ajax的核心对象。

//创建XMLHttpRequest 对象
let ajax = new XMLHttpRequest();
//建立连接
ajax.open(method,url,async,username,password);
method:请求的方法  必须参数 POST  GET PUT  DELETE.....
url:请求的URL字符串 必须参数
async: 是否为异步请求 默认为true 、false
username: 服务器需要进行验证 用户名
password: 服务器需要进行验证 密码

//建立连接后,发送请求
ajax.send(body)
body:表示请求的参数  POST请求的参数就是body

绑定事件 当请求状态改变时事件

ajax.onreadystatechange = function () {
            /**
             * status 请求状态
             *         200 : "OK"
             *         404
             *         500
             *         403......
             * readyState XMLHttpRequest状态
             *         0:请求未初始化
             *         1:服务器连接已建立
             *         2:请求已收到
             *         3:请求正在处理中
             *         4:请求已完成,响应已就绪
             */
            if (ajax.status == 200 && ajax.readyState == 4) {
                //responseText 响应的结果(字符串)
                //JSON.parse 将字符串转换为JSON对象  JSON.stringify 将JSON对象转换为字符串
                console.log(JSON.parse(ajax.responseText));
                // console.log(JSON.stringify({name:'张三',age:18}))
            }
}
responseText:请求后 服务器响应 的结果
// 请求POST类型的接口时 要注意 接口接受参数的方式
//1.创建XMLHttpRequest对象
let ajax = new XMLHttpRequest();
//设置请求的 方式、路径
ajax.open('POST', 'http://localhost:8081/garden/sendPost');
//配置头部信息中的 Content-Type 内容类型 application/x-www-form-urlencoded:表单类型的数据
// application/json 默认值
ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//发送请求 如果是post请求 在此传递参数
ajax.send("pageNum=1&pageSize=10&name=zhangsan");
//绑定事件 请求 状态改变时执行
ajax.onreadystatechange = function () {
    if (ajax.status == 200 && ajax.readyState == 4) {
        console.log(ajax.responseText);
    }
}

Cookie

Cookie是一些数据,存储在电脑中的文本本中,当web服务器向浏览器发送请求,在连接关闭时,服务器是不会记录用户的信息的,cookie的作用就是 记录信息

当用户访问web页面是,它的名字可以记录在cookie中

在用户下一次访问页面是,可以在cooki中再次读取数据。

缺点:

1.数据大小,作为存储容器,Cookie只能存储4KB左右的数据

2.安全性问题:在HTTP协议中Cookie是明文传递的(HTTPS中不是)

3.网络负担:Cookie会被附加在每一个HTTP请求中

WebStorage

是HTML5中的存储解决方案之一。

sessionStorage :回话存储 浏览器关闭 会导致缓存数据消失

localStorage: 将一直存储数据在本地。

<script>
    // sessionStorage
    // localStorage
    //存
    sessionStorage.setItem("name", "John");
    //取
    let name = sessionStorage.getItem("name");
    console.log(name);
    //删除单个数据
    // sessionStorage.removeItem("name");
    // let name =  sessionStorage.getItem("name");
    // console.log(name);
    //清除所有数据
    // sessionStorage.clear();
    // 通过下标 获取key
    // console.log(sessionStorage.key(0))
    //返回 sessionStorage的长度
    // console.log(sessionStorage.length);
    // 遍历所 sessionStorage
   /* for (const key in sessionStorage) {
        console.log(key, sessionStorage[key]);
    }*/
    for (let i = 0; i <sessionStorage.length ; i++) {
        //通过下标 获取 key
        let key = sessionStorage.key(i);
        console.log(sessionStorage.getItem(key));
    }
</script>

闭包

如何产生一个闭包?

当一个嵌套函数的内部(子)函数引用了嵌套函数内部(父)函数的变量时,就产生了一个闭包。

funA(){

let a = 1;

funB(){

a++;

}

}

什么是闭包?

闭包是嵌套的内部函数。

包含被引用变量的对象

闭包的作用?

可以读取函数内部的变量,让这个变量始终保持在内存中。

function fun1() {
    let a = 1;

    function fun2() {
        a++;
        console.log("内部的a:",a);
        return a;
    }
    return fun2;
}
let fun2 = fun1();
fun2();
fun2();
fun2();
let a = fun2();
console.log("我是外部的a:",a)

闭包的生命周期:

产生:在嵌套函数内部定义执行完时就产生了

死亡:在嵌套函数的内部函数称为垃圾对象时就死亡了

闭包的应用

定义JS模块

1.具有特定功能的JS文件

2.将所有的数据和功能封装到一个函数内部(私有的)

3.只向外暴露一个包含n个方法的对象 或者 函数

4.模块的使用者,只需要通过暴露的对象 调用方法,就实现功能

案例:

MyModule.js
function myModule() {
    //私有数据
    let msg = 'Hello World!';

    function doUpperCase() {
        console.log(msg.toUpperCase());
    }

    function doLowerCase() {
        console.log(msg.toLowerCase());
    }

    return {
        doSomething:doUpperCase,
        doOtherthing:doLowerCase
    }

}

MyModule2.js

(function () {
    let msg = 'Hello World!YJY';

    function doUpperCase() {
        console.log(msg.toUpperCase());
    }

    function doLowerCase() {
        console.log(msg.toLowerCase());
    }

    window.myModule2 = {
        doUpperCase,doLowerCase
    }
})();//立即执行函数

<script type="text/javascript" src="./js/MyModule.js"></script>
<script type="text/javascript" src="./js/MyModule2.js"></script>
<script>
    //调用
    let module = myModule();
    module.doOtherthing();
    module.doSomething();
    console.log("-----------------------------------------")
    window.myModule2.doUpperCase();
    window.myModule2.doLowerCase();

</script>

总结:

理解:

当嵌套的内部函数引用了外部函数的变量时就产生了闭包。

闭包的本质是内部函数中的一个对象,这个对象引用了变量(父级)属性

作用:

延长了局部变量的生命周期。

让函数外部能操作到函数的内部变量。

let fun2 = fun1();
fun2();
fun2();
fun2();
let a = fun2();
console.log("我是外部的a:", a)

闭包的应用:

模块化:封装一些数据以及操作的函数,向外暴露一些行为。

缺点:

变量占用内部的时间可能比很长

可以会导致内存的泄露

解决:即使的释放 fun2 = null; 让内部函数对象 称为垃圾对象。

ES新特性

 ES6 语法 >> ECMAScript 6
let 关键字 用来声明变量
不允许重复声明
块级作用域
const 关键字 用于声明常量
不允许重复声明
块级作用域
声明必须赋值(初始值)
值不允许改变
标识符一般大写

 // const MAX = 100;
    //解构赋值
    // 从数组和对象中提取数据,对变量进行赋值。结构解析
    // const arr=["张三","李四","王五","赵六"];
    //数组的解构赋值
    // let [zs,ls,ww,zl]=arr;
    // console.log(zs,ls,ww,zl);

    // const zs={
    //     name:'张三',
    //     tags:['篮球','车手','滑板']
    //     }
    //     //对象的解构赋值
    // let {name, tags} = zs;
    // console.log(name);
    // console.log(tags);

    //复杂的解构赋值
    // let ls={
    //     name:'李四',
    //     age:18,
    //     msgs:['测试数据1', "测试数据2", "测试数据3"],
    //     tags:[
    //         {name:'篮球'},
    //         {name:'车手'},
    //         {name:'滑板'},
    //     ]
    // }
    // let {name,age,msgs:[one,two,three],tags:[a,b,c]}=ls;
    // console.log(name);
    // console.log(age)
    // console.log(one)
    // console.log(two)
    // console.log(three)
    // console.log(a)
    // console.log(b)
    // console.log(c)
模板字符串  是增强版字符串  用反引号 ``
字符串中可以出现换行符
可以使用${xxxx} 形式输出变量
/*let newHTML = `<ul>
                       <li>${变量}</li>
                   </ul>`;*/
//ES6支持对象简化写法
//     let name='张三';
//     let age='18';
//     let speak=function (){
//         console.log(this.name);
//     }
//     //对象
//     let person={
//         name,age,speak
//     }
//     console.log(person);
//     person.speak();
/**
 * 箭头函数
 * ES6允许使用箭头函数定义函数的
 * function xxx(形参) {
 *     return xxx;
 * }
 * let fun = (形参1,形参2,形参3...) => {
 *     return 形参1+形参3+形参2;
 * }
 *
 * let fun= (形参1,形参2,形参3...)=> 形参1+形参3+形参2;
 *
 * 使用箭头函数的注意点:
 * 1.如果形参只有一个,则小括号可以省略
 *  let fun = 形参=> {return 结果 };
 * 2.如果函数体中只有一条语句,则花括号可以省略,
 *    函数的返回值为该条语句执行的结果
 *  let fun = 形参=>  结果
 * 3.箭头函数 this指向声明时所在作用域下的this的值,
 *       箭头函数不会改变this的指向的。
 * 4.箭头函数不能作为构造函数使用
 */
//3.箭头函数 this指向声明时所在作用域下的this的值 ,箭头函数不会改变this的指向的。
    let fun=()=>{
            console.log("fun函数中的:",this)
    }
    //fun();

    let user={
        name:'测试',
        getName(){
            console.log("getName",this)
            //this>>>fun作用域的当前对象(window)
            //let subFun=fun;
          /*  let subFun=()=>{
                //this>>>当前对象
                console.log("subFun",this)
            }*/

            /*    let subFun = function (){
                   //this >>> window
               console.log("subFun:",this)
           }*/
            subFun();

        }
    }
    user.getName();
/**
     * rest 参数
     * 用于获取函数的实参。
     *
     * rest参数 必须在参数列表的末尾
     */
    // function add(...args) {
    //     console.log(args);
    // }
    // add(1,2,3,4);

    // function minus(a,b,...args){
    //     console.log(args,a,b)
    // }
    // minus(100,300,1,2,3,4,5,6)

    /**
     *  spread 扩展运算符
     *  也就是 (...) 将数组、对象 进行解包
     *  */
    /*    const arr1 = ["张三", "李四", "王五", "赵六"];
        //合并数组
        let arr2 = ['测试数据1', '测试数据2', '测试数据3']
        let arr3 = [...arr1, ...arr2,"xxxx"]

        console.log(arr3)*/

    // let objA={
    //     name:'张三',
    // }
    // let objB={
    //     age:19
    // }
    // let objC={
    //     sex:'男'
    // }
    // let objD={
    //     ...objA,
    //     ...objB,
    //     ...objC
    // }
    // console.log(objD)
/**
 * 迭代器
 * iterator 是一种机制,是一个接口
 * 为各种不同的数据接口 提供一个统一访问机制
 * Array
 * Set
 * Map
 * String...
 */
const arr=["张三","李四","王五","赵六"];
    //使用 for...of...
    // for (const name of arr){
    //     console.log(name);
    // }
   //获取迭代器对象
    let iterator=arr[Symbol.iterator]();
    //调用对象的next方法
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
/**
 * 生成器
 * 是ES6的一种异步编程的方案。
 * (*)的位置有限制
 * 生成器函数返回的结果是一个迭代器对象,
 * 调用迭代器对象的next方法 可以得到 yield 后的内容
 * yield 相当于函数的暂停标记,当需要时执行next
 * 在执行下一步的代码
 *
 */
 function * gen(){
        console.log("执行第一行代码")
        yield "一直没有耳朵";
        console.log("执行第二段代码")
        yield "一只没有尾巴";
        console.log("执行第三行代码")
        yield "真奇怪"
    }
    let iterator=gen();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());

/* function* gen(arg) {
        console.log(arg);
        let one = yield 111;
        console.log(one)
        let two = yield 222;
        console.log(two)
        let three = yield 333;
        console.log(three)
    }
    let iterator = gen("AAA");
    console.log(iterator.next("BBB"));
    console.log(iterator.next("CCC"));
    console.log(iterator.next("DDD"));*/

    /* function one() {
         setTimeout(function () {
             console.log("one:", 111);
             iterator.next();
         }, 1000)
     }

     function two() {
         setTimeout(function () {
             console.log("one:", 222);
             // if(.....)
             iterator.next();
         }, 2000)
     }

     function three() {
         setTimeout(function () {
             console.log("one:", 333);
             // if(......)
             iterator.next();
         }, 3000)
     }

     function* gen() {
         yield one();
         yield two();
         yield three();
     }

     let iterator = gen();
     iterator.next();*/
Set 集合支持迭代器遍历
//创建了 集合
    // let s = new Set();
     let s = new Set([1,2,3,4,5,6,9,7,8,5,6,2,4,5,6,2,5]);
     //返回集合中的元素个数
     console.log(s.size);
     //新增数据
     s.add(0);
     //删除数据
     s.delete(1);
     //检查数据
     console.log(s.has(1));
     //清除所有
     // s.clear();
     console.log(s)
*  Map 键值对集合
*  键:不限于字符串,各种类型的谁都可以比如 对象
*  支持迭代器  可以使用扩展运算符
*  和 for  of
// let m = new Map();
      let m = new Map([['name', '张三'], ['age', 22]])
       //返回元素的个数
       console.log(m.size)
       //set 存储一个新的元素 key-value 返回当前map
       console.log(m.set("sex", "男"));
       //通过key  获取  value
       console.log(m.get("name"))
       //通过key删除
       console.log(m.delete("age"))
       //检测是否包含key
       console.log(m.has("age"))
       // m.clear() 清除所有
       console.log(m)

    class Phone {
           //构造方法
           constructor(brand, color, price) {
               this.brand = brand;
               this.color = color;
               this.price = price;
           }

           //打电话
           call() {
               console.log("我可以打电话");
           }
       }

       class Smartphone extends Phone {
           constructor(brand, color, price, screen, pixel) {
               super(brand, color, price);
               this.screen = screen;
               this.pixel = pixel;
           }

           call() {
               console.log("可以视频通话")
           }

           photo() {
               console.log("我可以拍照")
           }

           playGame(){
               console.log("可以游戏")
           }

           static run(){
               console.log("可以运行外界的程序")
           }
       }
       const Nokia = new Phone('诺基亚',"黑色",500);
        const smartphone = new Smartphone('苹果','金色',5999,"6.7inch","5000W");

       Nokia.call();
       smartphone.call();
       Smartphone.run();

       console.log(smartphone)

对象的合并

// Object.assign()
    const config1 = {
        hose:"localhost",
        port:"3306",
        name:"lisi",
        pass:'123456',
        test1:'test1'
    }

    const config2 = {
        hose:"localhost",
        port:"3306",
        name:"lisi",
        pass:'123456',
        test2:'test2'
    }
    //合并对象
    //合并后 会把相同的属性和方法覆盖,没有的属性和方法 会合并
    console.log(Object.assign(config1,config2));

更多推荐