js学习之路(七)

1. 对象访问机制 (上)

 /*
       对象访问机制 
         + 当你访问一个对象的成员的时候
         + 如果对象自己本身有, 直接返回结果给你, 停止查询
         + 如果对象自己本身没有, 会自动去 __proto__ 上访问
         + 有就给你返回结果, 停止查询
         + 如果还没有(未完待续)
 
       利用 prototype 和 __proto__ 和 对象访问机制
         + 解决了构造函数的不合理
         + 属性直接写在 构造函数体内
         + 方法书写在 构造函数的 prototype 上
         + 使用构造函数创建一个 有属性 有方法 合理的 对象
         + prototype作用: 就是为了书写一些方法给该构造函数的实例对象使用
           => 因为这个构造函数的每一个实例都可以访问这个构造函数的 prototype
     */
 
     function Person(name, age) {
       this.name = name
       this.age = age
     }
 
     Person.prototype.sayHi = function () { console.log('hello world') }
 
     // 使用 Person 创建一个对象
     let p1 = new Person('Jack', 18)
     console.log(p1)
 
     // 当我访问 p1.name 的时候, 自己就有
     console.log(p1.name)
     // 当我访问 p1.sayHi 的时候, 自己没有
     // 就去 p1.__proto__ 上找, 因为 p1.__proto__ === Person.prototype
     // 实际上就是去 Person.prototype 上找
     // 找到 sayHi
     p1.sayHi()
 
 
     // 再次创建一个实例化对象
     let p2 = new Person('Rose', 20)
 
     // 当我访问 p2.sayHi 的时候
     // 因为自己没有, 去到 p2.__proto__ 上找
     // 实际上也是去 Person.prototype 上找
     p2.sayHi()

2. 构造函数相关的 this 指向

/*
      构造函数相关的 this 指向
        1. 构造函数体内的 this 指向
          => 因为和 new 关键字连用, this 指向当前实例
        2. 构造函数原型上的方法里面的 this 指向
          => 因为方法是依靠实例对象在调用
          => this 指向当前实例
    */

    function Person() {
      this.name = 'Jack'
      console.log('构造函数体内 : ', this)
    }

    Person.prototype.fn = function () {
      console.log('我是 Person.prototype 上的 fn 方法')
      console.log('Person.prototype.fn : ', this)
    }

    // 创建实例
    let p1 = new Person()

    console.log('====================')
    console.log('====================')
    console.log('====================')

    // 调用方法
    // fn 时 Person.prototype 上的方法
    // 但是调用是依靠当前实例在调用
    // 标准的对象调用方式
    // p1.fn()   this 点前面是谁就是谁
    p1.fn() // this -> 当前实例

3. 对象访问机制

 /*
      对象访问机制
        + 当你访问一个对象的成员的时候, 会先在自己身上找
        + 自己没有去到 __proto__ 上找
        + 在没有, 再去 __proto__ 上找
        + 一直找到顶级对象的 __proto__ 都没有
        + 就返回 undefined

      分析:
        + 定义1: 每一个对象都有 __proto__
        + 随便一个实例化对象的 __proto__ 是所属构造函数的 prototype
        + 定义2: 每一个函数都有一个 prototype, 他是一个对象
        + 每一个构造函数的 prototype 应该也有 __proto__, 指向了谁 ?
        + 构造函数也是函数, 函数也是一个对象
        + 函数应该也有一个 __proto__, 指向了谁 ?

      定义:
        1. 每一个函数天生自带一个属性叫做 prototype, 是一个对象
        2. 每一个对象天生自带一个属性叫做 __proto__ 指向所属构造函数的 prototype
        3. 当一个对象, 没有准确的构造函数来实例化的时候, 我们都看作是内置构造函数 Object 的实例

      例子:
        1. var arr = [] , Array 的实例
        2. var obj = {} , Object 的实例
        3. var p1 = new Person() , Person 的实例
        4. var time = new Date() , Date 的实例
        5. var fn = function () {} , Function 的实例
        6. Person.prototype , Object 的实例
        7. Array.prototype , Objec 的实例

      结论:
        + 任何一个对象开始出发
        + **按照 __proto__ 开始向上查找**
        + 最终都能找到 Object.prototype
        + 我们管这个使用 __proto__ 串联起来的对象链状结构, 叫做原型链
        + 原型链作用: 为了对象访问机制服务
    */

    function Person() {
      this.name = 'Jack'
      this.age = 18
      this.gender = '男'
    }

    // 创建一个实例
    let p1 = new Person()

4. 原型链

原型链
        + 从任何一个对象出发, 按照 __proto__ 串联起来的对象链状结构
        + 为了对象访问机制而存在

      例子: 数组
        + 数组所属的构造函数是 Array
          => 数组.__proto__ === Array.prototype
          => Array.prototype.__proto__ === Object.prototype
          => 数组.__proto__.__proto__ === Object.prototype

      如果我想给 数组 扩展一个方法
        + 写在: Array.prototype 上
      如果我想给 函数 扩展一个方法
        + 写在: Function.prototype 上

      原型
        + 每一个函数天生自带的一个叫做 prototype 的属性
        + 为了存放一些方法, 给这个构造函数的所有实例使用

      constructor 属性(构造器)
        + 只有函数天生自带的那个 prototype 上才有
        + 表示我是哪一个构造函数所自带的 原型对象
        + 作用: 判断数据类型

    */

    // function Person() {
    // }

    // console.log(Person.prototype)

    // 使用 Perosn 构造函数创建一个对象
    // let p1 = new Person()
    // console.log(p1.constructor === Person)

    // 当我使用 p1 去访问 constructor 属性的时候
    // 自己没有, 去 p1.__proto__ 上找
    // 就是去 Person.prototype 上找
    // Person.prototype.constructor 是谁 ? Person
    // p1.constructor 就是 Person


    // console.log([].constructor === Array)
    // 访问的是 数组的 constructor 属性
    // 数组自己没有, 去到 数组.__protot__ 上找
    // 就是 Array.prototype
    // 找到的就是 Array.prototype.constructor ? Array

5. 判断数据类型

/*
      判断数据类型
        1. typeof
          => 准确的判断基本数据类型
          => 对于复杂数据类型并不准确

        2. constructor
          => 利用原型的属性
          => 利用对象访问机制

        3. instanceof
          => 语法: 对象 instanceof 构造函数

        4. Object.prototype.toString.call()
          => 语法: Object.prototype.toString.call(你要检测的数据类型)
    */

    // console.log(typeof 123)
    // console.log(typeof 'hello')
    // console.log(typeof true)
    // console.log(typeof undefined)
    // console.log(typeof null) // object
    // console.log(typeof {}) // object
    // console.log(typeof []) // object
    // console.log(typeof new Date) // object
    // console.log(typeof function () {})


    // constructor
    // var num = 123
    // console.log(num.constructor)
    // console.log('abc'.constructor)
    // console.log(true.constructor)
    // console.log([].constructor)
    // console.log((function () {}).constructor)
    // console.log((new Date()).constructor)
    // console.log(null.constructor)
    // console.log(undefined.constructor)


    // instanceof
    // console.log({} instanceof Object)
    // console.log((new String()) instanceof String)
    // console.log('' instanceof String)


    // Object.prototype.toString.call()
    // console.log(Object.prototype.toString.call(123))
    // console.log(Object.prototype.toString.call(''))
    // console.log(Object.prototype.toString.call(true))
    // console.log(Object.prototype.toString.call(undefined))
    // console.log(Object.prototype.toString.call(null))
    // console.log(Object.prototype.toString.call(new Date()))
    // console.log(Object.prototype.toString.call(function () {}))
    // console.log(Object.prototype.toString.call([]))
    // console.log(Object.prototype.toString.call({}))

6. 对象

<!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>
</head>
<body>

  <input type="text" id="username">

  <input type="text" id="txt">

  <script>
    /*
      对象
        + 我们数据类型的一种
        + 以键值对的形式存储数据
        + 因为 __proto__ 和 原型链 可以访问自己没有的属性

      for in 循环
        + 专门遍历对象
        + 遍历对象身上的所有属性
        + 遍历对象身上所有的 可枚举 的属性(包括原型链上的所有 可枚举 属性)
          => 一种是自定义的属性
          => 我们可以设置为可枚举属性

      对象自己的方法
        1. hasOwnProperty()
          => 查看是不是自己的属性
          => 语法: 对象.hasOwnProperty('你要检测的属性名')
        2. defineProperty() 数据劫持
          => 一种给对象添加属性的方法
          => 我可以给一个我设置的属性设置各种各样的行为状态
          => 语法: Object.defineProperty(给哪一个对象添加,  key, {
            添加的设置
          })

    */

    // function Person() {
    //   this.name = 'Jack'
    //   this.age = 18
    //   this.gender = '男'
    // }

    // Person.prototype.sayHi = function () { console.log('hello world') }

    // let p1 = new Person()
    // console.log(p1)

    // for (let key in p1) {
    //   console.log('我执行了', key)
    // }

    // console.log(p1.hasOwnProperty('sayHi'))



    // 数据劫持
    let obj = {
      name: 'Jack'
    }
    // 普通添加
    obj.age = 18

    var prop = {
      firstName: '张',
      lastName: '思锐'
    }

    // 数据劫持
    Object.defineProperty(obj, 'username', {
      // 对 obj.gender 属性进行一系列的配置
      // value: '男', // 这个成员值
      // enumerable: false, // 是否可枚举
      get () {
        return prop.lastName + prop.firstName
      },
      // 当你像修改劫持的数据的时候
      // 就会触发这个 set 函数
      // 接收一个形参, 就是你像修改的值
      set (val) {
        console.log('你想修改')
        console.log('你想改成 : ', val)
        // 通过在 set 里面修改 prop 对象里面的内容
        // 来达到修改 username 属性
        let a = val.slice(0, 1)
        let b = val.slice(1)
        prop.firstName = a
        prop.lastName = b
        let inp = document.querySelector('#username')
        inp.value = obj.username
      }
    })

    obj.name = 'rose'
    obj.age = 20

    // obj.username = '张三'

    var inp = document.querySelector('#txt')
    inp.addEventListener('input', () => {
      obj.username = inp.value
    })

    console.log(obj)
  </script>
</body>
</html>


7. ES6 的类

/*
      ES6 的类
        + 我们在 ES5 以前, 我们就用 函数 来充当 构造函数(类)
        + ES6 引入了一个 类 的概念
          => 就是使用一个新的关键字来定义 构造函数(类)
          => 定义完毕以后, 就是一个类, 不能当作函数来调用
          => 只能通过 new 来得到一个对象

      类的语法:
        + 语法: class 类名 {
            // 构造器, 我这个类创造的对象里面有哪些属性
            constructor () {
              this.name = xxx
              this.age = xxx
            }

            // 直接书写原型上的方法
            init () {} 原型上的方法 init
          }
          => 定义一个类
        + 注意: 一个 class 定义的 类 不能被当作普通函数执行
          => 不和 new 连用就报错了
    */

    // function Person() {
    //   this.name = 'Jack'
    //   this.age = 18
    // }
    // let p1 = new Person()
    // console.log(p1)
    // 本质还是一个函数, 是一个函数就可以直接调用
    // 当你将他当托普通函数来执行的时候,
    // 没有了创造对象的能力, this 指向改变了
    // Person() // this -> window

    class Person {
      // 构造器, 等价于我们的 构造函数题
      constructor (name, age) {
        this.name = name
        this.age = age

        this.init()
      }

      // 原型上的方法
      init () {
        console.log(this)
      }

      setScale () {

      }

      move () {

      }
    }

    // 使用 Person 类去创建对象
    let p1 = new Person('Jack', 18)
    console.log(p1)

    Person()

8.模块化开发

 /*
      模块化开发
        + 为什么需要模块化开发
          => 例子: 分页器, Pagination, creEle, setCss
            -> creEle 和 setCss 其实在很多地方都可以用
            -> 按照开发习惯, 应该把他们分开放
            -> a.js, 里面放上 creEle 和 setCss
            -> b.js, 里面放上 Pagination
          => 把一类方法放在一个单独的 js 文件里面
            -> 为了方便使用的时候, 只引入这一类方法的文件
            -> a.js 全都是封装的 操作 DOM 的方法
            -> b.js 全都是封装的 格式化 时间对象 的方法
            -> c.js 全都是封装的 和数字 相关的方法
          => 我们管这样一个封装好的 js 文件叫做一个 模块

        + 什么是模块化开发
          => 多个 js 文件之间的相互配合来实现效果
          => 一个 js 文件里面只封装一类内容

      问题: 由多个 js 文件出现的
        1. js 文件引入顺序
        2. js 文件之间的相互依赖不清晰
        3. js 文件内部的变量会污染全局
    */

9.模块化的发展

/*
      模块化的发展

      抽离一些功能
        1. a.js
          => 里面是操作 时间 的各种方法
        2. b.js
          => 里面是操作 DOM 的各种方法
        3. c.js
          => 里面进行整合和组装


      没有模块化
        + 按照顺序引入文件

      IIFE 伪模块化标准
        + Immediaitely Invoked Function Expression
        + 自执行函数 (function () {})()

      CommonJS 模块化标准
        + 2009 年, nodejs 出现了
        + 使用 JS 去做服务端语言
        + 伴生的是 CommonJS 模块化标准
        + 缺点: 只能在后端 JS 里面用

      AMD 模块化标准 - Async Module Definition
        + 2011 出现的, 社区里面发起的
        + 因为非官方, 没有关键字, 大家书写了一套叫做 require.js 的第三方文件
        + 来实现 模块化标准
        + 把每一个 js 文件独立出来了
          -> 使用了导入导出的语法来实现模块化
          -> 在 JS 文件里面引入另一个 JS 文件
        + 定义模块
          -> 调用 define 的方法
          1. 独立模块定义
            -> 每一个模块文件开始执行 define()
            -> 我不依赖其他文件, 我就是一个单纯的模块
            -> 向外暴露的内容, 直接 return 出去就好了
          2. 依赖其他模块的模块
            -> 我也是一个模块文件, 但是我依赖的以他模块的内容
            -> 使用 define() 定义
            -> 语法: define([ 依赖文件1, 依赖文件2, ... ], function (模块A, 模块B, ...) {})
          3. 导入 其他模块
            -> 我是一个模块整合文件
            -> 我就直接使用 a.js 文件里面的方法
            -> 使用这个方法 require()
            -> 语法: require([ 依赖文件1, 依赖文件2, ... ], function (模块1, 模块2) {})

      CMD - Common Module Defineion - 通用模块定义
        + 2011 左右, 社区里面出现的一个标准
        + 淘宝 "玉伯", 开发一了个 CMD 的模块化标准
        + 依赖于一个叫做 sea.js 的文件来实现的模块化标准
        + 使用: 文件需要引入一个 sea.js 的文件
          1. 独立模块定义
            -> define(function (require, exports, module) { })
            -> require() 用来导入其他文件的
            -> module.exports 是为了本文件导出内容的
            -> exports 是 module.exports 的别名
            -> var exports = module.exports
          2. 依赖其他模块的模块
            -> 你需要依赖其他文件模块
            -> 在 define( function (require, exports, module) {
              在你需要的位置使用 require() 方法来导入
              var modA = require('地址')
            })
          3. 资源整合
            -> 使用 seajs.use()
            -> 语法: seajs.use(['你要依赖的模块'], function (模块A) {})

      ES6 Module
        + 2015 年发布, ES6 语法里面自带了一个模块化标准
        + 各大浏览器厂商并不买账
        + 2016 年开始, Vue 出现了, 人家出现了一个脚手架(开发的大框架直接给你搭建好)
          => 搭建这个架子的时候, 内置了 ES6 模块化标准
        + 2018 年, 各大浏览器厂商开始原生支持 ES6 模块化标准
        + 2018 年中, Chrome 率先原生支持 ES6 模块化
        + 语法: 变成了 JS 的语法, 和关键字, 不需要任何第三方文件的引入
        + 特点: 页面必须在服务器上打开
          => live server 插件
          => 如果你想使用模块化语法, script 标签要加一个属性 type="module"
        + 使用:
          1. 每一个文件都可以作为独立模块, 页都可以作为整合文件
          2. 导出语法
            2-1. export default 导出的内容
            2-2. export var num = 200
          3. 导入语法
            3-1. 接收 export default 导出
              + import 变量 from '哪一个 JS 文件'
            3-2. 接收 export 导出的恩日哦那个
              + import { 接收变量 } from '哪一个 JS 文件'
        + 2020 年
          => ES2020 发布新的标准
          => 多了一个 按需加载的模块化
          => 语法: import(你要加载的文件).then(function (res) {})
    */

10.http 传输协议

<!--
    http 传输协议
      + 前后端交互的方式
      + 前端以什么样的形式发送数据给后端
      + 后端以什么样的形式返回数据给前端

    传输协议
      1. 必须经历四个步骤
        1-1. 建立连接
        1-2. 发送请求(前端给后端)
        1-3. 返回响应(后端给前端)
        1-4. 断开连接
      2. 只能由前端发起
        + 不能由后端主动沟通前端
      3. 一次只能说一个事情
        + 对于着一个事情你可以尽可能的描述的详细
        + 但是一次连接只能沟通一个事情
      4. 前后端交互只能交互字符串
        + 所有其他数据类型都不可以
        + 中文会转成 url 编码

    一个请求的四个步骤

    1. 建立连接
      + 基于 TCP / IP 协议的三次握手
      + 浏览器和服务器做的
      + 目的: 为了保证通道的连接
        1. 前端和后端说: "你在吗"
        2. 后端和前端说: "我再"
          -> 后端知道 前端正常发送
          -> 后端知道 后端正常接收
        3. 前端和后端说: "好的我知道了"
          -> 前端知道 后端正常接收
          -> 前端知道 前端正常发送
          -> 前端知道 前端正常接收
          -> 前端知道 后端正常发送
        4. 后端和前端说: "你发送请求吧"
          -> 后端知道 前端正常接收
          -> 后端知道 后端正常发送

    2. 发送请求
      + 前端发送请求给后端, 必须以 请求报文 的形式发送
      + 一个特殊格式的字符串文件(由浏览器进行组装)
      + 请求报文
        => 请求行
          -> GET / POST: 请求方式(未完待续)
          -> ./login.php: 请求地址
          -> HTTP/1.1: 传输协议版本
        => 请求头
          -> 对本次请求的描述信息
          -> Host: 请求主机
          -> Accapt: 期望的数据类型
          -> UserAgent: 请求终端
          -> Content-type: 请求体的数据格式
          -> ...
          -> Cookie: (未完待续)
        => 请求空行
          -> 分隔请求体和请求头的
        => 请求体
          -> 前端携带给后端的参数
          -> 有的有, 有的没有

    3. 接收响应
      + 每一个响应是由服务端接收到前端的请求以后, 给出的结果
      + 必须以响应报文的形式发送个前端
      + 响应报文
        1. 状态行
          => 200: 响应状态码(未完待续)
          => ok: 对响应状态码的简单描述
          => HTTP/1.1 传输协议版本
        2. 响应头
          => 对本次响应的描述信息
          => Date: 服务器时间(世界标准时间)
          => Server: 服务器信息
          => Content-Type: 响应体的数据格式
          => ...
        3. 响应体
          => 后端给前端的数据

    4. 断开连接
      + 基于 TCP / IP 协议的四次挥手
      + 为了保证断开连接
        1. 前端给后端发一个消息: "响应体收到, 我要准备断开连接了"
        2. 后端给前端发一个消息: "好的, 我知道你收到响应体了"
        3. 后端在其给前端发一个消息: "我已经准备断开连接了, 当我再次收到你的消息的时候, 我就断了, 不会再次回覆"
        4. 前端收到后端的第一个消息
        5. 前端收到后端的第二个消息: "好的, 我断开了, 别回了"


    留下三个内容
      1. 响应状态码
      2. 请求方式
      3. cookie
  -->

11.响应状态码

 <!--
    响应状态码
      + 以一个数字表示本次请求的响应状态
        => 成功: 创建成功, 删除成功, ...
        => 失败: 客户端失败, 服务端失败, ...
      + 是 100 ~ 599, 分成五类
        => 100 ~ 199: 表示连接继续
        => 200 ~ 299: 表示各种意义上的成功
        => 300 ~ 399: 表示重定向
        => 400 ~ 499: 表示客户端错误
        => 500 ~ 599: 表示服务端错误

    常见状态码
      + 101 表示连接继续
      + 200 通用成功
      + 302 临时重定向
        => 本次请求临时使用 服务器 来决定浏览器跳转的页面
      + 301 永久重定向
        => 终身只要访问这个地址, 就会给重新切换到新的地址
      + 304 缓存
        => 当你访问过一遍这个页面以后
        => 浏览器会自动缓存
        => 当你在其访问同一个地址的时候, 不会像服务器发送请求了, 而是从缓存里面获取
      + 403 访问权限不够
      + 404 访问地址不存在
      + 500 通用服务端错误
      + 501 维护或者过载
  -->

12.请求方式

 <!--
    请求方式
      + 前端和后端的交互手段
      + 最早: 不分 GET POST
        => 后来为了语义化, 做了一些区分
        => 本质是一样的

    常见的请求方式
      HTTP/1.0
        1. GET  : 偏向于获取的方式
          + 大部分都是给后端一些参数, 用来获取一些列数据
        2. POST : 偏向于给服务器一些数据
          + 大部分都是登录, 给服务器一些信息, 你给我一个简单的结果
        3. PUT  : 偏向于给服务器一些信息, 但是是添加使用
          + 大部分做注册, 给服务器一些信息, 你把这个信息存起来
        4. HEAD : 用来获取服务器头信息
      HTTP/1.1
        5. DELETE : 偏向于删除
          + 大部分是删除评论, 删除微博
        6. CONNECT: 管道连接改变代理连接使用
        7. PATCH  : 偏向于给服务器一些信息, 偏向于修改一些信息
          + 大部分用于完善用户资料
        8. OPTIONS: 用于获取服务器性能, 但是需要服务端同意
      二阶段: 只用 GET 和 POST


    GET 和 POST 请求方式的区别(重点!!!)
      + GET
        1. 语义是获取
        2. GET 携带参数的方式是 queryString, 在地址栏后面直接拼接, 不再请求体里面
        3. GET 理论上携带数据无限, 但是因为浏览器地址栏有限, IE 2KB
        4. GET 会被浏览器主动缓存
        5. GET 明文发送
        6. GET 只能发送 url 编码的数据(ASCII 码), 如果是中文会自动转码
      + POST
        1. 语义是给
        2. POST 携带载时是 requestBody, 在地址栏没有, 在请求体里面
        3. POST 理论上携带的数据无限, 但是会被服务器限制
        4. POST 请求不会被浏览器主动缓存, 除非手动设置
        5. POST 暗文发送
        6. POST 理论上可以发送任意格式的数据, 但是要和请求头里面得 content-type 配套
  -->

13.Cookie

<!--
    Cookie
      + 浏览器端的本地存储空间
      + 用来存储一些数据

    cookie 的特点(记下来!!!)
      1. 按照域名存储的
        + 哪一个域名存储的, 在当前域名下就可以访问
        + 换一个域名就不能访问
      2. 按照文件路径存储
        + 你在 a 文件夹下存储的数据
        + 只能在 a 文件夹及子文件夹访问
        + 在 a 文件夹的上级目录不能访问
      3. cookie 的存储时按照字符串的形式存储
        + 'key=value; key2=value2; key3=value3'
      4. 存储大小
        + 4KB 左右
        + 50条左右
      5. 时效性
        + 默认时会话级别的时效(关闭浏览器就没有了)
        + 我们可以手动设置 cookie 的时效(关闭浏览器以后依旧保存)
      6. 操作权限
        + 前端可以操作
        + 后端可以操作
      7. 请求自动携带
        + 只要 cookie 空间里面有数据
        + 那么你在发送任何一个请求的时候, 自动携带
  -->

14.session

/*
    session
      + 一个存在于 服务器 端的存储空间
      + 当他打开的那一瞬间, 就会生成一个 "密码"
      + 这个密码会自动存储到 cookie 里面
      + 等到返回前端的时候, 会自动把这个带回去
      + 只要你想向 session 空间里面存储内容或者获取内容
        => 必须要先开启, 后使用

    开启 session 空间
      + session_start();

    存储一些数据
      + PHP 有一个内置的 关联型数组就叫做 $_SESSION
  */

  // 1. 开启 session 空间
  /*
    当我在浏览器打开 localhost/01_session.php 文件的时候
    就会执行 session_start() 这段代码
    后端就会开启一个存储空间, 同时生成一段 密码
    同时把密码的一半放在 cookie 里面

    前端访问 localhost/01_session.php 本身就是一个请求
    此时后端是会给回一个响应
    响应回到前端了, 那么此时看到 cookie 空间里面就应该有一个 session_id 的存在
  */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EOPG

你的鼓励是我创造的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值