原型和原型链条、ES6、前后端交互Ajax

一、原型和原型链条

1.原型
 <script>
    /*
      原型
        + 解决问题
          => 当你需要给实例对象添加方法
          => 直接书写在构造函数体内
          => 这个行为并不好
          => 我们的原型就是解决了这个问题
        + 不好的原因
          => 当我把方法书写在构造函数体内
          => 每次创建实例的时候, 都会创建一个函数数据类型
          => 多个函数方法, 一模一样, 但是占据了多分存储空间
    */

    function Person(name, age) {
      // 向实例对象内添加属性
      this.name = name
      this.age = age

      // 向实例对象内添加方法
      // 在构造函数体内直接向实例对象添加方法, 这个行为并不好
      this.sayHi = function () { console.log('hello world') }
    }

    // 创建一个实例
    var p1 = new Person('Jack', 18)
    // 创建第二个实例
    var p2 = new Person('Rose', 20)

    console.log(p1)
    console.log(p2)

    console.log(p1.sayHi)
    console.log(p2.sayHi)
    console.log(p2.sayHi === p1.sayHi)

  </script>
2.解决问题
<script>
解决问题
   + 原型
     => 概念: 每一个构造函数天生自带一个 prototype 属性, 是一个对象数据类型
     => 概念: 每一个对象天生自带一个属性 __proto__, 指向所属构造函数的 prototype
     => 概念: 当你访问对象的成员的时候, 首先在自己身上查找, 如果没有, 自动去到 __proto__ 上查找
   + 如何解决问题
     => 我们把需要添加给实例的方法, 放在构造函数的原型(prototype)
     => 就可以有实例进行访问使用
   + 原型:
     => 构造函数天生自带的一个 prototype
     => 作用: 有构造函数添加方法, 专门给实例对象使用

    // 当函数被书写完毕以后
    // 就会有 prototype 出现
    // function Person() {}

    // // 直接向 prototype 内添加一些成员
    // Person.prototype.a = 100
    // Person.prototype.b = 200

    // console.log(Person.prototype)

    // // 创建一个实例对象
    // // p1 所属的构造函数就是 Person
    // // p1.__proto__ === Person.prototype
    // var p1 = new Person()
    // console.log(p1.__proto__ === Person.prototype)
    // console.log(p1.__proto__)


    // // 当你访问 p1 的 a 成员
    // // 因为当你访问 p1.a 的时候, 自己没有, 会自动去自己的 __proto__ 上查找
    // // 又因为 自己的__proto__ 就是 Perosn.prototype
    // // 所以, 其实就是去到 Person.prototype 上查找
    // console.log(p1.a)



    function Person(name, age) {
      // 向实例对象上添加属性
      this.name = name
      this.age = age

      // 向实例对象上添加方法
      // this.sayHi = function () { console.log('hello world') }
    }

    // 把想添加给实例对象的方法, 书写原型上
    Person.prototype.sayHi = function () { console.log('hello world') }


    // 创建实例对象
    // p1 和 p2 所属的构造函数都是 Person
    // p1.__proto__ === Person.prototype
    // p2.__proto__ === Person.prototype
    var p1 = new Person('Jack', 18)
    var p2 = new Person('Rose', 20)

    console.log(p1)
    console.log(p2)
    console.log(p1.__proto__ === Person.prototype)
    console.log(p2.__proto__ === Person.prototype)

    // 当你访问 p1 的sayHi 的时候
    // 自己没有, 回去自己的 __proto__ 上找
    console.log(p1.sayHi)

    // 当你访问 p2 的sayHi 的会搜
    // 自己没有, 会去自己的 __proto__ 上找
    console.log(p2.sayHi)

    // 因为 p1.__proto__ 和 p2.__proto__ 是一个对象空间
    // p1 和 p2 的 sayHi 是一个
    console.log(p1.sayHi === p2.sayHi)
  </script>
3.原型链
 <script>
      问题1: 实例对象身上的 __proto__ 指向谁 ?
        => 指向所属构造函数的 prototype
        => p1 所属的构造函数是 Person
        => p1.__proto__ 指向 Person.prototype
      问题2: Person.prototype 的 __proto__ 指向谁 ?
        => Person.prototype 所属的构造函数是谁
        => 因为 Perosn.prototype 是一个对象数据类型(Object)
        =>JS 内所有的 Object 数据类型都是属于 Object 这个内置构造函数
        => Person.prototype 是属于 Object 这个内置构造函数的
        => Person.prototype 的 __proto__ 指向 Object.prototype
      问题3: Person 的 __proto__ 指向谁 ?
        => Person 是一个函数, 函数本身也是一个对象, 就会有 __proto__
        =>JS, 所有的函数都是属于内置构造函数 Function 的实例
        => Person.__proto__ 指向 Function.prototype
      问题4: Object.prototype 的 __proto__ 指向谁 ?
        => Object.prototype 是一个对象数据类型, 只要是对象, 都是数据 Object 这个内置构造函数的
        => 注意: Object.prototype 在 JS 内叫做顶级原型, 不在有 __proto__ 
        => Object.prototype 的 __proto__ 指向 null
      问题5: Object 的 __proto__ 指向谁 ?
        => Object 是内一个内置构造函数, 同时也是一个函数, 同时也是一个对象
        =>JS, 所以的函数都是属于内置构造函数 Function 的实例
        => Object 也是 Function 的实例
        => Object.__proto__ 指向 Function.prototype
      问题6: Function.prototype 的 __proto__ 指向谁 ?
        => Function.prototype 也是一个对象数据类型
        => 只要是对象数据类型都是 Object 的实例
        => Function.prototype 的 __proto__ 指向 Object.prototype
      问题7: Function 的 __proto__ 指向谁 ?
        => Function 也是一个内置构造函数, 也是一个函数
        =>JS, 所有的函数都是属于内置构造函数 Function 的实例
        => Function 自己是自己的构造函数
        => Function 自己是自己的实例对象
        => Function 所属的构造函数的是 Function

      原型链
        + 用 __proto__ 串联起来的对象链状结构
        + 注意: 使用 __proto__
        + 每一个对象数据类型, 都有一个属于自己的原型链
        + 作用: 为了访问对象成员

      对象访问机制:
        + 当你需要访问对象的成员的时候
        + 首先在自己身上查找, 如果有直接使用
        + 如果没有, 会自动去 __proto__ 上查找
        + 如果还没有, 就再去 __proto__ 上查找
        + 直到 Object.prototype 都没有, 那么返回 undefined

    function Person() {}

    var p1 = new Person()

  </script>

原型和原型链条、ES6、前后端交互Ajax_第1张图片
原型和原型链条、ES6、前后端交互Ajax_第2张图片

原型和原型链条、ES6、前后端交互Ajax_第3张图片

二、ES6

1.ES6定义变量
<script>
    // 1. 预解析
    // console.log(num)
    // var num = 100
    // console.log(num)

    // 定义之前使用 let 声明的变量会报错
    // console.log(num2)
    // let num2 = 200
    // console.log(num2)

    // 定义之前使用 const 声明的变量会报错
    // console.log(num3)
    // const num3 = 300
    // console.log(num3)


    // 2. 重复变量名
    // var n1 = 100
    // var n1 = 200
    // console.log(n1)

    // let n2 = 100
    // let n2 = 200

    // const n3 = 100
    // const n3 = 200

    // 3. 块级作用域
    // 任何一个可以执行代码段的 {} 都会限制该变量的使用范围
    // if (true) {
    //   var num = 100
    //   console.log(num)
    // }
    // console.log(num)

    // if (true) {
    //   // 因为这个 num 使用 let 关键字定义的
    //   // 所以只能在这个 if 的 {} 内使用
    //   let num = 100
    //   console.log(num)
    // }
    // console.log(num)

    // if (true) {
    //   // 因为这个 num 使用 const 关键字定义的
    //   // 所以只能在这个 if 的 {} 内使用
    //   const num = 100
    //   console.log(num)
    // }
    // console.log(num)



    // 4. 定义时不赋值
    // let num
    // console.log(num)
    // num = 100
    // console.log(num)

    // 使用 const 的时候, 声明时必须赋值
    // const num
    // console.log(num)
    // num = 100
    // console.log(num)


    // 5. 修改
    // let num = 100
    // console.log(num)
    // num = 200
    // console.log(num)

    const num = 100
    console.log(num)
    // 你试图修改 num 的值, 但是因为是 const 定义的, 不能修改
    num = 200
    console.log(num)


  </script>
2.ES6的箭头函数
<script>
    // var fn1 = function () { console.log('我是 fn1 函数') }
    // fn1()

    // var fn2 = () => { console.log('我是 fn2 函数') }
    // fn2()

    /*
      箭头函数的特殊之处

      1. 箭头函数某些时候可以省略 ()
        => 当你的形参只有一个的时候, 可以不写 ()

      2. 箭头函数某些时候可以省略 {}
        => 当你的代码只有一句话的时候, 可以不写 {}
        => 并且会自动把这一句话的结果当做函数的返回值

      3. 箭头函数内没有 arguments

      4. 箭头函数内没有 this
        => 箭头函数内的 this 就是外部作用域的 this
    */

    // 1.
    // var fn1 = () => { console.log('我没有形参') }
    // fn1()

    // var fn2 = a => { console.log('我一个形参 : ', a) }
    // fn2(100)

    // var fn3 = (a, b) => { console.log('我两个形参: ', a, b) }
    // fn3(100, 200)


    // 2.
    // var fn1 = (a, b) => a + b
    // console.log(fn1(10, 20))

    // 3.
    // var fn1 = () => {
    //   console.log(arguments)
    // }
    // fn1(100, 200, 300)

    // var fn2 = function () {
    //   console.log(arguments)
    // }
    // fn2(100, 200, 300)

    // 4.
    var obj = {
      fn: function () { console.log(this) },
      fn2: () => { console.log(this) }
    }

    obj.fn() // this 因为 fn 函数被 obj 调用, 所以 this 是 obj
    obj.fn2() // 因为是箭头函数, 内部没有 this, 就是外部作用域的 this
  </script>
3.ES6的函数默认值
<script>
    function fn(a = 100, b = 200) {
      // 表示声明了两个形参
      // 其中 a 设置默认值为 100
      // 其中 b 设置默认值为 200
      console.log('a : ', a)
      console.log('b : ', b)
      console.log('---------------------')
    }

    // 两个实参都没有传递, 都会使用默认值
    fn()

    // 给 a 进行了赋值, a 就使用 10
    // b 继续使用默认值 200
    fn(10)

    // 给 a 进行了赋值, a 就使用 10
    // 给 b 进行了赋值, b 就使用 20
    fn(10, 20)
  </script>
4.ES6 解构赋值
 <script>
    // 1. 解构数组
    // var arr = [ 'hello', 'world' ]

    // // 开始解构
    // // 注意: 解构数组使用 []
    // // a 获取的内容就是 arr[0]
    // // b 获取的内容就是 arr[1]
    // var [ a, b ] = arr

    // console.log(a)
    // console.log(b)


    // 2. 解构对象
    var obj = { name: 'Jack', age: 18 }

    // 开始解构
    // 注意: 解构对象使用 {}
    // 表示定义一个叫做 name 的变量, 获取的是 obj 内一个叫做 name 的成员的值
    // var { name, age, a } = obj
    // console.log(name)
    // console.log(age)
    // console.log(a)

    // var a = obj.age
    // console.log(a)

    // 相当于定义变量 a 从 obj 内获取一个叫做 a 的成员的值
    // var { a } = obj
    // console.log(a)
    // 可以起一个别名
    // 相当于顶一个 a 变量, 从 obj 内获取一个叫做 age 的值
    var { age: a } = obj // => var a = obj.age
    console.log(a)
  </script>
5.ES6的模板字符串
 <script>
   
	 + 其实, 就是 ES6 内新增的定义字符串的方式
	   + 以前:
	     => var str = '内容'
	     => var str = "内容"
	   + 现在:
	     => var str = `内容`
	
	 区别:
	   1. 可以换行书写
	   2. 可以直接在字符串内解析变量
	     => 当你需要解析变量的时候, 直接书写 ${ 变量 }

    // 1.
    // var s1 = 'hello world'
    // var s2 = "hello world"
    // var s3 = `

    // hello
    // world


    // `
    // console.log(s1)
    // console.log(s2)
    // console.log(s3)


    // 2.
    var age = 18
    var s1 = `我叫前端小灰狼, 今年 ${age}`
    console.log(s1)

    var s2 = '我叫前端小灰狼, 今年 ${age} 岁'
    console.log(s2)

    var s3 = "我叫前端小灰狼, 今年 ${age} 岁"
    console.log(s3)

  </script>
6.ES6 的展开运算符
<script>
    /*
        + ...
        + 作用: 展开数组的[] 或者展开对象的 {}
    */

    // console.log(100, 200, 300, 400)
    // var arr = [ 100, 200, 300, 400 ]
    // console.log(arr)
    // console.log(...arr)

    // 作用1: 合并数组
    // var arr1 = [ 10, 20 ]
    // var arr2 = [ 30, 40 ]
    // var arr3 = [ 50, 60, 70 ]
    // var arr4 = [ 80, 90 ]
    // var arr5 = [ ...arr1, ...arr2, ...arr3, ...arr4 ]
    // console.log(arr5)

    // 作用2: 给函数传递参数
    // var arr1 = [ 10, 20, 17, 7, 31, 22, 12 ]
    // // var max = Math.max(10, 20, 17, 7, 31, 22, 12)
    // // var max = Math.max(arr1)
    // var max = Math.max(...arr1)
    // console.log(max)


    // 展开对象
    var obj = { name: 'Jack', age: 18 }
    console.log(obj)

    // 作用1: 用来复制对象
    // 注意: 展开书写的顺序问题, 在有相同成员的时候
    var obj2 = {
      gender: '男',
      ...obj,
      name: 'Rose',
    }
    console.log(obj2)
  </script>
7.ES6 的类语法
 <script>
    /*
      ES6 的类语法
        + 语法:
          class 类名 {
            // 原先 ES5 内的构造函数体
            constructor () {}

            // 直接书写原型上的方法即可

            // 书写静态属性和方法, 需要加上一个 static 关键字即可
          }
        + 注意: 必须和 new 关键字连用
          => 不和 new 关键字连用, 会直接报错
    */

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

    // // 原型添加一个方法
    // // 2. 原型上的方法, 目的是为了给 实例使用
    // Person.prototype.sayHi = function () { console.log('hello world') }

    // // 书写静态属性和方法
    // Person.a = 100
    // Person.go = function () { console.log('跑起来') }

    // var p1 = new Person('jack', 18)
    // console.log(p1)
    // p1.sayHi()

    // // 1. 构造函数本质还是一个函数, 可以不和 new 关键字连用
    // var p2 = Person('Rose', 20)
    // console.log(p2)

    // console.log(Person.a)
    // Person.go()


    // 类的书写
    class Person {
      constructor (name, age) {
        // 这里按照 ES5 的构造函数体书写
        this.name = name
        this.age = age
      }

      // 直接书写原型上的方法即可
      sayHi () { console.log('你好 世界') }

      // 静态属性
      static a = 100

      // 静态方法
      static go () { console.log('running') }
    }

    var p1 = new Person('张三', 18)
    console.log(p1)
    p1.sayHi()

    // 使用静态属性和静态方法
    Person.go()
    console.log(Person.a)


  </script>

三、前后端交互Ajax

1.第一次尝试 ajax
<script>
    // 1. 创建一个 ajax 对象
    var xhr = new XMLHttpRequest()

    // 2. 配置本次的请求信息
    // 请求方式: 按照接口文档来进行书写
    // 请求地址: 按照接口文档来进行书写
    // 是否异步: 默认是 true 表示异步请求, 选填为 false, 表示同步请求
    xhr.open('GET', 'http://localhost:8888/test/first', true)

    // 3. 配置一个请求完成后触发的事件
    // 请求完整: 本次请求发送出去, 服务器接收到了我们的请求, 并且服务器返回的信息已经回到了浏览器
    xhr.onload = function () {
      // 如何拿到后端返回的信息
      // 语法: xhr.responseText
      console.log(xhr.responseText)
    }

    // 4. 把本次请求发送出去
    xhr.send()
  </script>
2.第二次测试 ajax
 <script>
    // 1. 创建ajax 对象
    var xhr = new XMLHttpRequest()

    // 2. 配置本次的请求信息
    xhr.open('GET', 'http://localhost:8888/test/second', true)

    // 3. 配置请求完成的事件
    xhr.onload = function () {
      // 当后端返回的是 json 格式字符串的时候, 我们需要进行单独的解析
      // 语法: JSON.parse(json格式字符串)
      // 返回值: 解析好的 js 格式的数据
      var res = JSON.parse(xhr.responseText)
      console.log(res)
    }

    // 4. 发送出去
    xhr.send()
  </script>
3.GETPOST 请求
<script>
    // 1. GET 请求
    // var xhr = new XMLHttpRequest()
    // // 需要携带参数
    // // 因为是 GET 请求, 直接在地址后面进行参数的书写
    // xhr.open('GET', 'http://localhost:8888/test/third?name=前端小灰狼&age=18', true)
    // xhr.onload = function () {
    //   console.log(JSON.parse(xhr.responseText))
    // }
    // xhr.send()

    // 2. POST 请求
    var xhr = new XMLHttpRequest()
    // 注意: 因为是 POST 请求, 不需要在地址后面拼接参数
    xhr.open('POST', 'http://localhost:8888/test/fourth', true)
    xhr.onload = function () {
      console.log(JSON.parse(xhr.responseText))
    }

    // 注意: 当你发送 POST 请求, 并且需要携带参数的时候, 需要进行特殊说明
    // 语法: xhr.setRequestHeader('content-type', 你传递参数的格式)
    xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')

    // send 后面的() 就是书写请求体的位置
    xhr.send('name=前端小灰狼&age=18')
  </script>
4.登录案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    form {
      width: 500px;
      padding: 20px;
      margin: 50px auto;
      border: 3px solid pink;
      display: flex;
      flex-direction: column;
      font-size: 30px;
      padding-top: 50px;
      position: relative;
    }

    form > span {
      position: absolute;
      left: 50%;
      top: 5px;
      transform: translateX(-50%);
      width: 100%;
      text-align: center;
      color: red;

      display: none;
    }

    form > label {
      height: 50px;
    }

    form > label > input {
      font-size: 24px;
      height: 40px;
      padding-left: 20px;
    }
  </style>
</head>
<body>

  <form>
    <span class="error">用户名或者密码错误!!</span>
    <label>
      用户名 : <input class="username" type="text">
    </label>
    <label>
      密  码 : <input class="password" type="text">
    </label>
    <button>登录</button>
  </form>

  <script>
    /*
      案例 - 登录

      分析需求:
        + 问题1: 什么时候进行发送请求 ?
          => 点击登录按钮的时候
          => 需要给 form 标签绑定一个表单提交事件
        + 问题2: 需要拿到哪些信息 ?
          => 需要拿到用户填写的用户名和密码
        + 问题3: 需要如何发送给后端 ?
          => 按照接口文档的规范进行发送
        + 问题4: 请求完成以后, 我们需要做什么 ?
          => 根据后端返回的信息, 进行一些后续的操作
          => 如果后端返回的信息是登录成功, 那么我们进行页面跳转
          => 如果后端返回的是登录失败, 那么我们提示用户错误
    */

    // 0. 获取元素
    // 0-1. form 标签
    var loginForm = document.querySelector('form')
    // 0-2. 用户名文本框
    var nameInp = document.querySelector('.username')
    // 0-3. 密码文本框
    var pwdInp = document.querySelector('.password')
    // 0-4. 错误提示文本
    var errBox = document.querySelector('.error')

    // 1. 给 form 标签绑定一个表单提交事件
    loginForm.onsubmit = function (e) {
      // 注意: 阻止表单的默认提交行为
      e.preventDefault()

      // 2. 拿到填写的用户名和密码
      var name = nameInp.value
      var pwd = pwdInp.value

      // 2-2. 验证用户名和密码
      if (!name || !pwd) return alert('请完整填写表单')

      // 3. 发送 ajax 请求
      var xhr = new XMLHttpRequest()
      xhr.open('POST', 'http://localhost:8888/users/login', true)
      xhr.onload = function () {
        // 因为后端返回的是 json 格式数据
        var res = JSON.parse(xhr.responseText)
        console.log(res)

        // 进行条件判断
        if (res.code === 0) {
          // 登录失败了
          errBox.style.display = 'block'
        } else {
          // 登录成功了
          window.location.href = './home.html'
        }
      }

      // 注意: POST 请求携带参数需要提前说明
      xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')

      // 因为 POST 请求携带参数是在请求体内
      xhr.send('username=' + name + '&password=' + pwd)
    }

  </script>
</body>
</html>

你可能感兴趣的:(前端,Ajax,JavaScript,es6,ajax,javascript,css,html,前端,开发语言)