JS 第三天(+Ajax 新知识)

131 阅读1分钟

JS高级 第三天

一、set数组去重

<script>
        const beforeArr = [`a`,`b`,`c`]
        const set = new Set(beforeArr)

        set.add(1)
        set.add(2)
        set.add(2) // 发现重复 内部自动过滤
        console.log(set);

        const arr = [...set] // 把set 转换成数组
        console.log(arr);
</script>

运用set进行数组去重案例

<script>
        let ul = document.querySelector(`ul`)
        let inp = document.querySelector(`input`)
        let arr = [`文本1`, `文本2`]
        render()
        inp.addEventListener(`keydown`, function (e) {
            if (e.key === `Enter`) {
                let set = new Set(arr)
                set.add(inp.value)
                arr = [...set]
                render()
            }
        })
        function render() {
            let lis = arr.map((Value) => `<li>${Value}</li>`).join(``)
            ul.innerHTML = lis
        }
</script>

总结

​ 1.set方法,用new调用

​ 2.set是对象,需要转换成数组

二、this指向

普通函数 this

<script>
        function func() {
            console.log(this);
        }
        func() // this 指向winodw 这是一个定义在全局变量的函数 window.func1()

        const obj = {
            name: `黄某`,
            say() {
                console.log(this);
            }
        }
        obj.say() // this 指向obj

        function Person() {
            this.name = `悟空`
        }
        Person.prototype.say = function () {
            console.log(this);
        }
        const p1 = new Person()
        p1.say() //this=p1
        console.log(p1);
</script>

箭头函数 this

<script>
    const func1 = () => {
            console.log(this);
        }
        func1()

        const obj1 = {
            name:`悟空`,
            say:()=>{
                console.log(this);
            }
        }
        obj1.say()

        const obj2 = {
            name:`悟空`,
            obj3:{
                name1:`悟空2`,
                say:()=>{
                    console.log(this);
                }
            }
        }
        obj2.obj3.say()

        const button = document.querySelector(`button`)
        button.addEventListener(`click`,function(){
            console.log(this); // this 指向 button
        })
        button.addEventListener(`click`,()=>{
            console.log(this); // this 指向 winodws
        })
</script>

总结(大部分情况)

​ 1.普通函数 this等于函数调用者

​ (例外:bind call apply)

​ 2.箭头函数 this等于window

​ (例外:面向对象中用法 存在例外)

​ 3.箭头函数和this 一起用要慎用!!!

三、call,apply,bind

三种方式修改this的区别

<script>
        const obj = {
            name:`老王`,
            skill(){
                console.log(this.name+` 翻墙`);
            }
        }
        
        const person = {
            name:`大朗`
        }
        obj.skill.call(person) // call 修改this指向 大朗借用了老王的方法

        obj.skill.apply(person) // apply 大朗借用老王方法

        const func = obj.skill.bind(person) // bind 不会直接调用skill方法 而是返回一个新的函数
        func() // 主要调用新函数 - 调用skill()
    </script>

三种方式传递参数的区别

<script>
        const obj = {
            name:`老王`,
            skill(a,b){
                console.log(this.name+``+a+``+b);
            }
        }
        
        const person = {
            name:`大朗`
        }

        obj.skill.call(person,1,2) // 之前所学call借调方法
        obj.skill.apply(person,[1,2]) // apply 传递参数 必须用数组形式

        const func = obj.skill.bind(person)
        func(1,2) // 在新的函数上直接传参
</script>

总结

​ 1.bind call apply 都可以实现 修改this指向

​ 2.注意使用上代码的区别,bind需要返回一个新的函数再调用

​ 3.传递参数上代码的区别:apply传参要用数组类型,bind在调用的新函数内传参

以前使用apply 计算数组最值方法

<script>
		const arr = [1,2,3,4,5]
        // null this是第一个参数 这里不需要修改this 所以传入null
        let max = Math.max.apply(null,arr)
        console.log(max);
</script>

四、es6面向对象

es5-es6区别

<script>
        function Person(name) {
            this.name =name
        }
        Person.prototype.say = function(){
            console.log(this.name+`调用`);
        }

        const p1 = new Person(`悟空`)
        console.log(p1);
        p1.say()
</script>
<script>
        class Person{
            // 指构造函数=es5 Person内区域 
            constructor(name) {
                this.name = name
            }

            //行为 如同原型对象,行为 = person.prototype.say
            say(){
                console.log(this.name+`调用`);
            }
        }

        const p1 = new Person(`悟空1`)
        const p2 = new Person(`悟空2`)
        console.log(p1,p2);
        console.log(p1.say===p2.say); // true 不浪费内存
</script>

1650769911129

总结

​ 1.es6通过一个关键字 class 来确定

​ 2.属性行为都写在这个class方法内

​ 3.class是方法,不是对象 不用逗号隔开

继承区别

<script>
        function Person(name) {
            this.name = name
        }
        Person.prototype.say = function(){
            console.log(this.name+`调用`);
        }
        Person.prototype.fly = function(){
            console.log(this.name+`起飞`);
        }

        function Son(name,color) {
            Person.call(this,name)
            this.color = color
        }
        Son.prototype.say = Person.prototype.say
        Son.prototype.fly = Person.prototype.fly
        const s1 = new Son(`儿子`,`red`)
        console.log(s1);
        s1.say()
        s1.fly()
</script>
<script>
        class Person {
            constructor(name){
                this.name = name
            }

            say(){
                console.log(this.name+`调用`);
            }

            fly(){
                console.log(this.name+`起飞`);
            }
        }

        	//extends 就表示 继承 
       class Son extends Person {
            // 如果写了构造和extends必须加super 不加super 报错 Must call super
       constructor(name,color){
            super(name) // 父亲的构造函数 = Person.call(this,name)
                this.color = color
            }
        }

        const s1 = new Son(`儿子`,`red`)
        console.log(s1);
       	s1.say()
        s1.fly()
</script>

总结

​ 1.es6中继承注意写extends不写constructor 就不需要写super

​ 2.如果写了extends还写了constructor 就必须写super

​ 3.super()=Person.call(this,name)

es6继承封装案例

<script>
        class Element {
            constructor(dom) {
                dom = document.createElement(dom)
                this.dom = dom

            }

            append(ParerntSelect) {
  document.querySelector(ParerntSelect).appendChild(this.dom)
            }
        }

        class ElementDouble extends Element {
            constructor(dom, text) {
                super(dom)
                this.dom.innerText = text
            }
        }

        class ElementSingle extends Element {
            constructor(dom, src) {
                super(dom)
                this.dom.src = src
            }
        }
        
        const divModel = new ElementDouble(`div`, `文字内容`)
        divModel.append(`body`)

        const imgModel = new ElementSingle(`img`, `./img/01.jpg`)
        imgModel.append(`div`)
</script>

对比es5封装

<script>
        function Element(Node) {
            const dom = document.createElement(Node)
            this.dom = dom
        }
        Element.prototype.append = function (ParentNode) {
            document.querySelector(ParentNode).appendChild(this.dom)
        }

        function ElementDouble(Node, text) {
            Element.call(this, Node)
            this.dom.innerText = text
        }
	ElementDouble.prototype.append = Element.prototype.append

        //儿子二 构造的函数
        function ElementSingle(Node, src) {
            Element.call(this, Node)
            this.dom.src = src
        }
	ElementSingle.prototype.append = Element.prototype.append

        const divModel = new ElementDouble(`div`, `文字内容`)
        divModel.append(`body`)

        const imgModel = new ElementSingle(`img`, `./img/01.jpg`)
        imgModel.append(`div`)
</script>

es6补充-es5原型链

<script>
        class Person {
            constructor(name) {
                this.name = name
            }
            // 写法二 无区别
            color = `yellow`
            height = 180
            weight = 200


            say() {
                console.log(this.name + `调用`);
            }
            tall = function () {
                console.log(this.color+`写法二`);
            }
            // this配合箭头函数 大多数情况指向winodw 这里配合面对对象是例外
            make =()=>{
                console.log(this+`这里this指向调用者`);
            } 
        }

        const p1 = new Person(`悟空1`)
        const p2 = new Person(`悟空2`)
        p1.say()
        p1.tall()
        p1.make()
        console.log(p1.say === p2.say); // true
        console.log(p1.tall===p2.tall); // false
        console.log(p1.make===p2.make); // false
</script>

总结

​ 1.属性定义写在构造函数内 this.name = name

​ 2.属性定义写在大括号内 name = “悟空”

​ 3.方法写法1:say(){}

​ 4.方法写法2:say=function(){}

​ 5.方法写法3:say=()=>{}

​ 6.箭头函数中this例外情况,用在es6的calss充当方法 this 指向 p1 实例

​ 7.方法写法1性能最好,其余会有占内存浪费性能问题

原型链本质:

​ 一个对象,可以通过prototype来找到被它继承父亲的方法

​ 一个对象从底层触发,通过prototype 一层一层 往上找到继承的关系

原型链作用:

​ 需要给某个数据(字符串,数组,对象) 统一添加一个方法,可以直接在原型上添加,这样就可以复用

1650785869635

<script>
        // 万物皆对象 这样这个方法就会在对象原型内,可以复用
        Object.prototype.show = function(){
            console.log(`我创的`);
        }

        // 数组也是可以被new 的
        const arr = new Array(`a`,`b`,`c`)

        // 也就代表,JS内置的数组可以使用原型 
        Array.prototype.show = function(){
            console.log(`爷自创`);
        }
        arr.show() // 所以arr就调用这个方法 arr.push arr.map 等方法都是如此。
        console.log(arr);
    
       // 对象的创建也分两种清空
      // const ojb={};// 字面量 常用 直接 简单
      const obj = new Object(); // 利用构造函数的方式来创建对象
      Object.prototype.show = function () {
        console.log('对象 自己的show方法');
      };
      obj.show();

        console.dir(document.querySelector(`div`))
</script>

总结:

​ 1.可以利用原型对象的方式,在任意的构造函数上添加想要的行为

​ 2.任意的构造函数 包括自己定义的构造函数

​ 3.也包括JS内置就有的构造函数 Array等 (arr.push();arr.map()....)

​ 4.如果改了内置构造函数的原型对象上的行为(方法),后果很严重!!

<script>
    	Array.prototype.forEach=function(){
        	console.log("老子罢工了");
      	}
      	Array.prototype.map=function(){
        	console.log("老子罢工了");
      	}
      	const arr=[1,2,3];
      	arr.forEach(); // 不能正常使用了 被修改为如上
</script>

Ajax

一、服务器

本质:当我们上网看到的内容,在网络中的一台电脑上,这台电脑叫服务器。

作用:存储一个网站的文件(HTML css js 图片。。。)

1、资源:

本质:服务器上的网页、图片等文件都称为资源,资源代指服务器上存储的内容。通俗讲我们从网络上看到的内容都叫资源

1650793053803

2、数据

本质:网页中的数据,也是服务器对外提供的一种资源。

1650793093380

服务器多数情况都使用数据表方式存储数据

1650793141908

3、客户端

本质:前端开发中,客户端特指Web浏览器

作用:将互联网中的Web资源加载,并且呈现到浏览器给用户使用

前端其实也就是围绕客户端做操作

1650793277100

4、资源与URL地址

本质:表示服务器上每个资源的确切位置,每个资源对应独一的URL地址

1650802164490

1650802188817

作用:对数据操作(增删改查),也对应不同URL地址(不能搞混)

1650802252167

5、客户端与服务器通信

本质

​ 请求:客户端通过网络找到服务器要资源的过程

​ 响应:服务器把资源通过网络发送给客户端

1650802402379

6、Ajax

本质:Ajax是浏览器中的技术,实现客户端网页请求服务器的数据

1650802475838

使用场景

1650802495905

1650802503317

总结:

​ 1.服务器本质就是一台电脑

​ 2.前端开发中,客户端指浏览器

​ 3.网页中资源存储在服务器中

​ 4.URL对服务器数据操作需要找到对应的URL地址

​ 5.请求是由客户端发送的,响应是由服务器做出的

​ 6.有数据的地方就有Ajax,数据是网页的灵魂

二、请求方式

1.同步-异步

<body>
    <h1></h1>
    <h2></h2>
    <script>
        // 同步执行的代码 按顺序 马上得出结果
        console.log(document.querySelector(`body`));
        console.log(document.querySelector(`div`));

        // 异步执行的代码 虽然是0  输出 1 3 延时器
        console.log(1);
        setTimeout(() => {
            console.log(`延时器`);
        }, 0)
        console.log(3);

        setInterval(() => {
            document.querySelector('h1').innerText = Date.now();
        }, 10);

        setInterval(() => {
            document.querySelector('h2').innerText = Date.now();
        }, 10);
    </script>
</body>

总结

​ 1.同步代码结果会马上得到,按顺序一件一件做事(核酸排队)

​ 2.异步代码结果不会马上得到,可以同时做多件事(三个大妈共同输出吵架)

2.Ajax请求数据5种方式

1650802713232

总结

​ 1.操作服务器数据除了使用URL,还需要指定请求方式

​ 2.根据操作性质不同,请求的方式也不同

三、基础用法

axios

本质:专注于数据请求的库

语法

1650802867232

<script>
        axios({
            method:`get`,
            // 直接问后端要 我们只负责用对代码 然后请求成功
            url:`http://www.itcbc.com:3006/api/getbooks`
            // then 是axios封装的一个代码 服务器把数据返回,里面的代码就会触发
            // result 是一个形参 任意改
        }).then((result)=>{
            // 别人怎么定义 我们就怎么拿 因为这里底层套了两层data
            const arr = result.data.data // 数据里的 id bookname 等是固定的
            console.log(arr);
            render(arr)
        })

        function render(arr) {
            let html = arr.map((value)=>`<tr>
                <td>${value.id}</td>
                <td>${value.bookname}</td>
                <td>${value.author}</td>
                <td>${value.publisher}</td>
            </tr>`).join(``)
            document.querySelector(`tbody`).innerHTML = html
        }
</script>