js高级第二天

114 阅读5分钟

js高级第二天

1.原型链继承

利用代码的能力实现 面向对象的特性 封装继承

1.初体验

  1. 子类strudent 继承了父类 Person的属性

        // 父类
        function Person(name, height) {
          this.name = name;
          this.height = height;
        }
    
        Person.prototype.say = function () {
          console.log(this.name);
          console.log(this.height);
        }
    
        // 子类
        function Student(grade, name, height) {
          // 借用了父类的构造函数,完成对自己的赋值
          Person.call(this, name, height)
          this.grade = grade;
        }
    
        // 赋值了父类原型上的所有的 属性和方法
        Student.prototype = Person.prototype;
        // 修改之类的指向
        Student.prototype.constructor = Student;
    
        // 创建子类的实例
        const stu = new Student("一年", "周星星", 170);
        stu.say();
    

    需求

    1. 有一个负责创建元素的构造函数 A
    2. 有一个负责创建图片的构造函数 B
    3. 构造函数 B 可以使用 构造函数 A 的原型上的所有的功能 实现继承

    效果

    1650797659376

    代码

        // 1 负责创建元素  
        function Element(nodeName, text) {
          const node = document.createElement(nodeName);
          node.classList.add("element")
          node.innerText = text;
          this.node = node;
        }
    
        // 2 原型上挂载 共用的方法
        Element.prototype.appendTo = function (selector) {
          const parent = document.querySelector(selector);
          parent.appendChild(this.node);
        }
    
        // 3 创建一个实例
        const div = new Element("div", "做人开心就好");
        // 4 追加到父元素上
        div.appendTo("section");
    
        // 5 一个新的构造函数 用来创建图片
        function ElementImg(src) {
          // 6 借用了 1 中的构造函数,并且把参数传递了进去
          Element.call(this, "img", "");
          // 7 图片设置路径
          this.node.src = src;
        }
    
        // 8 继承了 父亲的构造函数上的原型上的所有 函数
        ElementImg.prototype=Element.prototype;			// 修改来原型,也就修改了构造函数
        // 9 重新将 constructor 的指向改回来
        ElementImg.prototype.constructor=ElementImg;
    
        // 10 创建一个图片实例:注意,实例化代码10不能在8和9之前
        const img = new ElementImg("images/01.png");
        
        // 11 创建到父元素上
        img.appendTo("section");
    

    2.es6 class(重点)

    es6的class 的出现 基本上可以替代了es5的构造函数和原型,使之代码结构上更加简洁。

    关键字

    1. class

    2. 属性

    3. 方法

    4. 继承 extends

    5. 构造函数 constructor

    6. 方法重写 override:子类方法覆盖父类,super.父类方法()

    7. 父类的构造函数 super :子类有构造方法且使用this前,必须使用super()

    完整代码体验

        class Person {
          // 构造方法
          constructor(name) {
            // 属性
            this.name = name;
          }
          // 方法
          say() {
            console.log(this.name);
          }
        }
    	// 继承
        class Student extends Person{
          constructor(name,height){
            // console.log(this);			// 语法错误:必须先调用super()才能使用this
            super(name);
            this.height=height;
          }
        }
    
        const s1=new Student("八神",180);
        s1.say();							// 八神
    
    	class Saler extends Person{
            constructor(name,age){
                super(name);
                this.age = age;
            }
            // 覆盖(重写)
            say(){
                // 访问父类方法
                super.say();				// 马云
                console.log(this.age);
            }
        }
    
    	const s2 = new Saler('马云',50);
    	s2.say();							// 50
    

    Tab栏切换

    <!DOCTYPE html>
    <html>
    
    <head lang="en">
        <meta charset="UTF-8">
        <title>tab栏切换</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
    
            ul {
                list-style: none;
            }
    
            .box {
                width: 400px;
                height: 300px;
                border: 1px solid #ccc;
                margin: 100px auto;
            }
    
            .hd {
                height: 45px;
            }
    
            .hd span {
                display: inline-block;
                /*将行内元素转换成行内块元素,宽高才起作用*/
                width: 90px;
                background-color: pink;
                line-height: 45px;
                text-align: center;
                cursor: pointer;
            }
    
            .hd span.current {
                /*交集选择器,标签指定式选择器*/
                background-color: purple;
                /*紫色*/
            }
    
            .bd li {
                height: 255px;
                background-color: purple;
                display: none;
                /*设置隐藏*/
            }
    
            .bd li.current {
                display: block;
                /*显示*/
            }
        </style>
        <script src="js/TabExchange.js"></script>
    </head>
    
    <body>
        <div class="box" id="box">
            <div class="hd">
                <span class="current">体育</span>
                <span>娱乐</span>
                <span>新闻</span>
                <span>综合</span>
            </div>
            <div class="bd">
                <ul id="list">
                    <li class="current">我是体育模块</li>
                    <li>我的娱乐模块</li>
                    <li id="li3">我是新闻模块</li>
                    <li>我是综合模块</li>
                </ul>
            </div>
        </div>
    
        <script>
            let tab = new TabExchange('box', 'current');
            console.dir(tab);
        </script>
    
    </body>
    
    </html>
    
    class TabExchange {
    
        // 构造函数
        constructor(id, className) {
            // 获取id对应的元素:规范,属于最外层
            this.id = document.querySelector(`#${id}`)
            // 规定内部有两层解构:div>span
            this.hd = this.id.querySelectorAll('div>span')
            // 规范内部有两层解构:div>ul>li
            this.bd = this.id.querySelectorAll('div>ul>li')
            // 保存当前要处理的样式类
            this.style = className;
    
            // 调用自己的tabClick 方法处理点击事件
            this.tabClick();
        }
    
    
        // 绑定点击事件
        tabClick() {
            // 因为接下来要绑定事件,事件里面也会出现this,所以先定义变量that来保存当前TabExchange对象的this
            let that = this
    
            // 循环遍历,绑定事件,并进行事件处理
            this.hd.forEach(function (item, key) {
                // item就是span,key就是span的下标
                item.addEventListener('click', function () {
    
                    // 排他:清空hd全部样式
                    that.hd.forEach(function (item1) {
                        item1.classList.remove(that.style)
                    })
    
                    // 清空bd的所有样式
                    that.bd.forEach(function (item2) {
                        item2.classList.remove(that.style)
                    })
    
                    // 给当前事件元素添加样式
                    that.hd[key].classList.add(that.style)
                    that.bd[key].classList.add(that.style)
                })
            })
        }
    
    }
    

2.元素创建继承

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .element {
        width: 200px;
        height: 200px;
        border-radius: 50%;
        border: 10px solid #00ffff;

        text-align: center;
        font-size: 30px;
        line-height: 200px;

        overflow: hidden;
        float: left;
    }
</style>

<body>
    <script>
        // 创建一个类:可以创建普通元素,并且可以实现将元素挂到指定父元素下
        class CreateElement {
            // 构造函数,传入标签名,文本内容,和元素默认类名
            constructor(element, text, className = 'element') {
                // 1.创建元素
                const node = document.createElement(element)
                // 2.添加类名
                node.classList.add(className)
                // 3.添加文本内容(双标签有效,单标签无效)
                node.innerText = text

                // 4.将创建的元素节点存入到属性node
                this.node = node
            }

            // 将当前创建的元素 添加到指定父元素下
            appendTo(selector) {
                // 获取父元素
                const parent = document.querySelector(selector)
                // 添加子元素
                parent.appendChild(this.node)
            }
        }

        // 直接创建一个普通元素
        const div = new CreateElement('div', '做人开心就好')
        div.appendTo('body')

        // 图片标签不适用于普通元素创建(有属性src),但是想使用默认的样式和创建过程
        // 创建子类 继承 父类
        class CreateImg extends CreateElement {
            // 自己的构造函数:只需要传入图片
            constructor(src, className = 'element') {
                // 父类构造函数
                super('img', '', className)

                // 给创建的元素增加src属性
                this.node.src = src
            }
        }

        // 改变了创建的内容,但是可以直接应用父类继承的方法
        const img = new CreateImg('images/02.jpg')
        img.appendTo('body')

    </script>
</body>

</html>

2.函数参数默认值

定义函数的同时,可以给形参一个默认值

    // 定义函数的同时,可以给形参一个默认值
    function show(msg = "大家一起快活呀") {
      console.log(msg);
    }

    show();// 打印 大家一起快活呀
    show("搞笑不");// 打印 搞笑不

3.对象简写

在定义对象的时候,如果属性名和变量名一直,那么可以实现简写

    const name = "悟空";
    const skill = "72变";
    const say = function () { }
    const obj = {
      name, skill, say
    }
    console.log(obj);// {name:"悟空",skill:"72变",say:function(){}}

对象的方法也可以简写

    const obj = {
      say() {
        console.log(this);
      }
    }

4.Set

1.永远不会有重复元素的对象

2.可以理解为不重复的数组

    const set = new Set([1, 5, 3, 4]);
    set.add(5);
    set.add(5);
    console.log(set);

Set对象转为数组

const set = new Set([1, 5, 3, 4]);
set.add(5);
set.add(5);
console.log(set);

const arr = [...set];// 将set对象转数组
console.log(arr);

5.函数的四种调用模式

根据函数内部this的指向不同,可以将函数的调用模式分成4种

  1. 函数调用模式
  2. 方法调用模式
  3. 构造函数调用模式
  4. 上下文调用模式(借用方法模式)

1.函数调用模式

如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window

function fn(){
  console.log(this);// 指向window 
}
fn();

2.方法调用模式

当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象

const obj = {
  sayHi:function(){
    console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
  }
}
obj.sayHi();

3.构造函数调用模式

如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。

function Person(){
  console.log(this);
}
Person();//this指向什么?
var p = new Person();//this指向什么?

4.方法借用模式

也叫上下文模式,分为 apply 与 call

1.call

call方法可以调用一个函数,并且可以指定这个函数的this指向

    const RichWumon = {
      name: "富婆",
      say: function () {
        console.log(this.name, " 我要重金求子");
      }
    }

    const obj = {
      name: "屌丝"
    }

    RichWumon.say();			// 富婆
    RichWumon.say.call(obj);	// 屌丝

2.all应用

  1. 将伪数组转成数组
	
    let divs = document.querySelectorAll('div');
    // let divs = document.body.children;
    console.log(divs);

    function change(nodelist) {
        console.log(Object.prototype.toString.call(nodelist));
        return Array.prototype.slice.call(nodelist);

    }

3.apply

就是apply()方法接受的是一个包含多个参数的数组。而call()方法接受的是若干个参数的列表

可以利用apply 将 刚才的call 的代码修改一下

    const RichWumon = {
      name: "富婆",
      say: function () {
        console.log(this.name, " 我要重金求子");
      }
    }

    const obj = {
      name: "屌丝"
    }

    RichWumon.say();			// 富婆
    RichWumon.say.apply(obj);	// 屌丝

4.apply应用

1.简化log方法

	// 简化log方法
    function log() {
        // 不需要改变this
        console.log.apply(console, arguments);
    }

5.bind方法

**bind()**方法创建一个新的函数, 可以绑定新的函数的this指向

var name = '张三';
function Fn(){
    this.age = 1;
    
    console.log(this.name + this.age);
}

Fn();			// 张三 1

// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
let obj = {
    name:'小强',
}
const newFn = Fn.bind(obj);
newFn();		// 小强 1