JavaScript 数组 对象 方法 ## **3.拼接arr.join(‘分隔符‘)**

内置对象:数组对象方法

1.连接数组arr.concat(数组)

//声明数组
        let arr = [10,20,30]
        //(1) arr.concat(数组)   : 把两个数组连接成一个数组
        //应用场景: 一般用于长列表(下一页),不断往后面拼接数组
        let newArr = arr.concat([40,50])
        console.log(newArr)//[10,20,30,40,50]

2.翻转数组arr.reverse()

 let arr = [10,20,30]
  //(2) arr.reverse()   : 翻转数组
        //应用场景: 价格从低到高 切换成 从高到低, 只需要翻转数组即可
        arr.reverse()
        console.log( arr )//[30,20,10]

3.拼接arr.join(‘分隔符’)

        //(3) arr.join('分隔符') : 把数组每一个元素拼接成字符串
        let arr1 = [80,90,55,60]
        //应用场景 :  有些歌曲是多个人合唱,服务器会给我们一个数组。 这个时候就需要将数组元素通过join拼接起来然后再页面显示
        let str = arr1.join('&')
        console.log( str )//80&90&55&60

4.排序arr.sort(function(a,b){return a-b // return a-b //从小到大 //return b-a //从大到小})

//(4) arr.sort( function(a,b){return a-b} ) : 排序
         let arr = [10,30,2]
        arr.sort( function(a,b){
    
    
            // return a-b //从小到大
            return b-a //从大到小
        } )
        console.log(arr)//[30,10,2]

字符串对象

** 1. 字符串类似于数组,也有长度和下标**

let  str='我要去曦度看武'
//1. 字符串类似于数组,也有长度和下标
        console.log( str.length )//7
        console.log( str[5] )//看

2. str.indexOf(‘字符串’) 获取 ‘字符串’ 在str中的首字母下标 如果字符串存在则返回首字母下标, 如果字符串不存在则返回固定值 -1 应用场景: 一般用户判断 str中是否有某个字符串 如果没有则返回-1,不是-1说明有

let  str='我要去曦度武'
let  index1=str.indexOf('度武')//4
let  index1=str.indexOf('去武')//-1

3. str.split(‘分隔符’) 用分隔符切割字符串,得到切割之后的数组 应用场景 : 一般用户解析 网址

let url = 'http://www.baidu.com?name=张三&age=20'
        console.log( url.split('|') )//['http://www.baidu.com?name=张三&age=20']
        console.log( url.split('?') )//['http://www.baidu.com', 'name=张三&age=20']
        console.log( url.split('=') )//['http://www.baidu.com?name', '张三&age', '20']

**4. str.substr(起始下标,截取长度) 截取字符串 应用场景 : 一般后台返回的数据 不会和前端完全匹配。 有时候需要自己截取一部分 例如: 商品价格后台返回 :价格58元 但是前端只需要显示58元,就需要截取 **

let  str='我要去曦度看武剑仙降临'
 console.log( str.substr(2,5) )//从2下标开始,往后截取5个字 //曦度看武剑仙 

5.大小写转换 (中文没有大小写) 应用场景: 字母验证码不区分大小写 (一般无论你输入什么,都会转成大写或小写保持格式统一)


        console.log('dsSFJSGDJHsdfs'.toLocaleLowerCase() )//小写 dssfjsgdjhsdfs
        console.log('dsSFJSGDJHsdfs'.toLocaleUpperCase() )//大写 DSSFJSGDJHSDFS
        

原型对象:

一.构造函数
1.工厂函数(了解) : 用于创建对象的函数
2.构造函数 : 使用new调用一个函数
构造函数作用与工厂函数一致,都是用来创建对象的。但是代码更加简洁。
3.构造函数new工作原理
(1)创建空对象
(2)this指向这个对象
(3)对象赋值
(4)返回这个对象
4.构造函数new在使用时需要注意的地方
4.1 构造函数首字母一般大写, 为了提醒调用者不要忘记new关键字
4.2 如果在构造函数内部 手动return
return 值类型 : 无效,还是返回new创建的对象
return 引用类型 : 有效,会覆盖new创建的对象

 function Person(name,age,sex){
    
    
            //(1)创建空对象   {}
            //(2)this指向这个对象  this = {}
            //(3)对象赋值
            this.name = name
            this.age = age
            this.sex = sex
            //(4)返回这个对象 return this
        }

        let p1 = new Person('嘿嘿嘿',23,'男')
        console.log(p1)//{name:'嘿嘿嘿',age:23,sex:'男'}
        

二.原型函数
(1)构造函数内部方法: 浪费内存资源 2.使用全局函数解决内存浪费3.使用对象 : 解决内存浪费 + 变量污染

//   function Person(name,age){
    
    
      //       this.name = name
      //       this.age = age
      //       this.eat = function(){
    
    
      //           console.log('eat');

      //       }
      //   }

      //   let p1 = new Person('张三',18)
      //   let p2 = new Person('李四',20)
      //   console.log( p1,p2)
      /* 思考: p1和p2都有eat方法,而是函数体相同。但是他们是同一个函数吗?
      不是同一个: 因为每一次调用构造函数, 内部都会执行一次function,就会在堆中开辟一个新的空间。虽然代码是一样的,但是地址不同。 就会导致每调用一次构造函数,多出一个函数堆空间。导致内存资源浪费
      */
      //   console.log( p1.eat == p2.eat )//false

      /* 2.使用全局函数解决内存浪费
      导致新的问题: 全局变量污染
      */
      //   let eat = function() {
    
    
      //     console.log("吃东西")
      //   }

      //   let learn = function() {
    
    
      //     console.log("学习")
      //   }

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

      //   let p1 = new Person("张三", 18)
      //   let p2 = new Person("李四", 20)
      //   console.log(p1, p2)
      /* 思考题:p1的eat和p2是不是同一个
      答案:是的  因为构造函数内部并没有重新function创建一个函数,而是拷贝eat的地址赋值。 无论你调用构造函数多少次,都是拷贝eat的地址
      */
      //   console.log( p1.eat == p2.eat )//true

      /* 3.使用对象 : 解决内存浪费 + 变量污染 */

      let obj = {
    
    
        eat: function() {
    
    
          console.log("吃东西")
        },
        learn: function() {
    
    
          console.log("学习")
        }
      }

      function Person(name, age) {
    
    
        this.name = name
        this.age = age
        this.eat = obj.eat
        this.learn = obj.learn
      }

      let p1 = new Person("张三", 18)
      let p2 = new Person("李四", 20)
      console.log(p1, p2)

三.原型对象
** 原型继承 :把父对象 作为子对象构造函数的原型
1.原型对象是什么? : 任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象
2.原型对象作用? : 解决 内存浪费 + 变量污染
3.原型对象相关三个属性 : 描述 构造函数、原型对象、实例对象三者关系
(1)prototype : 属于构造函数, 指向原型对象
(2)proto : 属于实例对象,指向原型对象, proto : 属于实例对象的,指向原型对象
注意: 这个属性不是web标准,很多浏览器不会显示的。 这个属性在开发中不能使用,只能用于学习研究
(3) constructor : 属于原型对象,指向构造函数
**

 /* 
        1.原型对象是什么? :  任何函数在声明的时候,系统会自动帮你创建一个对象,称之为原型对象
        2.原型对象作用? : 解决  内存浪费 + 变量污染
        3.原型对象相关三个属性
        */

      //构造函数
      function Person(name, age) {
    
    
        this.name = name
        this.age = age
      }

      //原型对象
      console.log(Person.prototype)
      Person.prototype = {
    
    
        eat: function() {
    
    
          console.log("吃东西")
        },
        learn: function() {
    
    
          console.log("学习")
        }
      }
      //实例对象 : 用new调用构造函数,返回的那个对象(new创建的那个对象)
      let p1 = new Person('张三',20)
      console.log( p1 )

      let p2 = new Person('李四',22)
      console.log( p1.eat == p2.eat )//true
      

四.获取对象所有的属性值

(1)以前 for-in 循环


         //1 以前的写法:  for-in 循环
         for(let key in person ){
    
    
             console.log( person[key] )  
         }

(2)现在:

 //2.静态方法  Object.values(对象名)
         //返回值是一个数组,会存储对象每一个属性值
         let arr = Object.values(person)
         console.log(arr)

面向对象的三大特征

面向对象三大特征: 封装 、 继承 、 多态
1.封装 : 把代码放入对象的方法中
2.继承 : 一个对象 拥有 另一个对象 所有的成员
3.多态 : 一个对象 在不同情况下的不同状态
js语言基本不涉及多态

2.1原型继承 :把父对象 作为子对象构造函数的原型

 <script>
        /* 
        1.继承 :  一个对象 拥有 另一个对象 所有的 成员
        2.原型继承 :把父对象 作为子对象构造函数的原型
        */

        //父对象
        let father = {
    
    
            house:{
    
    
                address : '深圳湾一号',
                price: 20000000
            },
            car:{
    
    
                brand : '劳斯莱斯幻影',
                price:15000000
            }
        }

        //子对象
        //构造函数
        function Son(name,age){
    
    
            this.name = name
            this.age = age
        }
        //原型继承: 把父对象 作为子对象构造函数的原型
        Son.prototype = father
        //可选 : 原型继承之后,由于父对象覆盖原来的 子对象构造函数原型, 就会导致constructor消失.
        //解决办法: 手动添加。(对开发几乎没有影响,也可以不加)
        Son.prototype.constructor = Son


        //实例对象
        let s1 = new Son('ikun',30)
        let s2 = new Son('班长',20)
        console.log(s1,s2)
        
        
    </script>
    

原型链

 <script>
       /* 
       1.原型链 : 每一个对象都有自己的原型, 而原型也是对象,也会有自己的原型,此次类推形成链式结构。称之为原型链。(原型链的终点是null)
       2.对象访问原型链规则 : 就近原则
        * 对象先访问自己的,自己没有就找原型的,原型没有就找原型的原型,一直到原型链终点null.如果还找不到。  属性则获取undefined, 方法则会报错 xxx is not function
       */     

       //1.构造函数
       function Person(name,age){
    
    
           this.name = name
           this.age = age
        //    this.type = '学生'//如果自己有type,优先访问自己的
       }

       //2.原型对象 : 存储具有共同特征的数据
       Person.prototype.type = '哺乳动物'
       Person.prototype.country = '中国'
       Person.prototype.eat = function(){
    
    
           console.log(this.name + '吃东西')
       }

       //3.实例对象
       let p1 = new Person('班长',20)
       let p2 = new Person('ikun',20)
       console.log(p1)
       

       /* 小测试 */
       console.log( p1.name )//班长  p1自己有name属性
       console.log( p1.age )//20   p1自己有age
       console.log( p1.type )//哺乳动物  p1自己没有type,但是p1的原型有
       console.log( p1.girlFrined )//undefined  p1自己没有girlFrined, p1的原型也没有girlFrined

       p1.eat()// 吃东西
      //    p1.learn()//报错   undefined is not a function
      /* 思考:  p1自己没有toString, p1的原型也没有toString, 但是为什么不报错呢?
      原因:  p1的原型的原型有toString
      */
       p1.toString()

       /* 如何查看实例对象原型 : 两行 */

       //查看p1的原型
       console.log( p1.__proto__.constructor )//Person
       console.log( Person.prototype === p1.__proto__ )//true
       //查看p1的原型的原型
       console.log( p1.__proto__.__proto__.constructor )//Object
       console.log( Object.prototype === p1.__proto__.__proto__ )//true
       //查看p1的原型的原型的原型
       console.log( p1.__proto__.__proto__.__proto__ )//null
              
   
       

    </script>

内置对象

<script>
        // 数组对象  
        //实例化对象
        let arr = [10,20,30]//new Array(10,20,30)
        console.log( arr )
        //1.1 查看arr的原型
        console.log( arr.__proto__.constructor )//Array
        console.log( arr.__proto__ === Array.prototype )//true
        //1.2 查看arr的原型的原型
        console.log( arr.__proto__.__proto__.constructor )//Object
        console.log( arr.__proto__.__proto__ === Object.prototype )//true
        
        // 字符串对象
        let str = new String('abc')
        console.log( str )
        //2.1 查看str的原型
        console.log( str.__proto__.constructor )//String
        console.log( str.__proto__ === String.prototype )//true
        //2.2 查看arr的原型的原型
        console.log( str.__proto__.__proto__.constructor )//Object
        console.log( str.__proto__.__proto__ === Object.prototype )//true
        
        // 日期对象
        let date = new Date()
        /* js有几个特殊的对象 无法使用 log来打印的,需要用dir来打印: function date dom对象 */
        console.dir( date )
        //3.1 查看date的原型
        console.log( date.__proto__.constructor )//Date
        console.log( date.__proto__ === Date.prototype )//true
        //3.2 查看date的原型的原型
        console.log( date.__proto__.__proto__.constructor )//Object
        console.log( date.__proto__.__proto__ === Object.prototype )//true
        
    </script>

instanceof(关键字)

 <script>
        /* 
        1. instanceof(关键字): 运算符。 用于检测 构造函数的prototype在不在实例对象的原型链中
            说人话: 亲子鉴定,鉴定两个对象之间有没有血缘关系
        2.  实例对象 instanceof 构造函数
            检测 右边构造函数的prototype 在不在 左边实例对象的原型链中
        
        3. 应用 :  某些函数为了限制你的数据类型,在内部需要用instanceof进行判断是否是正确的数据类型
        */    

        let arr = [10,20,30]
        // arr-> Array.prototype -> Object.prototype -> null
        console.log( arr instanceof Array )//true
        console.log( arr instanceof Object )//true
        console.log( arr instanceof String )//false

        //封装一个函数,要求这个函数必须要传数组类型、 传其他类型不可以
        function fn(arr){
    
    
            if( arr instanceof Array){
    
    
                console.log( arr.reverse() )
            }else{
    
    
                console.log('数据类型错误')
            }
        }

        fn( [10,20,30] )
        fn( 'abc' )


        
    </script>

面向对象封装消息提示

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>面向对象封装消息提示</title>
    <style>
      .modal {
    
    
        width: 300px;
        min-height: 100px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        border-radius: 4px;
        position: fixed;
        z-index: 999;
        left: 50%;
        top: 50%;
        transform: translate3d(-50%, -50%, 0);
        background-color: #fff;
      }
      .modal .header {
    
    
        line-height: 40px;
        padding: 0 10px;
        position: relative;
        font-size: 20px;
      }
      .modal .header i {
    
    
        font-style: normal;
        color: #999;
        position: absolute;
        right: 15px;
        top: -2px;
        cursor: pointer;
      }
      .modal .body {
    
    
        text-align: center;
        padding: 10px;
      }
      .modal .footer {
    
    
        display: flex;
        justify-content: flex-end;
        padding: 10px;
      }
      .modal .footer a {
    
    
        padding: 3px 8px;
        background: #ccc;
        text-decoration: none;
        color: #fff;
        border-radius: 2px;
        margin-right: 10px;
        font-size: 14px;
      }
      .modal .footer a.submit {
    
    
        background-color: #369;
      }
    </style>
  </head>
  <body>
    <button id="btn1">消息提示1</button>
    <button id="btn2">消息提示2</button>
    <button id="btn3">消息提示3</button>
    <button id="btn4">消息提示4</button>

    <!-- <div class="modal">
      <div class="header">提示消息 <i>x</i></div>
      <div class="body">消息内容</div>
      <div class="footer">
        <a href="javascript:;" class="cancel">取消</a>
        <a href="javascript:;" class="submit">确认</a>
      </div>
    </div> -->

 
    <script>
      //1. 模态框构造函数
      function Modal(title,message){
    
    
        this.title = title
        this.message = message
        this.modalBox = `<div class="modal">
        <div class="header">${
     
     this.title} <i>x</i></div>
        <div class="body">${
     
     this.message}</div>
        </div>`
      }

      //2. 模态框原型
      Modal.prototype.open = function(){
    
    
        //(1)创建空标签
        let div = document.createElement('div')
        //(2)设置标签内容
        div.innerHTML = this.modalBox
        //(3)添加到页面
        document.body.appendChild(div)
        //给删除按钮注册点击事件
        div.querySelector('.header i').onclick = function(){
    
    
          document.body.removeChild(div)
        }
      }

      //1.确认框构造函数
      function Confirm(title,message){
    
    
        this.title = title
        this.message = message
        this.modalBox = ` <div class="modal">
        <div class="header">${
     
     this.title} <i>x</i></div>
        <div class="body">${
     
     this.message}</div>
        <div class="footer">
          <a href="javascript:;" class="cancel">取消</a>
          <a href="javascript:;" class="submit">确认</a>
        </div>
        </div>`
      }

      /* 为什么要继承: confirm确认框和 modal模态框 功能是一样的, 也要显示到页面,也要点击xx移除
      1.继承 :  一个对象 继承 另一个对象 所有的成员
      2.原型继承 :  把父对象 作为 子对象构造函数的原型
      */
       Confirm.prototype = Modal.prototype

      //继续给Confirm的原型添加自己的方法
      Confirm.prototype.addEvent = function( confirm ){
    
    
        let modal = document.querySelector('.modal')
        modal.querySelector('.submit').onclick = function(){
    
    
          //调用函数
          confirm()
          //移除模态框
          modal.parentNode.removeChild(modal)
        }
        modal.querySelector('.cancel').onclick = function(){
    
    
          //移除模态框
          modal.parentNode.removeChild(modal)
        }
      }

      //弹窗1
      document.querySelector('#btn1').onclick = function(){
    
     
        //创建模态框
        let m = new Modal('友情提示','删除成功')
        m.open()
        console.log( m )
      }
      //弹窗2
      document.querySelector('#btn2').onclick = function(){
    
    
        //创建模态框
        let mm = new Modal('提示消息','您没有权限操作')
        mm.open()
      }

      //弹窗3
      document.querySelector('#btn3').onclick = function(){
    
    
        //创建确认框
        let c = new Confirm('友情提示','您确定要删除吗?')
        console.log(c)
        c.open()
        //添加确认功能
        c.addEvent( function(){
    
     alert('删除成功')}  )
        
      }
      //弹窗4
      document.querySelector('#btn4').onclick = function(){
    
    
        //创建确认框
        let c = new Confirm('友情提示','您确定要下单吗?')
        c.open()
        //添加确认功能
        c.addEvent(function(){
    
    
          alert('下单成功')
        })
      }

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

arguments关键字:

    <script>
        /* 
        1. arguments关键字: 获取函数所有的 实参
            是一个伪数组 :  有数组三要素(元素、下标、长度),但是不能使用数组的方法

        2. 应用 : 一般用户参数数量不限的函数. 
            例如: arr.push()  Math.max()  这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
        */    

        function fn(a,b){
    
    
            console.log(a)
            console.log(b)
            console.log(a+b)
            console.log(arguments)  
        }

        fn()
        fn(10)
        fn(10,20)
        fn(10,20,30)
        fn(10,20,30,40)


        
    </script>

剩余的

<script>
        /* 
        1. arguments关键字: 获取函数所有的 实参
            是一个伪数组 :  有数组三要素(元素、下标、长度),但是不能使用数组的方法

        2. 应用 : 一般用户参数数量不限的函数. 
            例如: arr.push()  Math.max()  这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参

        3. 剩余参数(rest参数) : 获取函数剩余的所有实参
            语法:  function 函数名(形参1,...形参2){
    
    }
            特点: (1)只能作为最后一个参数  (2)是真数组

        4. 一般情况下,rest参数可以替代arguments
        */    

        function fn(...b){
    
    
            console.log(b)//10
            console.log(arguments)
            
        }

        fn(10)
        fn(10,20)
        fn(10,20,30)
        fn(10,20,30,40)


        
    </script>

函数默认参数

<script>
        /* 
        1. arguments关键字: 获取函数所有的 实参
            是一个伪数组 :  有数组三要素(元素、下标、长度),但是不能使用数组的方法

        2. 应用 : 一般用户参数数量不限的函数. 
            例如: arr.push()  Math.max()  这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参

        3. 剩余参数(rest参数) : 获取函数剩余的所有实参
            语法:  function 函数名(形参1,...形参2){
    
    }
            特点: (1)只能作为最后一个参数  (2)是真数组

        4. 一般情况下,rest参数可以替代arguments

        5. 函数默认参数
            function 函数名(形参=默认值){
    
      }
        */    

        function fn(a=10,b=20){
    
    
            //以前: 逻辑或短路
            // 找真 : 左边是真就返回左边式子的值,否则返回右边式子的值
            // a = a || 10
            // b = b || 20
            console.log( a + b ) 
        }

        fn(5)
        


        
    </script>

环境对象 this

 <script>
        /* 
        环境对象 this :'调用'我,我就指向谁 
            普通函数;  函数名()          this指向window
            对象方法:   对象名.方法名()   this指向对象
            构造函数;  new 函数名()      this指向new创建实例对象
                * 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
        */

        function fn(){
    
    
            console.log( this )
        }

        //普通函数 : window
        fn()
        //构造函数 : new创建实例对象
        new fn()

        let obj = {
    
    
            name:'张三',
            eat:fn
        }
        //对象方法 : obj对象
        obj.eat()

    </script>
 <script>
        /* 
        环境对象 this :'调用'我,我就指向谁 
            普通函数;  函数名()          this指向window
            对象方法:   对象名.方法名()   this指向对象
            构造函数;  new 函数名()      this指向new创建实例对象
                * 小技巧: 没点没new是window, 有new是实例,有点是点左边的对象
        */

      //作用域链
      let obj = {
    
    
        name: "张三",
        eat: function() {
    
    
          //1级链
          console.log(this) //1.obj
          function fn() {
    
    
            //2级链
            console.log(this) //2.window
          }
          fn()
        }
      }

      let eat = obj.eat
      obj.eat()
    </script>

函数上下文调用

call()调用函数

 <script>
        /* 
        1.环境对象 this : 谁'调用'我,我就指向谁 
            普通函数;  函数名()          this指向window
            对象方法:   对象名.方法名()   this指向对象
            构造函数;  new 函数名()      this指向new创建实例对象

        *** 默认情况下,函数内部的this不能主动修改. 如果需要修改,则需要使用上下文方式

        2.上下文调用 : 修改函数内部的this
            2.1 函数名.call(修改后的this,形参1,形参2…………)
            2.2 函数名.apply()
            2.3 函数名.bind()

        3. 面试必问:  call 和 apply 和 bind三者区别
        */

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

        // 函数名.call(修改后的this)
        fn.call({
    
    name:'张三'},10,20)


    </script>
<script>
        /* 伪数组 : 有数组三要素(下标,元素,长度),但是没有数组的方法
            伪数组本质是对象
         */

        let weiArr = {
    
    
            0:88,
            1:20,
            2:50,
            3:60,
            length:4
        }

        console.log( weiArr )

        //如果希望伪数组也可以调用数组的方法(排序、拼接),就需要把伪数组转成真数组

        /* 
        1. slice可以查询数组,默认情况下不传参这个方法会得到数组本身
        2. 但是伪数组由于原型不是Array,所以无法调用slice
        3. slice方法存储在哪里? : Array.prototype
        */
        weiArr = Array.prototype.slice.call(weiArr)
        console.log(weiArr)
        
        // weiArr.slice()

        //实际开发中,ES6新增语法用于伪数组转真数组 :  Array.from(伪数组)
        let arr = Array.from(weiArr)
        console.log( arr )
        
        
        
    </script>
 <script>
        /* 
        1. typeof 数据 : 有两种数据类型无法检测
            null和数组无法检测,结果都是 'object'

        2. 解决方案:万能数据类型检测
            Object.prototype.toString.call(数据)
         */

        //值类型
        let str = 'abc'
        let num = 123
        let bol = true
        let und = undefined
        let nul = null
        //引用类型
        let arr = [10,20,30]
        let fn = function(){
    
    }
        let obj = {
    
    name:'张三'}

        console.log( typeof str )//'string'
        console.log( typeof num )//'number'
        console.log( typeof bol )//'boolean'
        console.log( typeof und )//'undefined'
        console.log( typeof nul )//'object'
        console.log( typeof arr )//'object'
        console.log( typeof fn )//'function'
        console.log( typeof obj )//'object'


        /* Object.prototype.toString() 返回固定格式字符串 '[object 数据类型]' */
        console.log( Object.prototype.toString.call( str ) )//[object String]
        console.log( Object.prototype.toString.call( num ) )//[object Number]
        console.log( Object.prototype.toString.call( bol ) )//[object Boolean]
        console.log( Object.prototype.toString.call( und ) )//[object Undefined]
        console.log( Object.prototype.toString.call( nul ) )//[object Null]
        console.log( Object.prototype.toString.call( arr ) )//[object Array]
        console.log( Object.prototype.toString.call( fn ) )//[object Function]
        console.log( Object.prototype.toString.call( obj ) )//[object Object]
        
        
        
        
    </script>

apply(修改后的this, 数组或伪数组 )

<script>
        /* 
        1.环境对象 this : 谁'调用'我,我就指向谁 
            普通函数;  函数名()          this指向window
            对象方法:   对象名.方法名()   this指向对象
            构造函数;  new 函数名()      this指向new创建实例对象

        2.上下文调用 : 修改函数内部的this
            2.1 函数名.call(修改后的this,形参1,形参2…………)
            2.2 函数名.apply(修改后的this, 数组或伪数组 )
            2.3 函数名.bind()

        3. 面试必问:  call 和 apply 和 bind三者区别
        */

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

        // 函数名.call(修改后的this,形参1,形参2…………)
        fn.call({
    
    name:'张三'},10,20)
        
        // 函数名.apply(修改后的this, 数组或伪数组 )
        // apply会自动帮你遍历数组,然后按照顺序逐一传参
        fn.apply({
    
    name:'李四'}, [30,40] )


    </script>
<script>
        //伪数组 本质是 :  对象
        let obj = {
    
    
            0:20,
            1:66,
            2:88,
            3:90,
            length:4
        }  
        
        //伪数组转真数组
        let arr = []
        // arr.push( obj[0],obj[1],obj[2],obj[3])
        //借助 apply自动遍历数组/伪数组 逐一传参特点
        //这里不需要修改this,只是借助apply传参的特点. this指向原来是谁,还是设置谁
        arr.push.apply( arr,obj )
        console.log(arr)

        //伪数组转真数组 :  Array.from( 伪数组 )
        console.log( Array.from(obj) )
        
        
    </script>
  <script>
        //求数组最大值
        let arr = [20,50,66,100,30]
        
        //1.js基础 : 擂台思想
        let max = arr[0]
        for(let i = 1;i<arr.length;i++){
    
    
            if( arr[i] > max ){
    
    
                max = arr[i]
            }
        }
        console.log(max)

        //2. Math.max()
        // let max1 = Math.max(arr[0],arr[1],arr[2],arr[3],arr[4])
        //这里使用apply只是借助传参特点,this指向不用修改。还是原来的this
        let max1 = Math.max.apply(Math,arr)
        console.log( max1 )

        //ES6求最大值   ...作用和apply类似,也会自动遍历数组,然后逐一传参
        let max2 = Math.max(...arr)
        console.log(max2)
        
    </script>

bind(修改后的this)

 <script>
        /* 
        1.环境对象 this : 谁'调用'我,我就指向谁 
            普通函数;  函数名()          this指向window
            对象方法:   对象名.方法名()   this指向对象
            构造函数;  new 函数名()      this指向new创建实例对象

        2.上下文调用 : 修改函数内部的this
            2.1 函数名.call(修改后的this,形参1,形参2…………)
            2.2 函数名.apply(修改后的this, 数组或伪数组 )
            2.3 函数名.bind(修改后的this)
                * 不会立即执行函数,而是得到一个修改this之后的新函数。
                * bind一般用于修改: 定时器函数、事件处理函数

        3. 面试必问:  call 和 apply 和 bind三者区别
        */

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

        // 函数名.call(修改后的this,形参1,形参2…………)
        fn.call({
    
    name:'张三'},10,20)
        
        // 函数名.apply(修改后的this, 数组或伪数组 )
        // apply会自动帮你遍历数组,然后按照顺序逐一传参
        fn.apply({
    
    name:'李四'}, [30,40] )

        //函数名.bind(修改后的this)
        // bind不会立即执行函数,而是返回一个修改this之后的新函数
        let newFn = fn.bind({
    
    name:'王五'})
        newFn(100,200)
        newFn(10,20)


    </script>
<script>
        /*
        定时器中的this : 默认指向window
        */

        setTimeout(function() {
    
    
          console.log(this)
        }.bind({
    
     name: "1111" }),2000)


      //   let obj = {
    
    
      //     name: "张三",
      //     hobby: ["学习", "干饭", "睡觉"],
      //     sayHi: function() {
    
    
      //       setTimeout(function() {
    
    
      //         console.log(this)
      //       }, 1000)
      //     }
      //   }

      //   obj.sayHi()
    </script>

**
1.环境对象 this : 谁’调用’我,我就指向谁
普通函数; 函数名() this指向window
对象方法: 对象名.方法名() this指向对象
构造函数; new 函数名() this指向new创建实例对象
2.上下文调用 : 修改函数内部的this
2.1 函数名.call(修改后的this,形参1,形参2…………)
2.2 函数名.apply(修改后的this, 数组或伪数组 )
2.3 函数名.bind(修改后的this)
* 不会立即执行函数,而是得到一个修改this之后的新函数。
* bind一般用于修改: 定时器函数、事件处理函数
3.面试必问: call 和 apply 和 bind 三者区别
相同点 : 作用一致,修改函数this指向
不同点 :
传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参
执行机制不同 : call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数
**

1.闭包closure是什么 : a. 闭包 是一个 访问其他函数内部变量 的 函数 b. 闭包 = 函数 + 上下文引用 2.闭包作用 : 解决变量污染 * 一般用于回调函数

 3.在浏览器中调试闭包 :
        */    

        document.querySelector('.btn').onclick = function(){
    
    
            //1.获取用户搜索的内容
            let txt = document.querySelector('input').value
            //2.网络请求 : 不是立即就能出结果的,网络请求需要时间的。
            //使用定时器来模拟请求
            setTimeout(function(){
    
    
                alert(`${
    
    txt}的搜索结果如下:123条`)
            },1000)
        }

递归函数: 一个函数 在内部 调用自己,递归作用和循环类似的,也需要有结束条件

 //双函数递归 : 两个函数互相调用
        function fn1(){
    
    
            console.log('哈哈')
            fn2()
        }

        function fn2(){
    
    
            console.log('呵呵')
            fn1()
        }

1.递归函数: 一个函数 在内部 调用自己 * 递归作用和循环类似的,也需要有结束条件 2.递归应用: 浅拷贝与深拷贝 : 方式一(推荐) : JSON方式实现 * let newObj = JSON.parse( JSON.stringify( obj ) ) 方式二(递归) : 了解 遍历dom树

//浅拷贝: 拷贝地址
// 修改拷贝后的数据,原数据也会修改
 
 //深拷贝 : 拷贝数据
//(1)先把js对象 -> JSON字符串   (JSON会自动帮你深拷贝)
// let jsonStr = JSON.stringify( obj )
//(2)再把 JSON字符串 -> js对象
// let newObj = JSON.parse( jsonStr )

猜你喜欢

转载自blog.csdn.net/qq_43944285/article/details/124503627