JS--笔记0413

一,轮播图

基本步骤和思路

  1. 根据ul>li,原始的轮播图数量,生成对应的焦点标签,ol>li
    获取ul>li标签对象伪数组
    循环遍历伪数组
    生成li标签,添加index属性
    将生成的li标签,写入到ol中
  2. 复制原始轮播图内容,第一张和最后一张
    clone第一张和最后一张图片的标签
    将第一张写入到ul末位,将最后一张写入到ul起始
    重新定义ul的宽度
    将ul左移一个单位,显示原始轮播图的第一张图片
  3. 自动轮播
    设定定时器
    index变量++
    调用move运动函数,left:-index*li宽度
  4. 运动终止,执行的函数
    判断index数值
    如果是 最后一个li,index赋值为1,根据新的index,设定ul的位移
    如果是 第一个li,index赋值为倒数第二个li索引,根据新的index,设定ul的位移
    焦点样式切换
    先清除所有ol>li样式
    根据index数值,设定对应ol>li标签,li标签index属性数值,与index变量数值相同
    给bool变量赋值为原始数值,让点击可以继续进行
  5. 鼠标移入移出
    移入,清除定时器,终止运动
    移出,再次启动执行 自动轮播 函数
  6. 焦点按钮点击事件
    判断 bool 变量存储的数值是否是原始数值
    如果不是,执行return
    给bool赋值非原始数值
    给焦点按钮添加点击事件(一般是事件委托的形式)
    获取焦点按钮,index属性的属性值
    赋值给index变量,根据index执行 move运动函数
  7. 左右切换点击事件
    判断 bool 变量存储的数值是否是原始数值
    如果不是,执行return
    给bool赋值非原始数值
    左按钮,index–,根据index执行 move运动函数
    有按钮,index++,根据index执行 move运动函数
  8. 解决点击过快问题
    本质是为防止,同一时间,有多个运动函数同时执行
    思路:定义一个变量 bool
    如果是原始值,证明没有点击过按钮,可以执行点击效果
    如果不是原始值,证明已经点击过按钮,并且当前运动没有结束
    此时不允许再次执行点击效果,防止触发生成多个运动效果
    也就是同一个时间内,只允许有一个运动效果
  9. 页面隐藏问题
    当页面显示状态发生改变时,触发事件处理函数
    当隐藏时,清除定时器,终止运动
    当显示时,重新启动 自动轮播函数

二,节点操作

另一种操作页面内容的方式,多用于生成新的标签和复制标签

1. 获取节点

标签.childNodes 获取所有的子级节点
标签.children 获取所有的子级标签节点
标签.firstChild 获取第一个子级节点
标签.lastChild 获取最后一个子级节点
标签.firstElementChild 获取第一个子级元素节点
标签.lastElementChild 获取最后一个子级元素节点
标签.previousSibling 获取上一个兄弟节点
标签.nextSibling 获取下一个兄弟节点
标签.previousElementSibling 获取上一个兄弟元素节点
标签.nextElementSibling 获取下一个兄弟元素节点
标签.parentNode 获取直接父级节点
标签.attributes 获取属性节点

2. 节点的类型,名称,内容

节点类型 标签.nodeType
元素节点 : 1
属性节点 : 2
文本节点 : 3
注释节点 : 8
节点名称 标签.nodeName
元素节点 : 大写的表现名称
属性节点 : 小写的属性名称
文本节点 : #text
注释节点 : #comment
节点内容 标签.nodeValue
元素节点 : null
属性节点 : 属性的属性值
文本节点 : 文本内容
注释节点 : 注释内容

3. 节点的操作:
            新建
                创建元素节点 document.createElement('标签名称')
                创建文本节点 document.createTextNode('文本内容')
            删除
                删除当前标签的子级节点 标签.removeChild('节点标签名称')
            克隆
                只克隆标签本身       标签.cloneNode()
                克隆标签本身和内容   标签.cloneNode(true)
            写入
                在当前标签末位写入        标签.appendChild(写入的标签)
                在当前标签子级标签前写入  标签.insertBefore(写入的标签,在哪个之前写入)

三 正则表达式

是验证字符串内容是否符合规范的方法

1. 建立正则表达式

字面量 let 变量 = /正则表达式/
构造函数 let 变量 = new RegExp();

2. 语法规范
  1. 元字符
    \d 数字
    \D 非数字
    \w 数字,字母,下划线
    \W 非数字,字母,下划线
    \s 空格
    \S 非空格
    . 非换行
  2. 边界符
    ^ 起始
    $ 结尾
  3. 限定符
    * 0 至 正无穷
    + 1 至 正无穷
    ? 0 至 1
    {n} n 次
    {n,} n 至 正无穷
    {n,m} n 至 m 次 包括n和m
  4. 特殊符号
    \ 表示正则或者转义符
    | 逻辑或
    () 表示看着一个整体来执行
    [] 表示是其中一个内容即可
    [^] 对其中内容取反
    a-b 表示a-b范围之内的内容
  5. 写在 正则表达式外的
    i 不分区大小写
    g 全局匹配
3. 配合的函数

search() 不区分大小写
变量.search(/正则/i)
indexOf,不能使用正则
match() 全局捕获
变量.match(/正则/g)
replace() 全局替换
变量.replace(/正则/g , 原有的要替换的内容)

四 ES6的语法规范

1. let const变量声明

let : 多用于定义基本数据类型
声明变量,变量名称不能重复
如果定义在 循环 和 { } 中,只能在循环和{ }中存在
类似于forEach() 在循环中,建立的独立的相互不影响的存储不同数据的循环变量
const : 多用于定义引用数据类型,定义常量(存储数据不允许改变的变量)
声明变量,变量名称不能重复
如果定义在 循环 和 { } 中,只能在循环和{ }中存在
定义的数据不能发生改变

2. 箭头函数

主要是为了配合构造函数使用
语法形式 :
function(){} — ()=>{}
function(e){} — e=>{}
function(){一行} — ()=>一行
this指向 :
指向父级程序的this指向
如果父级程序有this指向,就指向父级程序的this
如果父级程序没有this值,指向window
箭头函数,不能改变this指向

3. 改变函数this指向

箭头函数不能改变this指向,必须是父级程序的this指向

  1. 函数.call(参数1,其他参数…)
    立即执行函数
    参数1,是改变的this指向
    其他参数是原始函数的参数
  2. 函数.apply(参数1,[其他参数])
    立即执行函数
    参数1,是改变的this指向
    其他参数是原始函数的参数,必须是数组的形式
  3. const fun = 函数.bind(参数1)
    定义返回一个新的函数
    新函数与原始函数完全一致,只是this指向不同

4. 解构语法

将对象,数组的数据获取,给变量赋值

  1. 数组的解构 : 一一对应的赋值
    let [a1,a2,a3,a4] = [1,2,3,4];
    let [a1,a2,[a3,a4]] = [1,2,[3,4]];
  2. 对象的解构
    let {属性} = 对象
    let {属性:别名} = 对象
    let {属性:{属性}} = 对象
    let {属性:{属性:别名}} = 对象

5.合并,展开运算符

…变量
如果是实参或者其他位置 …变量 是将变量中的数据,一一展开,进行操作
如果是形参,…变量 是将所有的实参,以数组的形式存储
函数如果没有定义形参,有一个 arguments 属性来以数组的形式存储实参
箭头函数没有 arguments 只能使用合并运算符

6. 立即执行函数

理解执行函数,但是不能再次执行,只能执行一次
(函数)()
!函数()
~函数()

五 面向对象编程

1. 基本概念

所谓的面向对象编程,是一种编程思想和书写方式方法
简单理解:
之前是将程序,封装在函数内,设定参数和返回值
现在是将程序,封装在对象内,设定对象的属性和方法

2. 构造函数和实例化对象

构造函数:就是专门定义生成对象的函数
必须和关键词 new 配合使用
实例化对象:本质上就是一个对象,只不过是通过构造函数生成的

3. 原型链

1. 原型对象:

每一个 函数 都有一个 prototype
本质上一个专门存储 数据 和 方法(函数) 的空间

2. 原型属性:

每一个 对象 都有一个 __ proto__
实例化对象的 __ proto__ 指向的 就是 生成这个实例化对象的构造函数的 prototype

3. 原型链:

通过 __ proto__ 将相互关联的数据,串联起来,可以相互访问数据的功能,就称为原型链
在JavaScript中任意一个数据类型,都可以看做是对象,都有 __ proto__

举例:
定义 构造函数时, 将 实例化对象的方法,定义在构造函数的 prototype 中
生成 实例化对象 时 对象本身只有定义在 构造函数中的属性
没有定义在 prototype 中的方法
在 执行 实例化对象 时, 要调用方法,是通过原型链 也就是 通过 __ proto__
找到 构造函数 的 prototype 空间 并且调用其中 存储的方法

4. 构造函数

构造函数为了和普通函数区别,一般是将所有函数名称单词是的首字母大写
不大写也能执行,但是不符合语法按规范

定义构造函数:
在函数内,定义实例化对象的方法,通过的是this来指定定义实例化对象的属性
this.属性 = 属性值
在 prototype 中 定义 实例化对象的方法
构造函数 . prototype . 函数方法名 = function ( ) { }
使用,调用构造函数,必须和 new 关键词一起使用

   <script> 
       function CreateObj(name,age){
           this.name = name;
           this.age = age;
           // 直接定义在构造函数内的,会直接定义在实例化对象中
           this.fff = function(){
               console.log(123);
               console.log(this);

           }
       }
       // 定义在 prototype 中的,不会定义在实例化对象中,只会定在构造函数中
       CreateObj.prototype.fun = function(){
           console.log(this.age,this.name);
           console.log(this);
       }

       const obj = new CreateObj('张三',18);

       obj.fff();	 //123	Object { name: "张三", age: 18, fff: fff() }
       obj.fun();	//18 张三	Object { name: "张三", age: 18, fff: fff() }

       console.log(obj)	//Object { name: "张三", age: 18, fff: fff() }

2. table表格之面向对象

 <style>
        table {
            border-collapse: collapse;
        } 
        table td {
            width: 100px;
            line-height: 30px;
            border: 1px solid #000;
            text-align: center;
        }
    </style>
</head> 
<body>
    <div name="tabBox"> 
        姓名: <input type="text"><br>
        年龄: <input type="number" min="18" max="250"><br>
        姓名:<input type="radio" name="sex" value="男"><input type="radio" name="sex" value="女">
        保密<input type="radio" name="sex" value="保密"> <br>
        城市: <select>
            <option value="北京">北京</option>
            <option value="上海">上海</option>
            <option value="广州">广州</option>
            <option value="重庆">重庆</option>
            <option value="天津">天津</option>
        </select><br>
        <button name="add">添加</button>
        <table>
            <thead>
                <tr>
                    <td>序号</td>
                    <td>姓名</td>
                    <td>年龄</td>
                    <td>性别</td>
                    <td>城市</td>
                    <td>删除</td>
                </tr>
            </thead>
            <tbody></tbody>
        </table> 
    </div>
    <script> 
        // 面向过程 
        var arr = [
            {name:'张三',age:18,sex:'男',city:'北京'},
            {name:'李四',age:19,sex:'女',city:'上海'},
            {name:'王五',age:20,sex:'男',city:'广州'},
            {name:'赵六',age:21,sex:'女',city:'重庆'},
            {name:'刘七',age:22,sex:'保密',city:'天津'},
        ]; 
        var oTb = document.querySelector('tbody');
        var oBtnAdd = document.querySelector('[name="add"]'); 
        setTab(); 
        // 新增数据操作
        oBtnAdd.onclick = function(){
            var oIptName = document.querySelector('[type="text"]').value;
            var oIptAge = document.querySelector('[type="number"]').value;
            var oIptCity = document.querySelector('select').value;
            var oIptSex = document.querySelectorAll('[type="radio"]');
            var oIptSexValue = 0; 
            oIptSex.forEach(function(item){
                if(item.checked === true){
                    oIptSexValue = item.value;
                }
            })
            var obj = {
                name:oIptName,
                age:oIptAge,
                sex:oIptSexValue,
                city:oIptCity,
            }
            arr.push(obj);
            setTab();
        }  
        function setTab(){
            var str = '';
            arr.forEach(function(item , key){
                str += '<tr>';
                str += `<td>${key+1}</td>`;
                for(var k in item){
                    str += `<td>${item[k]}</td>`;
                }
                str += `<td><button index="${key}">删除</button></td>`;
                str += '</tr>';
            })
            oTb.innerHTML = str;
        } 
        oTb.onclick = function(e){
            e = e || window.event;
            var eTag = e.target || e.srcElement;
            if(eTag.tagName == 'BUTTON'){
                var index = eTag.getAttribute('index');
                arr.splice(index , 1);
                setTab();
            }
        } 

面向对象和面向过程
从面向过程,改造成面向对象

  1. 获取的数据,标签对象,要以参数的形式,定义给构造函数和实例化对象
    获取标签对象时,一般获取父级,传参父级,在构造函数中,通过父级标签,获取子级标签独享
  2. 必须非常非常非常注意,this的指向,一般在面向对象中,都是使用箭头函数
    如果万一不能清楚地知道this指向,可以先输出 this
  3. 其他步骤和思路基本相同,没有区别

总结:

  1. 改不改箭头函数,看内部是否需要 指向实例化对象的this
    如果需要,可以改箭头函数,或者是提前存储this指向
    如果不许需要,改不改箭头函数都行
    一切以实现程序为最终需求,程序能执行就可以
  2. 之前面向过程的是参数,数据等,
    现在是面向对象编程,要在对象的属性中,定义参数数据
    也就是通过 构造函数 this.属性 = 属性值 语法来定义需要获取的参数数据
  3. 定义在构造函数方法中的一些变量数据,并不是定义在实例化对象中的属性
    没有必须写成 this.属性 = 属性值 的形式
    只要写成普通的变量定义即可
    使用时,也是直接使用变量,不需要添加this
  4. 在构造函数的方法中,调用其他的函数方法
    语法形式 应该是 实例化对象.函数方法名称()
    在构造函数中,使用this来指向实例化对象,写成 this.函数方法名称()
        // 本地定义的数组
        const arr = [
            { name: '张三', age: 18, sex: '男', city: '北京' },
            { name: '李四', age: 19, sex: '女', city: '上海' },
            { name: '王五', age: 20, sex: '男', city: '广州' },
            { name: '赵六', age: 21, sex: '女', city: '重庆' },
            { name: '刘七', age: 22, sex: '保密', city: '天津' },
        ];

        // 获取父级标签,传参也是父级标签,在构造函数中,通过这个父级标签,获取子级标签对象
        const oTabBox = document.querySelector('[name="tabBox"]');

        // 创建构造函数

        // 参数1: 数组,也就是生成table表格的内容
        // 参数2: 标签对象,父级标签对象

        function CreateSetTableObj(array, ele) {
            // 在构造函数中,定义需要的数据

            // 定义属性,存储参数,为了在方法函数中,可以使用参数
            // 在方法函数中,调用参数,不能直接调用,必须是this.属性 = 参数,赋值之后,通过this.属性调用
            this.array = array;
            this.ele = ele;

            // 获取标签对象,tbody,写入内容的标签对象
            this.tbody = ele.querySelector('tbody');

            // 获取数据的input等标签
            // 在构造函数中,可以直接使用 ele 的

            // 获取输入姓名的标签
            this.oIptName = ele.querySelector('[type="text"]');
            // 获取输入年龄的标签
            this.oIptAge = ele.querySelector('[type="number"]');
            // 获取下拉列表框,选择城市标签
            this.oIptCity = ele.querySelector('select');
            // 获取所有的单选标签,结果是一个伪数组
            this.oIptSex = ele.querySelectorAll('[type="radio"]');
        }

        // 定义方法,创建td标签,生成页面内容
        // 就是之前面向过程的程序,将颞部的函数,如果有必要,改成箭头函数
        CreateSetTableObj.prototype.createTd = function () {
            let str = ' ';
            // 将普通函数,改为箭头函数
            // 将arr变量,改为 this.arr 属性获取数据
            // 不改箭头函数,this指向不是实例化对象,this.arr , this.tbody就有可能使用出现问题
            // 也可以先将 this 存储,使用存储的this
            // 此处, this.arr , this.tbody 没有写在 forEach中,不改也可以,对当前的程序没有影响
            // 但是为了确保如果使用this,可以正确执行,最好是改成箭头函数
            this.array.forEach((item, key) => {
                // forEach中没有用到this,可以不改成箭头函数
                // 最好写成箭头函数,方便使用
                str += '<tr>';
                str += `<td>${key + 1}</td>`;
                for (var k in item) {
                    str += `<td>${item[k]}</td>`;
                }
                str += `<td><button name="del" index="${key}">删除</button></td>`;
                str += '</tr>';
            })
            // oTb 改为 this.tbody 属性获取数据
            this.tbody.innerHTML = str;
        } 
        // 通过事件委托方式,给添加和删除按钮,定义点击事件
        CreateSetTableObj.prototype.setClick = function () {
            // 给最外层的div标签,添加点击事件,通过点击的目标,判断点的是哪个标签
            // 父级div是定义构造函数时,传递的参数,使用this.ele来存储
            // 这里要改成箭头函数,因为要使用this
            this.ele.addEventListener('click', (e) => {
                // 如果点击标签name属性值是add,点击的是添加按钮
                if (e.target.getAttribute('name') == 'add') {
                    // 获取数据
                    // 生成对象
                    // 对象写入数组
                    // 根据新的数组,冲洗渲染页面

                    // 点击时,才获取对应的数据

                    // 姓名
                    let oIptNameVal = this.oIptName.value;
                    // 年龄
                    let oIptAgeVal = this.oIptAge.value;
                    // 城市
                    let oIptCityVal = this.oIptCity.value;
                    // 也可以不在属性中定义标签对象,在此处,直接获取标签中的数据
                    // let oIptNameVal = this.ele.querySelector('[type="text"]').value;

                    // 获取性别标签的伪数组,
                    // 循环遍历,如果是选中状态,获取其中的数据

                    // 建立一个变量存储数据结果
                    let oIptSexValue = 0;
                    // 循环遍历, this.oIptSex 存储单选的伪数组
                    // 此处循环中,没有使用this,改不改箭头函数都行
                    this.oIptSex.forEach(function (item) {
                        if (item.checked === true) {
                            oIptSexValue = item.value;
                        }
                    })

                    // 将获取的数据,写入到对象中
                    const obj = {
                        name: oIptNameVal,
                        age: oIptAgeVal,
                        sex: oIptSexValue,
                        city: oIptCityVal,
                    }

                    // 将对象新增,写入数组中
                    this.array.push(obj);

                    // 根据新的数组,调用函数方法,渲染生成新的页面
                    this.createTd();

                    // 如果点击标签name属性值是del,点击的是删除按钮
                } else if (e.target.getAttribute('name') == 'del') {
                    // 获取点击标签,index属性的属性值
                    // 根据属性值,从数组中删除单元
                    // 再根据新数组,代用函数,重新生成页面
                    // 获取点击标签,index属性值
                    let index = e.target.getAttribute('index');
                    // 用属性值对应的索引下标,删除数组中的单元
                    this.array.splice(index, 1);
                    // 重新调用函数方法,来重新渲染页面
                    // 在构造函数内部,调用已经定义的函数方法
                    // 应该是 实例化对象.函数方法名称()
                    // 现在 this 指向的是 实例化对象,我们就使用this来替换
                    this.createTd();
                }
            })

        }

        // 创建实例化对象,输入参数
        // 参数1,根据执行的数组
        // 参数2,父级div标签对象
        const setTabObj = new CreateSetTableObj(arr, oTabBox);
        // 调用方法,创建td标签,生成页面内鹅绒
        setTabObj.createTd();
        setTabObj.setClick();

    </script>

3. ES6的构造函数语法

ES5的构造函数有一些问题
最大的问题,就是定义 prototype 是在函数之外定义的
调用构造函数,生成实例化对象,一定要在定义 prototype 之后
否则生成的实例化对象,只有属性没有函数方法
ES6中,新增语法形式 class 类
是一种新的定义构造函数的语法
作用和原理与ES5语法完全相同
只是语法格式和书写方式,不同

    // 如果先调用构造函数,只有属性没有方法
    // 因为定义方法的步骤还没执行呢
    const obj1 = new Fun('张三');
    // obj1.f()  // 执行结果是报错的

    function Fun(name){
        this.name = name;
    }
    // 在定义函数外,定义prototype
    Fun.prototype.f = function(){
        console.log(this.name)
    }

    const obj2 = new Fun('李四');
    obj2.f();

</script>

4. class

ES5和ES6语法的对比

  1. ES5语法

     function Fun1(name,age){
         this.name  = name;
         this.age = age;
     }
     Fun1.prototype.f1 = function(){
         console.log(this.name , this.age);
     }
    
  2. ES6语法 class

        class Fun2{
            constructor(name,age){
                this.name = name;
                this.age = age;
            }

            f2(){
                console.log(this.name , this.age);
            }
        }

        const obj1 = new Fun1('张三',18);
        const obj2 = new Fun2('李四',20);

        console.log(obj1);
        console.log(obj2);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值