首页 🚓JavaScript

  1. windows的resize事件
 <script>
      // window(窗口)的resize :  re重新设置size尺寸 =>
      // => 当浏览器窗口大小发生变化时 => resize触发
      // resize : 浏览器窗口尺寸发生变化的时候,触发的事件
      window.addEventListener('resize', function () {
        console.log('window大小变化了')
        //  rem -> html的fontSize  @media

        // 获取html元素 .style.fontSize = ?
      })

      // 1. resize事件的事件->window
      // 2. resize事件触发->window窗口尺寸变化时,自动触发
      // 3. resize可以用来做什么呢? -> 响应式网站 -> html的fontSize设置

      // rem @media  vw/vh bootstrap(bs) 
      // 百分比布局   flex->移动端用的多
      // js-> 嗅探 -> pc or mobile
      // js-> resize -> 
      // js-> flexible.js 

      // 企业开发用哪个多?
      // flexible.js
      // rem
    </script>
  1. 事件冒泡
 <style>
    .father {
      width: 400px;
      height: 400px;
      background-color: pink;
      overflow: hidden;
      margin: 200px auto;
    }

    .son {
      width: 200px;
      height: 200px;
      background-color: green;
      margin: 100px auto;
      overflow: hidden;
    }
    .sun {
      width: 100px;
      height: 100px;
      background-color: blue;
      margin: 50px auto;
    }
  </style>
</head>
<body>
  <div class="father">
    <div class="son">
      <div class="sun"></div>
    </div>
  </div>
  <script>
    // 参数1:事件类型
    // 参数2:事件的处理函数
    // 参数3:useCapture: 是否捕获阶段触发 默认是false
    document.addEventListener('click', function () {
      console.log('document的点击事件触发了')
    }, true)
    document.body.addEventListener('click', function () {
      console.log('body的点击事件触发了')
    }, false)
    document.querySelector('.father').addEventListener('click', function () {
      console.log('father的点击事件触发了')
    }, true)
    document.querySelector('.son').addEventListener('click', function () {
      console.log('son的点击事件触发了')
    }, false)
    document.querySelector('.sun').addEventListener('click', function () {
      console.log('sun的点击事件触发了')
    }, true)
  </script>
  1. 表单的change和input事件
<input type="text" id="ipt" />
    <script>
      let ipt = document.querySelector('#ipt')
      // 表单元素的两个常用事件
      // change事件: 表单元素的value值变化了 && 失去焦点
        ipt.addEventListener('change',function(e){
            console.log('-----')
        })
      // input事件: 表单元素的value值变化了 => 边打字边触发 (不用失去焦点)
        ipt.addEventListener('input', function (e) {
          console.log('-----')
        })

      // Q1: change和input事件常用 -> input
      // Q2: change和input事件区别 ->
      // A2: 是否失去焦点
      // Q3: 什么东西的改变会触发change事件
      // A4: 表单元素的value值改变时并且失去焦点 就会触发
      // ps: type="text"/ checkbox / file / radio / .....!!!!
      //   下拉框 文件上传
    </script>
  1. 值类型和引用类型
 <script>
    // js的数据类型分类
    /* 
      简单数据类型:number string boolean undefined null symbol
      复杂数据类型: object array function

      从内存的角度来划分:
        简单数据类型也称为值类型,变量在存储简单数据类型的时候,存储的就是值本身。
        复杂数据类型也称为引用类型, 变量在存储复杂数据类型的时候,存储的不是对象本身,存储是对象的地址(引用)对象本身存储在堆内存中。
        
      程序运行需要占用一定的内容,定义的数据都是存储在内存中。
    */
    let num = 10

    let str = 'abc'

    let money = 100


    let user = {
      name: 'zs',
      age: 18
    }
  </script>
  1. 阻止事件传播
<style>
    .father {
      width: 400px;
      height: 400px;
      background-color: pink;
      overflow: hidden;
      margin: 200px auto;
    }

    .son {
      width: 200px;
      height: 200px;
      background-color: green;
      margin: 100px auto;
      overflow: hidden;
    }
    .sun {
      width: 100px;
      height: 100px;
      background-color: blue;
      margin: 50px auto;
    }
  </style>
</head>
<body>
  <div class="father">
    <div class="son">
      <div class="sun"></div>
    </div>
  </div>
  <script>
    // 参数1:事件类型
    // 参数2:事件的处理函数
    // 参数3:useCapture: 是否捕获阶段触发 默认是false
    document.addEventListener('click', function (e) {
      console.log('document的点击事件触发了')
      // stop: 停止
      // propagation: 传播
      // e.stopPropagation()
    }, true)
    document.body.addEventListener('click', function () {
      console.log('body的点击事件触发了')
    }, false)
    document.querySelector('.father').addEventListener('click', function () {
      console.log('father的点击事件触发了')
    }, true)
    document.querySelector('.son').addEventListener('click', function () {
      console.log('son的点击事件触发了')
    }, false)
    document.querySelector('.sun').addEventListener('click', function (e) {
      console.log('sun的点击事件触发了')
      // e.stopPropagation()
    }, true)
  </script>
  1. 登录框
 <style>
      body {
        height: 4000px;
      }
      .login-header {
        width: 100%;
        text-align: center;
        height: 30px;
        font-size: 24px;
        line-height: 30px;
      }

      * {
        padding: 0px;
        margin: 0px;
      }

      .login {
        width: 512px;
        position: absolute;
        border: #ebebeb solid 1px;
        height: 280px;
        left: 50%;
        right: 50%;
        background: #ffffff;
        box-shadow: 0px 0px 20px #ddd;
        z-index: 9999;
        margin-left: -250px;
        margin-top: 140px;
        display: none;
      }

      .login-title {
        width: 100%;
        margin: 10px 0px 0px 0px;
        text-align: center;
        line-height: 40px;
        height: 40px;
        font-size: 18px;
        position: relative;
        cursor: move;
        -moz-user-select: none; /*火狐*/
        -webkit-user-select: none; /*webkit浏览器*/
        -ms-user-select: none; /*IE10*/
        -khtml-user-select: none; /*早期浏览器*/
        user-select: none;
      }

      .login-input-content {
        margin-top: 20px;
      }

      .login-button {
        width: 50%;
        margin: 30px auto 0px auto;
        line-height: 40px;
        font-size: 14px;
        border: #ebebeb 1px solid;
        text-align: center;
      }

      .login-bg {
        width: 100%;
        height: 100%;
        position: fixed;
        top: 0px;
        left: 0px;
        background: #000000;
        filter: alpha(opacity=30);
        opacity: 0.3;
        display: none;
      }

      a {
        text-decoration: none;
        color: #000000;
      }

      .login-button a {
        display: block;
      }

      .login-input input.list-input {
        float: left;
        line-height: 35px;
        height: 35px;
        width: 350px;
        border: #ebebeb 1px solid;
        text-indent: 5px;
      }

      .login-input {
        overflow: hidden;
        margin: 0px 0px 20px 0px;
      }

      .login-input label {
        float: left;
        width: 90px;
        padding-right: 10px;
        text-align: right;
        line-height: 35px;
        height: 35px;
        font-size: 14px;
      }

      .login-title span {
        position: absolute;
        font-size: 12px;
        right: -20px;
        top: -30px;
        background: #ffffff;
        border: #ebebeb solid 1px;
        width: 40px;
        height: 40px;
        border-radius: 20px;
      }
    </style>
  </head>
  <body>
    <div class="login-header">
      <a id="link" href="#">点击,弹出登录框</a>
    </div>
    <div id="login" class="login">
      <div id="title" class="login-title">
        登录会员
        <span><a id="closeBtn" href="#" class="close-login">关闭</a
          ></span
        >
      </div>
      <div class="login-input-content">
        <div class="login-input">
          <label>用户名:</label>
          <input
            type="text"
            placeholder="请输入用户名"
            name="info[username]"
            id="username"
            class="list-input"
          />
        </div>
        <div class="login-input">
          <label>登录密码:</label>
          <input
            type="password"
            placeholder="请输入登录密码"
            name="info[password]"
            id="password"
            class="list-input"
          />
        </div>
      </div>
      <div id="loginBtn" class="login-button">
        <a href="#" id="login-button-submit">登录会员</a>
      </div>
    </div>

    <script>
      // 1. 点击链接,需要显示登录框
      // 2. 点击关闭按钮,需要关闭登录框
      // 3. 在登录框外边点击,需要关闭登录框
      // 4. 在登录框的头部进行拖拽,要有跟随效果
      // 5. 限制登录框的拖拽范围
      let link = document.querySelector('#link')
      let login = document.querySelector('#login')
      let closeBtn = document.querySelector('#closeBtn')
      let title = document.querySelector('#title')

      link.addEventListener('click', function (e) {
        login.style.display = 'block'
        // 点击了a链接,不要继续冒泡
        e.stopPropagation()
      })

      closeBtn.addEventListener('click', function() {
        login.style.display = 'none'
        
      })

      document.addEventListener('click', function () {
        login.style.display = 'none'
        console.log('隐藏')
      })

      // 给login注册点击事件
      login.addEventListener('click', function(e) {
        // 阻止事件传播
        e.stopPropagation()
      })

      title.addEventListener('mousedown', function (e) {
        let x = e.pageX - login.offsetLeft
        let y = e.pageY - login.offsetTop
        console.log(x, y)
        document.onmousemove = function (ev) {
          // 直接把margin
          let top = ev.pageY - y
          if (top < 0 ) {
            top = 0
          }
          login.style.margin = 0
          login.style.left = ev.pageX - x + 'px'
          login.style.top = top + 'px'
        }
      })

      title.addEventListener('mouseup', function (e) {
        console.log('鼠标谈起了')
        document.onmousemove = null
        e.stopPropagation()
      })
    </script>
  </body>
  1. 鼠标移入和移出
<style>
      #box {
        width: 200px;
        height: 200px;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
    <script>
      // 需求
      // 移入box->green
      // 移出box->yellow
      let box = document.querySelector('#box')
      // 移入 mouseenter
      box.onmouseenter = function (e) {
          box.style.backgroundColor = 'green'
      }
      // 移出 mouseout
      box.onmouseout = function (e) {
          box.style.backgroundColor = 'yellow'
      }

      
    </script>
  </body>
  1. 鼠标移入和移出2
 <style>
      #box {
        width: 200px;
        height: 200px;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
    <script>
      // 前提
      // 移入和移出 其实不只是下面的两个事件
      // 入 mouseenter
      // 入 mouseover

      // 出 mouseout
      // 出 mouseleave

      // 1. 入和出 上面的4个单词 怎么组合都可以 =>
      //  建议A: mouseover和mouseleave 一起用
      //  建议B: mouseenter和mouseout 一起用
      // 2. A和B有什么区别?
      // A: 不支持冒泡 -> 不是-> 从里到外 false
      // B: 支持冒泡 -> 从里到外 true
      // 3. 所有事件都有冒泡的现象?
      // 不是
      // 4. 场景
      // ul>li ->  移入li  触发ul  ->  B
      // ul>li ->  移入li  不触发ul  ->  A

      let box = document.querySelector('#box')
      box.onmouseover = function (e) {
        box.style.backgroundColor = 'green'
      }
      box.onmouseleave = function (e) {
        box.style.backgroundColor = 'yellow'
      }

      // Q1: 方案A => mouseover和mouseleave => 不支持冒泡
      // Q2: 方案B => mouseenter和mouseout => 支持冒泡
      // over->覆盖
      // leave->离开
      // enter->进入
      // out->出去
    </script>
  </body>
  1. 值类型和引入类型的画图
 <script>
    let money = 100

    let user = {
      name: 'zs',
      age: 18,
      dog: {
        name: '金毛'
      },
      sayHi: function () {
        console.log('大家好')
      }
    }
  </script>
  1. scroll事件
<style>
        div {
            width: 100px;
            height: 100px;
            padding: 10px;
            border: 10px solid #000;
            overflow: scroll;
        }
    </style>
</head>

<body>
    <div>
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        yguhjkfghjkfghjkfefewfewfyguhjkfghjkfghjkfefewfewf
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
        哈哈和氛围
    </div>

    <script>
        // 前提: 注册scroll事件, 需要有滚动条
        // scroll 事件
        let div = document.querySelector("div");
        div.onscroll = function(){
            // div内容的滚动的距离 
            // scrollTop 属性 没单位
            console.log(div.scrollTop)
        }

        // Q1. div.onscroll事件-> 触发该事件的条件
        // A1. div的内容滚动 && 滚动条
        // Q2. 获取内容滚动的距离
        // A2. 通过事件源.scrollTop属性 (没单位)

      

    </script>
</body>
  1. 定义变量的三种方式
<body>
  <script>
    // 在js中定义变量有3种方式
    // 早期只有一种: var
    // 2015年js发布了一套新的规范:ES6
    // 新增了两个定义变量的关键字: let 和 const


    // let和const
    // let定义变量
    // 1. let定义的变量不能重复的
    // 2. let定义的变量必须先定义变量,才能使用这个变量
    // 3. let定义的变量只有在当前{}中有效
    // console.log(num)
    // let num = 10
    // {
    //   let num = 10
    //   console.log(num)
    // }
    // console.log(num)

    // const也可以定义变量,但是const定义的通常称为常量 值不会发生改变的量
    // const和let一样的,但是const定义的变量值不允许改变。
    // const pi = 3.14
    // console.log(pi)

    const obj = {
      name: 'zs',
      age: 18
    }
    // obj.name = 'ls'
    // // 报不报错???
    // console.log(obj)
    obj = {}
    // 定义变量优先使用const,,,如果变量需要改变的情况,才考虑使用let
  </script>
</body>
  1. 值类型和引用类型的赋值特征
<body>
  <script>
    // 1. 值类型 :变量存储的是值本身,,把一个变量的值赋值给另一个变量的时候,直接把值赋值给另一个变量
    // let num1 = 10
    // let num2 = num1
    // num2 += 1
    // console.log(num1) // 10
    // console.log(num2) // 11


    let obj1 = {
      name: "zs",
      age: 18
    }
    let obj2 = obj1
    obj1.name = 'ls'
    console.log(obj1.name) // ls
    console.log(obj2.name) // ls


  </script>
</body>
  1. var定义变量
<body>
  <script>
    // 早期定义变量使用var
    // 1. var可以重复声明很多次变量
    // 2. var没有块级作用域
    // 3. var可以先使用,再声明
    
    /* 
      预解析:
        1. 找到所有var的声明,,,提升到最前面,,不会提升赋值
        2. 找到所有function的声明,提升到最前面,不会提升调用
        3. 如果函数同名,会覆盖,如果变量同名会忽略。
    */
    // var num
    // console.log(num)
    // var num = 10
    // var num = 20
    // var num = 30
    // console.log(num)
    function fn () {
      console.log('哈哈')
    }
    fn()

    

    

    // 预解析
    // 浏览器执行代码的时候,先预解析,然后才是一行一行执行
    
  </script>
</body>
  1. 面试题1
<script>
    // let a = 10
    // let x = a
    // a += 1
    // console.log(a) // 11 
    // console.log(x) // 10 


    // 11 21 10 20  3
    // 11 21 11 21
    // 
    // function fn(a, b) {
    //   a = a + 1;
    //   b = b + 1;
    //   console.log(a);
    //   console.log(b);
    // }

    // let x = 10;
    // let y = 20;
    // fn(x, y);
    // console.log(x);
    // console.log(y);

    let p = {
      name:"zs",
      age:18
    }
    let p2 = p
    p.name = 'ls'
    p2.age = 20
    console.log(p)  // {name: 'ls', age: 20}
    console.log(p2) // {name: 'ls', age: 20}
  </script>
  1. 存储技术-简单数据
<body>
    <script>
      // let arr = [10,20]
      // arr.push(30)
      // console.log(arr)
      // 持久化存储: 把数据永久的进行保存 -> 刷新网页, 数据还在

      // 对象.方法()
      // window.location
      // window.localStorage对象->属性和方法
      // localStorage
      // 1. 设置值 setItem()
      // console.log(window.localStorage)
      // let username = 'xiaomingba'
      // setItem('要保存的数据的名字,随便命名','要存的数据username')
      // setItem()无返回值
      // localStorage.setItem('username','xiaomingba')
      //  localStorage.setItem('uname',username)
      //  localStorage.setItem('pwd',123456)
      //  localStorage.setItem('sex','未知')

      // 测试数据的保存结果  =>  保存的位置 => Chrome->F12->Application选项卡->
      // 左侧目录Storage->找到当前运行的网页程序->看到保存的数据了

      // 2. 获取值
      // let v = localStorage.getItem('pwd')
      // console.log(v) // ?

      // 测试 -> 一旦set成功, 数据一直存在

      // 3. 移除保存的数据(代码方式)
      // localStorage.removeItem('username')
      // localStorage.removeItem('uname')
      // localStorage.removeItem('pwd')

      // 小结(代码问题)
      //   localStorage.setItem('key名', 'value值')
      //   let 获取的数据 = localStorage.getItem('key名')
      //   localStorage.removeItem('key名')
      //   只能保存字符串类型的数据!!!!!

      // 注意: (面试问题)
      // 1. 持久化存储=>window.localStorage对象
      // 2. localStorage特点: 
      // a. 关闭网页后, 数据依然存在
      // b. localStorage来源于HTML5特性=>兼容
      // c. localStorage保存的数据容量很大=>5M 1M=1024KB 



      // 保存
      window.localStorage.setItem('uname','zhangsan')
      // 获取
      let result = window.localStorage.getItem('uname')
      console.log(result)
      // F12->Application->查看结果

    </script>
  </body>
  1. 面试题2
<script>
    // let p = {
    //   name: "zs",
    //   age:18
    // }

    // let p2 = p

    // p = {
    //   name: 'ls'
    // }

    // p.name = 'ww'

    // console.log(p.name)
    // console.log(p2.name)
    // ww zs  5
    // ww ww  2
    // ww ls
    // ls ls

    // 4
    // ww zs  4
    // ww ls  2
    let p = {
      name: 'zs',
      age: 18
    }
    function fn (o) {
      // let o = p
      o.name = 'ls'
      o = {
        name: 'ww'
      }
      console.log(o.name)
    }
    fn (p)
    console.log(p.name)
    

  </script>
  1. 预解析的练习
<script>
    // // 找找这个班最帅的
    // function getCool() {
    //   console.log('康康是这个班最帅的男人')
    // }

    // getCool()

    // function getCool() {
    //   console.log('飞飞是这个班最帅的男人')
    // }
    // getCool()

    // function getCool() {
    //   console.log('cc是这个班最帅的男人')
    // }

    // getCool()

    // 1. 尽量不要重复声明函数
    // 2. 尽量把函数的声明放到最前面
    // function a() {
    //   console.log("aaaaa");
    // }

    // console.log(a); //
    // function a() {
    //   console.log("aaaaa");
    // }
    // var a = 1;
    // console.log(a); //
    // undefined 1  5
    // undefined a

    // 函数  1
    // 函数 函数
    // 1    1
    
    // function a() {
    //   console.log('哈哈')
    // }

    // console.log(a)
    // var a = 1
    // console.log(a)
    // function a() {
    //   console.log('哈哈')
    // }
    // a()
    // 函数  1 哈哈      6
    // 函数  1 undefined 3
    // 函数  1 报错
    // fn1();
    // function fn1() {
    //   console.log(num1);
    //   var num1 = 20;
    // }


    // 写代码尽量避免预解析
    // 1. 声明变量不用var,使用let const
    // 2. 先声明,在调用
    function a () {

    }

    var a = 1
  </script>
  1. 存储技术-复杂数据-对象
<script>
      // 需求:  存储一个对象数据 , 希望取出来的也是对象

      // 1.0 代码 -> 能保存 但是用不了
      //   localStorage.setItem('per',per) // [object Object]
      //   let per2 = localStorage.getItem('per')
      //   console.log(per2) // [object Object]

      // 2.0 代码 ->  JSON内置对象
      // stringify->  把对象->JSON字符串
      //   let str = JSON.stringify(per)
      //   console.log(str) // {"age":10,"size":18,"name":"zs"}
      //   localStorage.setItem('per',str)

      let per = {
        age: 10,
        size: 18,
        name: 'zs',
      }
      localStorage.setItem('per', JSON.stringify(per))
      // parse->  把JSON字符串->对象
      // let per2 = localStorage.getItem('per')
      // let per3 = JSON.parse(per2)
      let per2 = JSON.parse(localStorage.getItem('per'))
      // 测试
      console.log(per2.age)

      // localStorage的使用
      // 基本数据类型 -> string
      // 复杂类型([]  or  {})-> JSON.stringify()  和 JSON.parse()
    </script>
  1. 存储技术-复杂数据-数组
<script>
      // 测试 -> 如果存非字符串 ->  []  or {}
      // let arr = ['欧美','亚洲','日韩','自己的']
      // 结果 -> Application -> String
      // localStorage.setItem('list',arr)
      // 结果 -> getItem -> String
      // let listData = localStorage.getItem('list')
      // console.log(listData)  //"欧美,亚洲,日韩,自己的"

      // 问题?  ->  本来存的是数组  ->  返回字符串  -> 不能使用数组的方法

      // 解决上述问题
      // JSON
      // JSON.
      // Math.
      //

      // let names = ['小泽','小仓','abc']
      // 数组=>JSON字符串  :  保留了数组本来的样子的字符串 => ["小泽","小仓","abc"]
      // let result = JSON.stringify(names)
      // console.log(result); //string => ["小泽","小仓","abc"]
      //   JSON字符串=>数组
      //   console.log(JSON.parse(result)) // array => 能展开, 有length

      // 测试结果
      // 需求: 保存一个数组 ->   getItem()返回数组
      //   let arr1 = ['中国', '美', '韩']
      //   console.log(arr1)
      //   //   let temp = JSON.stringify(arr1)
      //   //   localStorage.setItem('country', temp)
      //   localStorage.setItem('country', JSON.stringify(arr1))

      //   let result = localStorage.getItem('country')
      //   let resultArr = JSON.parse(result)
      //   let arr2 = JSON.parse(localStorage.getItem('country'))
      //   console.log(arr2)

      // 小结1
      // 数组->JSON字符串
      //   let str = JSON.stringify(arr)
      // JSON字符串->数组
      //   let arr2 = JSON.parse(str)

      // 小结2
      // 把数组数据进行转化->JSON字符串->setItem()
      //   let scores = [59, 59, 49]
      let scores1 = [59, 59, 49]

      //   localStorage.setItem('scores', JSON.stringify(scores))
      // 取值-> 把ls保存的JSON字符串取出来->转数组
      //   let result = JSON.parse(localStorage.getItem('scores'))
      //   console.log(result)

      localStorage.setItem('scores1', JSON.stringify(scores1))
      let result = JSON.parse(localStorage.getItem('scores1'))
      console.log(result)

      // 1. 存储 :  localStorage.  setItem   getItem  removeItem
      // 2. 数据类型处理:  JSON.stringify()  JSON.parse()
      // 问题-----> 单词多 实参和返回值和作用 -> 4个方法在一起用 -> 混淆 -> 记不住!

      // localStorage
      // Q1: 作用 -> 数据持久化 -> 把数据永久的保存到浏览器
      // Q2: 特点 -> 大数据 / 关闭浏览器依然有 / 3个方法
      // Q3: set get remove  ->  Item
      // Q4: 保存的数据只能是字符串
      // Q5: 问题:  保存的是[] => 取出也是字符串
      // Q5: 解决: JSON.???
    </script>
  1. 对象的回顾
<script>
    // 对象是无序的键值对的集合
    // 对象会包含属性和方法

    // 如何去创建对象?

    // 1. 内置的构造函数Object创建对象
    // 名字 年龄 成绩 学习
    // let obj = new Object()
    // obj.name = '张三'
    // obj.age = 20
    // obj.score = 100
    // obj.study = function () {
    //   console.log('学习')
    // }

    // 2. 通过 字面量{}的方式创建
    // 字面量:直接量 字面意思就直接能够知道这个变量的类型和值
    // "abc" 'abc' 123 true []  {}
    // let obj = {
    //   name: '张三',
    //   age: 20,
    //   score: 100,
    //   study: function () {
    //     console.log('学习')
    //   }
    // }

    // 3. 自定义构造函数 Student
    let StudentObj = {
      study: function() {
        console.log('学习')
      },
      sing: function() {
        console.log('唱歌')
      }
    }
    function Student(name, age, score) {
      this.name = name
      this.age = age
      this.score = score
      this.study = StudentObj.study
      this.sing = StudentObj.sing
    }
    let stu = new Student('张三', 18, 100)
    let stu2 = new Student('李四', 20, 90)

    console.log(stu.study === stu2.study)
  </script>
  1. 作用域和作用域链
<script>
    // 作用域:变量起作用的区域
    // js中,只有两种作用域,,,全局作用域  函数作用域
    // 全局作用域: script内,函数外这部分就是全局作用域
    //   全局作用域中定义的变量叫做全局变量
    // 函数作用域:函数内部就是函数作用域
    //   函数作用域中定义的变量叫做局部变量  只要当前作用域中能够访问

    // let和const 块级作用域

    // var num = 10 // 全局变量

    // console.log(num)
    // function fn () {
    //   var num1 = 20 // 局部变量
    //   console.log(num)
    //   console.log(num1)
    // }
    // fn()
    // console.log(num1)

    {
      var num = 10  // 全局变量
      let money = 100  // 局部变量
    }

    console.log(num)
    console.log(money)
    

    /* 
      var定义变量:  函数内的是局部变量,函数外的是全局变量
      let和const定义变量:函数内的或者是代码块内都是局部变量,外面的都是全局变量。
    */
  </script>
  1. 发布微博持久化-简版
<style>
      * {
        margin: 0;
        padding: 0;
      }

      ul {
        list-style: none;
      }

      .box {
        width: 600px;
        margin: 100px auto;
        border: 1px solid #000;
        padding: 20px;
      }

      textarea {
        width: 450px;
        height: 160px;
        outline: none;
        resize: none;
      }

      ul {
        width: 450px;
        padding-left: 80px;
      }

      ul li {
        line-height: 25px;
        border-bottom: 1px dashed #cccccc;
      }

      input {
        float: right;
      }
    </style>
  </head>

  <body>
    <div class="box" id="weibo">
      <span>微博发布</span>
      <textarea name="" id="txt" cols="30" rows="10"></textarea>
      <button id="btn">发布</button>
      <ul id="ul"></ul>
    </div>

    <script>
      let txt = document.querySelector('#txt')
      let btn = document.querySelector('#btn')
      let ul = document.querySelector('#ul')
      // 1.0 检查本地是否有数据
      // 三元表达式
      //   let list = JSON.parse(localStorage.getItem('list'))
      //     ? JSON.parse(localStorage.getItem('list'))
      //     : []

      // 逻辑运算符
      let list = JSON.parse(localStorage.getItem('list')) || []

      // 双分支if else 
      // let result = JSON.parse(localStorage.getItem('list'))
      // if (result) {
      //     list = result
      // } else {
      //     list = []
      // }

      // 2.0 根据数据数组创建对应数量的li
      for (let index = 0; index < list.length; index++) {
        //   3.0 调用创建li的方法 传递数组里面的数据
        createLi(list[index])
      }

      // 3.0 创建li元素的方法 createLi
      function createLi(txtValue) {
        let li = document.createElement('li')
        let button = document.createElement('button')

        button.onclick = function () {
          ul.removeChild(this.parentNode)
        }
        li.innerText = txtValue
        button.style.float = 'right'
        button.innerText = 'del'
        li.appendChild(button)
        ul.insertBefore(li, ul.children[0])
      }

      // 4.0 添加按钮
      btn.onclick = function () {
        if (txt.value.trim().length === 0) {
          alert('error')
          return
        }
        createLi(txt.value)
        list.push(txt.value)
        localStorage.setItem('list', JSON.stringify(list))
        txt.value = ''
      }
    
    
    
    
    </script>
  </body>
  1. 原型的概念
<script>
    // 1. 任何一个构造函数,都默认会自带一个属性: prototype属性
    // 2. 这个prototype属性对应的值是一个对象
    // 3. 只要是通过构造函数new出来的对象可以直接访问这个原型对象上的任意的属性。
    // function Person() {}
    // console.log(Person.prototype)

    function Person (name) {
      this.name = name
    }

    Person.prototype.aa = 'bb'
    Person.prototype.money = 100
    console.log(Person.prototype)

    let p1 = new Person('张三')

    console.log(p1.name)
    console.log(p1.aa)
    console.log(p1.money)

    let p2 = new Person('李四')
    console.log(p2.aa)
    console.log(p2.money)
  </script>
  1. 作用域链的说明
<script>
    // 函数能够形成函数作用域  函数内部可以有函数,内部的函数也会形成作用域,多个作用域的嵌套就形成了作用域链。
    // 变量的搜索原则
    // 1. 当前作用域中寻找该变量
    // 2. 如果找不到,会去外层作用域查找该变量
    // 3. 如果找不到,一直会找到全局作用域,如果找到,就使用, 如果找不到就报错,因为没有定义这个变量

    // let num = 10
    function fn() {
      // let num = 20
      function fn1 () {
        // let num = 30
        console.log(num)
      }
      fn1()
    }
    fn()


  </script>
  1. 构造函数-原型-实例三者关系
<script>
    /* 
      构造函数: Person
      实例:p p2   Person的实例    通过构造函数new出来的对象
      原型对象:   Person.prototype

      一家三口
        爸爸
        妈妈
        孩子
    */
    function Person(name) {
      this.name = name
    }

    let p = new Person('张三')
    let p2 = new Person('李四')

  </script>
  1. 作用域链的面试题
 <script>
    // var num = 10; //全局
    // function fn1() {
    //   console.log(num); // 局部变量  
    //   var num = 20;
    //   console.log(num);  
    // }
    // fn1();
    // console.log(num);    
    // undefined 20 10      5
    // 10 20 10             5


    // 2 -- 改造上面的面试题
    // var num = 10; //全局变量
    // fn1();
    // function fn1() {
    //   console.log(num); // 10
    //   num = 20; // 把全局变量num改成了20
    //   console.log(num); // 20
    // }
    // console.log(num); // 20
    // 10 20 20  6
    // 20 20 10
    // 10 20 10  2

    // var num = 10
    // function fn() {
    //   num++
    // }
    // fn()
    // console.log(num)

    // var num = 123
    // function f1(num) {
    //     console.log(num)
    // }

    // function f2() {
    //     var num = 456
    //     f1(num)
    // }
    // f2()

    // var num1 = 10; // 全局
    // var num2 = 20; // 全局  200
    // function fn(num1) {
    //   num1 = 100; // 局部
    //   num2 = 200; 
    //   num3 = 300; // 局部 
    //   console.log(num1);
    //   console.log(num2);
    //   console.log(num3);
    //   var num3;
    // }
    // fn();
    // console.log(num1);
    // console.log(num2);
    // console.log(num3);


    // 100 200 300  100 200 报错  4
    // 100 200 300 10 200 报错   5
    // 10 200 300  100 200 报错

    // var color = 'red'
    // function outer() {
    //   var anotherColor = 'blue'

    //   function inner() {
    //     var tmpColor = color
    //     color = anotherColor
    //     anotherColor = tmpColor
    //     console.log(anotherColor)
    //   }

    //   inner()
    // }
    // outer()
    // console.log(color)

    // red red   3
    // blue blue 4
    // red blue  3


    let n1 = 10
    let n2 = 20
    let n3 = 30

    function fn() {
      let n2 = 30
      n1 = 100
      n2 = 200
      n3 = 300
      console.log(n1)
      console.log(n2)
      console.log(n3)
    }
    function fn2 (n3) {
      let n1 = 50
      n1 = 1000
      n2 = 2000
      n3 = 3000
      console.log(n1)
      console.log(n2)
      console.log(n3)
    }
    // 1.
    // fn()
    // fn2()

    // 2
    // fn2()
    // fn()

    console.log(n1)
    console.log(n2)
    console.log(n3)

  </script>
  1. 函数的四种调用模式
   }
    // }
    // // 方法调用模式
    // // obj.sayHi()

    // let fn = obj.sayHi
    // fn()

    // var age = 38;
    // var obj = {
    //   age: 18,
    //   getAge: function () {
    //     console.log(this.age);
    //   }
    // }
    // obj.getAge() // 方法调用模式
    // var f = obj.getAge
    // f()

    // 18 38 4

    // var age = 38;
    // var obj = {
    //   age:18,
    //   getAge:function () {
    //     console.log(this.age);
    //     function foo(){
    //       console.log(this.age);
    //     }
    //     foo(); // 函数调用
    //   }
    // }
    // // obj.getAge();
    // obj['getAge']()

    // 18 18 
    // 18 38 4


    // var length = 10
    // function fn() {
    //   console.log(this.length)
    // }
    // var arr = [fn, '222']
    // fn() // 函数模式  10
    // // 属于方法调用
    // // 对象名.方法名()
    // // 对象名['方法名']()
    // arr[0]()
    // 10 2

    // var length = 10
    // function fn () {
    //   console.log(this.length)
    // }
    // var obj = {
    //   length: 20,
    //   say: fn
    // }

    // var arr = [fn, 1, 2, 3]


    // fn() // 10
    // obj.say() // 20
    // arr[0]() // 4

    var length = 10
    function fn() {
      console.log(this.length)
    }
    var obj = {
      length: 5,
      method: function (fn) {
        console.log(this.length)
        fn() // 10
        arguments[0]();
      }
    }
    obj.method(fn, 10, 5);

    // 10 3           10
    // 10 5
  </script>
  1. 原型解决构造函数内存浪费问题
<body>
  <!-- 
    创建多个学生对象
      名字 年龄 成绩
      学习 打架
   -->
  <script>
    function Student(name, age, score) {
      this.name = name
      this.age = age
      this.score = score
    }

    // 原型对象的作用:用于给实例提供共享的属性和方法
    // 原型对象
    Student.prototype.study = function () {
      console.log('能够学习')
    }

    Student.prototype.fight = function () {
      console.log('会打架')
    }

    Student.prototype.money = 10000
    let s1 = new Student('张三', 18, 100)
    let s2 = new Student('李四', 23, 80)

    console.log(s1.name)
    s1.study()
    console.log(s1.money)

    console.log(s1.study === s2.study)

  </script>
</body>
  1. _proto属性
<script>
    function Person(name, age) {
      this.name = name
      this.age = age
    }

    Person.prototype.money = 100

    let p = new Person('张三', 18)

    // 访问原型对象
    // 任何的实例,都自带一个属性,__proto__  通过这个属性能够找到原型对象
    // console.log(Person.prototype)
    // console.log(p.__proto__)
    // console.log(Person.prototype === p.__proto__)
    Person.prototype.money = 200
    console.log(p.money)
  </script>
  1. arguments的使用
<script>
    // function fn(a, b) {
    //   // 所有的函数内部自带一个属性 arguments
    //   // arguments代表所有的实参
    //   console.log(arguments)
    //   console.log(a + b)
    // }

    // fn(1, 2, 3, 5, 6)

    // 需求:实现一个max方法
    function max() {
      let max = arguments[0]
      for (let i = 1; i < arguments.length; i++) {
        if (arguments[i] > max) {
          max = arguments[i]
        }
      }
      return max
    }

    console.log(max(1, 22, 3, 4))
  </script>
  1. constructor属性
<body>
  <script>
    function Person() {

    }
    // 原型对象
    console.log(Person.prototype)

    console.log(Person.prototype.constructor === Person)
  </script>
</body>
  1. 构造函数调用模式
<script>
    // function fn() {

    // }

    // 构造函数调用模式  new 函数()   this会指向新对象
    // let f = new fn()

    var name = 'zs'
    var age = 18
    function Person(name, age) {
      this.name = name
      this.age = age
      console.log(this.name)
      console.log(this.age)
    }

    // 函数调用模式 window
    var p = Person('ls', 20)

    console.log(name)
    console.log(age)

    // zs 18 zs 18 4
    // zs 18
    // ls 20 ls 20 6


    /* 
      函数调用模式  函数名()   this指向window
      方法调用模式  对象名.方法名() 数组名[下标]()  this指向当前数组或者当前对象
      构造函数调用模式  new 函数名()  this指向新创建的对象

      上下文调用模式  call apply bind
    */

    /* setTimeout(function(){}, 1000) setInterval() */
    // setInterval(function () {
    //   console.log(this)
    // }, 1000)

    // button.onclick = function () {
    //   this
    // }
  </script>
  1. 测试题01
<script>
    // function Person () {
    // }
    // let p = new Person()

    // console.log(p.constructor === Person.prototype.constructor)
    // console.log(p.constructor === Person)
    // console.log(Person.prototype.constructor === Person)
    // true true 4
    // false true 2
    // false false

    // console.log(p)




    // ============================================
    function Person () {}
    let p1 = new Person()
    let p2 = new Person()
    console.log(p1.constructor === p2.constructor)
    console.log(p1.constructor === Person.prototype.constructor)
    console.log(p2.constructor === Person)
  </script>
  1. 上下文调用模式-call
 <script>
    // 4. 方法借调模式 上下文模式
    // 自己指定this的指向  call apply bind
    // 任何函数都可以直接调用 call apply bind
    // function fn (a, b) {
    //   console.log(this)
    //   console.log(a, b, a+b)
    //   console.log('哈哈')
    // }

    // // 调用函数
    // // fn(1, 2)
    // // fn.call()

    // // 参数要比正常调用多一个
    // // 参数1:用于指定this指向的
    // // 后续参数:和正常调用一样的参数列表
    // let arr = [100]
    // fn.call(arr, 1, 2)

    // call的作用:
    // let ff = {
    //   name: '大飞哥',
    //   money: 100000,
    //   liao: function () {
    //     console.log(`你好,我是${this.name},我有${this.money}块钱`)
    //   }
    // }
    // ff.liao()
    
    // let cc = {
    //   name: '大葱哥',
    //   money: 100
    // }

    // ff.liao.call(cc)


    let ff = {
      name: '大飞哥',
      liao: function (name) {
        console.log(`${name},你好,我是${this.name},抓住你了,嘿嘿嘿~~~~`)
      }
    }
    ff.liao('刘金虎')

    // 班长  朱兴杨  撩 汪 旭
    let bz = {
      name: '朱兴杨'
    }

    ff.liao.call(bz, '汪旭')
  </script>
  1. 上下文调用模式-apply
 <script>
    // apply和call一样,都可以指定this指向
    // 但是二者的参数不一样
    // call需要的参数列表和正常调用一样,多增加一个this指向
    // apply需要把所有的参数放到一个数组中,也需要指定this的指向

    // function fn(a, b, c) {
    //   console.log(a, b, c)
    //   console.log(this)
    // }

    // let arr = []

    // fn.call(arr, 10, 20, 30)
    // // 参数1:指定this
    // // 参数2:数组 把所有的参数都放到一个数组中
    // fn.apply(arr, [10, 20, 30])

    // 需求:
    // 求一个数组中的最大值
    let arr = [1, 3, 5, 22, 4]
    // Math.max(1, 3, 2, 32, 2)

    // let max = Math.max.apply(arr, arr)
    // console.log(max)

    console.log(Math.min.apply(arr, arr))
  </script>
  1. 原型链
<body>
  <button>按钮</button>
  <script>
    // let button = document.querySelector('button')
    // button.addEventListener('click', function() {
    //   console.log('哈哈哈')
    // })

    // // button.addEventListener  说明一定能够找到addEventListener
    // console.dir(button)


    // 一个实例都会有原型对象(__proto__,,构造函数.prototype),原型对象本身也是个对象,原型对象也会有原型对象,一环扣一扣,形成了原型链。
  </script>
</body>
  1. 伪数组和数组
<script>
    // 伪数组:和数组长得一样,,,,能够跟数组一样有下标和长度,而且能够进行遍历,这个就叫伪数组,实质上伪数组就是一个普通的对象
    // let obj = {
    //   0: '张三',
    //   1: '李四',
    //   2: '王五',
    //   length: 3
    // }
    // console.log(obj[2])
    // for (let i = 0; i < obj.length; i++) {
    //   console.log(obj[i])
    // }

    // Array.prototype

    // 伪数组借用数组的方法
    // Array.prototype.push.call(obj, '赵六')
    // let result = Array.prototype.pop.call(obj)
    // console.log(result)
    // console.log(obj)

    // 把伪数组转成数组 slice
    // obj = Array.prototype.slice.call(obj)
    // console.log(obj)

    
    // 练习
    // 封装一个函数,接收N个参数,,,要能够打印这些所有的参数,并且使用-拼接来
    // function log() {
    //   // 1. arguments
    //   // 2. -  join
    //   let result = Array.prototype.join.call(arguments, '-')
    //   console.log(result)
    // }

    // log('张三', '李四') // 张三-李四

    // log(1, 2, 3, 4) // 1-2-3-4

    // js提供一个方法
    // 数组 = Array.from(伪数组|数组)
    function log() {
      let result = Array.from(arguments).join('-')
      console.log(result)
    }

    log(1,2,3)
  </script>
  1. 注意-实例和原型的关系
<script>
    // 实例可以直接访问原型对象上的属性和方法,但是不能访问构造函数上的属性和方法。
    function Person() {

    }
    Person.money = 100
    Person.prototype.num = 200

    let p = new Person()

    console.log(p.num)
    console.log(p.money)
  </script>
  1. 上下文调用模式-bind
 <script>
    // bind也能够修改函数内部的this指向
    // bind不会调用这个函数,,bind会生成一个新的函数,而且这个新函数内部的this是绑死的
    // function fn () {
    //   console.log(this)
    //   console.log('哈哈哈')
    // }
    // let arr = []
    // let fn1 = fn.bind(arr)
    // fn1()
    // bind经常用来修改某个函数内部的this指向


    // es6 箭头函数 
    let user = {
      name: '飞飞',
      sayHi: function () {
        setInterval(
          function () {
            console.log(`大家好,我是${this.name}`)
          }.bind(this)
        , 1000)
      }
    }

    user.sayHi()
  </script>
  1. 小结
<script>
    // 值类型和引用类型
    // 值类型:简单数据类型,变量在存储简单数据类型的时候,存储的就是值本身,所以简单类型也叫值类型
    // 引用类型:复杂数据类型,变量在储存复杂数据类型的时候,存储的仅仅是地址,复杂类型实质上存储在堆内存中。

    // 赋值特征
    // 如果变量存储的是值类型,赋值给另一个变量, 直接就是把值赋值给另一个变量
    // 如果变量存储的是复杂数据类型,赋值给另一个变量,仅仅把地址赋值给另一个变量,此时对象只有一个

    // 构造函数创建对象的缺点
    // 如果每个实例都有方法,浪费内存空间
    // 原型对象:任何一个构造函数都会有一个prototype属性,这个构造函数的prototype属性会指向一个对象,这个对象称为原型对象
    // 原型对象:所有的属性和方法都会被实例所继承,实例可以直接访问原型对象上的所有的属性和方法

    // 实例.__proto__ 也指向原型对象,等价于 构造函数.prototype, 
    // 原型对象有一个属性 constructor,指向了构造函数。
    // 能够画出一个实例的 关系图
    // 构造函数(妈妈) --- 原型对象(爸爸) -----实例(孩子)
  </script>
  1. 四种调用模式
<script>
    /* 
      1. 函数调用模式  函数名()   this指向window
      2. 方法调用模式  对象名.方法名()  this指向当前对象
      3. 构造函数调用模式 new 构造函数()  this指向新创建的对象
      4. 上下文调用模式 随意指定函数的this
        call  fn.call(指定this, 参数1, 参数2, 参数3)
        apply fn.apply(指定this, [参数1, 参数2, 参数3])
        bind: let fn1 = fn.bind(指定this)  得到一个新函数,而且新函数的this绑死了
    */
  </script>
  1. 原型链
<script>
    // 一个对象一定会有原型对象(一个人一定会有爸爸),原型对象本身也是一个对象,原型对象还会有原型对象,一环扣一环,形成了原型链。

    // function Person() {

    // }

    // // p ====> Person.prototype
    // // 查找p元素的原型链
    // let p = new Person()

    // // 所有对象的原型链的尽头: Object.prototype ===> null
    // console.log(p.toString())

    // 随便给一个对象,都要能够分析出原型链

    // arr ==> Array.prototype ====> Object.prototype
    // d   ==> Date.prototype =====> Object.prototype
    // let d = new Date()
    // let arr = [1,2,3]  // let arr = new Array()
    // console.log(arr.toString())


    // Math对象的原型链
    // Math ===> Object.prototype ===> null
    // console.log(Math)

    // div ----> HTMLDivElement.prototype  ---> HTMLElement.prototype ---> Element.prototype ===> Node.prototype ===> EventTarget.prototype  ===> Object.prototype ===> null 
    let div = document.querySelector('div')
    console.dir(div)
  </script>
  1. 递归函数
<script>
    // 递归函数:一个函数内部调用函数本身,这个函数就叫递归
    // 注意:递归函数一定要注意结束的条件,如果没有结束条件,就是死递归

    let count = 0
    function tellStory() {
      count++
      console.log('从前有座山')
      console.log('山里有座庙')
      console.log('庙里有个老和尚')
      console.log('老和尚给小和尚讲故事')

      if (count < 5) {
        tellStory()
      }
    }

    tellStory()
    
  </script>
  1. 属性查找原则
<script>
    // 获取对象的某个属性或者方法的时候
    let obj = {
      name: 'zs',
      age: 18
    }

    console.log(obj.name)
    console.log(obj.age)
    console.log(obj.aa)
    console.log(obj.toString)
  </script>
  1. 递归函数的作用
 <script>
    // 递归函数: 化归思想
    // 把一个复杂的问题简单化 把一个未知的问题转化为已知的问题。
    // 求1-60之间所有的数的  求 getSum(60) = getSum(59) + 60
    //                        getSum(59) = getSum(58) + 59
    //                        getSum(1) = 1
    // function getSum(n) {
    //   if (n === 1) {
    //     return 1
    //   }
    //   return getSum(n-1) + n
    // }

    // console.log(getSum(100))


    // 斐波那契数列  兔子数列
    // 某个月的兔子数 = 前两个月的兔子数
    // 1 2 3 4 5 6  7   8   9   10  11  12
    // 1 1 2 3 5 8  13  21  34  55  89  144
    //  第n个月的兔子数   12月

    function getTu(n) {
      // 第1个月和第2个月直接1对
      if (n === 1 || n=== 2) {
        return 1
      }
      return getTu(n-1) + getTu(n-2)
    }

    console.log(getTu(24))
  </script>
  1. 原型链面试题
<script>
    // function Person(name) {
    //   this.name = name;
    // }

    // Person.prototype.name = "ls";
    // Person.prototype.money = 100;

    // var p = new Person("zs");

    // console.log(p.name); // zs
    // console.log(p.money); // 100

    // let obj = {
    //   name: null,
    //   age: 18
    // }
    // console.log(obj.name)

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

    // Person.prototype.name = "ls";
    // Person.prototype.money = 100;

    // // {name: 'zs', money: undefined}
    // let p = new Person('zs');
    // console.log(p)

    // console.log(p.name);
    // console.log(p.money);

    // zs 100
    // zs undefined 3


    function Person(name, money) {
      if (name) {
        this.name = name
      }
      if (money) {
        this.money = money
      }
    }

    Person.prototype.name = "ls";
    Person.prototype.money = 100;

    let p = new Person();
    console.log(p)

    console.log(p.name);
    console.log(p.money);
  </script>
  1. 深拷贝和浅拷贝
 <script>
    // 对象的拷贝(克隆)的概念
    let obj = {
      name: 'zs',
      age: 18
    }
    // 拷贝obj对象 得到一个新对象  这个新对象和obj对象一模一样,,两个对象相互独立的。
    function copy(obj) {
      let temp = {}
      for (let key in obj) {
        temp[key] = obj[key]
      }
      return temp
    }

    let obj1 = copy(obj)
    obj.name = 'ls'
    console.log(obj1)
    console.log(obj)


  </script>
  1. 属性设置原则
 <script>
    // function Person() {
    // }

    // Person.prototype.money = 300
    // let p = new Person()

    // p.money = 200

    // console.log(p.money)
    // console.log(Person.prototype.money)
    function Person() {

    }

    let p = new Person();
    Person.prototype.money = 200;

    console.log(p.money); // 200

    p.money = 300;

    console.log(p.money); // 300

    console.log(Person.prototype.money); // 200
  </script>
  1. 对象的基本语法
 <script>
    // 操作对象有两种 点语法 []语法
    // let obj = {
    //   name: 'zs',
    //   age: 18
    // }
    // .语法更加简洁  []与更加灵活
    // console.log(obj.name)
    // console.log(obj['name'])

    // let name = 'age'
    
    // console.log(name)

    // obj.xxx 和变量没有任何的关系,它会直接去对象obj中找xxx属性
    // console.log(obj.name) // obj的name属性
    // let key = 'name'
    // console.log(obj.key) // obj中找key属性 undefined

    
    // let obj = {
    //   name: 'zs',
    //   age: 18
    // }
    // // console.log(obj.name)
    // let key = 'name'
    // // console.log(obj['na' + 'me'])
    // console.log(obj[key])


    // let obj = {
    //   name: 'zs',
    //   age: 18
    // }

    // let name = 'age'

    // console.log(obj.name) // zs
    // console.log(obj['name']) // zs
    // console.log(obj[name]) // 18

    let obj = {
      name: 'zs',
      age: 18
    }

    for (let key in obj) {
      // key是遍历的键
      // console.log(key)
      // console.log(obj.key) 
      // console.log(obj['key'])
      console.log(obj[key])
    }
  </script>
  1. 阻止a链接的跳转
<body>
  <!-- http https -->
  <!-- 伪协议: javascript:表示a链接别跳转了,变成执行js代码 -->
  <a href="http://www.baidu.com">百度一下</a>
  <script>
    let link = document.querySelector('a')
    // link.onclick = function () {
    //   console.log('哈哈哈')
    //   return false
    //   // e.preventDefault()
    // }

    link.addEventListener('click', function(e) {
      console.log('哈哈')
      e.preventDefault()
    })
  </script>
</body>

querySelectorAll与children的区别

<body>
  <ul>
    <li>001</li>
    <li>002</li>
    <li>003</li>
    <li>004</li>
    <li>005</li>
    <li>006</li>
    <li>007</li>
    <li>008</li>
    <li>009</li>
    <li>010</li>
  </ul>

  <script>
    let ul = document.querySelector('ul')

    let lis = ul.children
    let lis2 = ul.querySelectorAll('li')

    console.log(lis)
    console.log(lis2)

    document.querySelector('li:last-child').onclick = function () {
      this.remove()
      // this.parentNode.removeChild(this)
    }
  </script>
</body>
  1. 对象拷贝
 <script>
    let obj = {
      name: 'zs',
      age: 18,
      gender: '男',
      car: {
        brand: '玛莎拉蒂',
        price: 100
      }
    }
    // 对象浅拷贝:只会拷贝对象的一层属性,但是如果属性中还有对象,这个对象就没有拷贝
    // 对象深拷贝:不管这个对象有多少层属性,都要完全独立
    function clone (obj) {
      let temp = {}
      for (let k in obj) {
        // 判断这个属性的值是否是对象,如果是对象不能直接拷贝地址,需要拷贝整个对象
        if (typeof obj[k] === 'object') {
          // 是对象
          temp[k] = clone(obj[k])
        } else {
          temp[k] = obj[k]
        }
      }
      return temp
    }

    let result = clone(obj)
    console.log(obj)
    console.log(result)
  </script>

window-onload

<style>
    .father {
      position: relative;
      width: 400px;
      height: 400px;
      background-color: pink;
      margin: 100px;
    }

    .son {
      position: absolute;
      left: 100px;
      top: 100px;
      width: 100px;
      height: 100px;
      background-color: green;
    }
  </style>
</head>
<body>

  <!-- <button>按钮</button>
  <div>123</div>
  <img src="2.gif" alt=""> -->

  <div class="father">
    <div class="son"></div>
  </div>
  <script>
    console.log(document.querySelector('.son').offsetLeft)
    // window.onload = function () {
    //   // 执行这段代码,打印图片的宽度和高度
    //   let img = document.querySelector('img')
    //   console.log(img.offsetWidth)
    //   console.log(img.offsetHeight)
    //   console.log(456)
    // }

    // console.log(123)

    // var a = 11
    // console.log(window.a)

    // let b = 12
    // console.log(window.b)
  </script>
</body>
  1. 对象的深拷贝
 <script>
    let obj = {
      name: 'zs',
      age: 18,
      gender: '男',
      dog: {
        name: '金毛'
      }
    }

    function clone(obj) {
      let newObj = {}
      for (let k in obj) {
        // newObj['dog'] = obj['dog']
        // 判断obj[k]类型是否是对象,如果是对象,继续克隆
        newObj[k] = typeof obj[k] === 'object' ? clone(obj[k]) : obj[k]
      }
      return newObj
    }

    let newObj = clone(obj)

    console.log(obj)
    console.log(newObj)
  </script>
  1. 拖拽效果
 <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    div {
      position: absolute;
      width: 200px;
      height: 200px;
      background-color: teal;
      cursor: move;
    }
  </style>
</head>
<body>
  <div></div>
  <script>
    let div = document.querySelector('div')

    div.onmousedown = function (e) {
      console.log('按下了')
      // 1. 记录按下的位置
      let x = e.pageX - div.offsetLeft
      let y = e.pageY - div.offsetTop
      
      // 2. 注册鼠标移动事件
      document.onmousemove = function (e) {
        let left = e.pageX - x;
        let top = e.pageY - y;
        console.log(left, top)
        if (left < 0) {
          left = 0
        }
        if (top < 0) {
          top = 0
        }
        if (left > window.innerWidth - div.offsetWidth) {
          left = window.innerWidth - div.offsetWidth
        }
        if (top > window.innerHeight - div.offsetHeight) {
          top = window.innerHeight - div.offsetHeight
        }
        div.style.left = left + 'px'
        div.style.top = top + 'px'
      }
    }

    div.onmouseup = function () {
      console.log('弹起了')
      document.onmousemove = null
    }
  </script>
</body>
  1. 需求-树形菜单数据的处理
<body>
  <script>
    /* 
      部门

      传智播客
        上海校区
          前端学科
          java学科
          UI学科
        深圳校区
        北京校区
        广州校区
    */
    const list = [
      {id: '1', pid: '', name: '总裁办'},
      {id: '2', pid: '', name: '行政部'},
      {id: '3', pid: '', name: '人事部'},
      {id: '4', pid: '', name: '财务部'},
      {id: '5', pid: '4', name: '出纳'},
      {id: '6', pid: '4', name: '审计'},
      {id: '7', pid: '2', name: '学工'},
      {id: '8', pid: '1', name: '教研部'},
      {id: '9', pid: '8', name: 'java'},
      {id: '10', pid: '8', name: '前端'},
      {id: '11', pid: '8', name: 'python'}
    ]
    
    // [
    //   {
    //     id: '1', pid: '', name: '总裁办',
    //     children: [
    //       {
    //         id: '8', pid: '1', name: '教研部',
    //         children: [
    //           {id: '9', pid: '8', name: 'java'},
    //           {id: '10', pid: '8', name: '前端'},
    //           {id: '11', pid: '8', name: 'python'}
    //         ]
    //       },
    //     ]
    //   },
    //   {
    //     id: '2', pid: '', name: '行政部',
    //     children: [
    //       {id: '7', pid: '2', name: '学工'},
    //     ]
    //   },
    //   {id: '3', pid: '', name: '人事部'},
    //   {
    //     id: '4', 
    //     pid: '', 
    //     name: '财务部',
    //     children: [
    //       {id: '5', pid: '4', name: '出纳'},
    //       {id: '6', pid: '4', name: '审计'},
    //     ]
    //   }
    // ]


    // // 从数组中找到pid为xxx的所有的元素
    // function listToTree (list, pid) {
    //   const arr = []
    //   list.forEach(item => {
    //     if (item.pid === pid) {
    //       arr.push(item)
    //       const children = listToTree(list, item.id)
    //       if (children.length > 0) {
    //         item.children = children
    //       }
    //     }
    //   })
    //   return arr
    // }
    // const result = listToTree(list, '')
    // console.log(result)

  </script>
</body>


文章评论

目录