0


JavaScript高阶

1,作用域与函数进阶

1.1 执行环境关联着变量对象

          (1)执行环境关联着一个变量对象,变量对象里面存储着我们声明的变量以及函数

          (2)全局执行环境  window对象

1.2 执行环境栈

          (1)当代码在函数中执行,函数也有执行环境,环境被推入执行环境栈中

          (2)栈 :存放数据的容器,先入后出。应用运行期间全局环境变量window不会被销毁

1.3 作用域与作用域链

            1,标识符

                    变量,函数,对象的属性的名字,函数的参数

            2,作用域

                    标识符以及标识符所能访问的范围

            3,作用域链

                    作用域一层包裹一层,形成的链式结果

            4,关系

                    代码在执行环境中执行时,会创建作用域链,变量对象中存着各种作用域的标识符

            5,作用域链的作用

                    标识符查找,沿着作用域链逐级寻找,直到找到全局作用域window,如果找不到则报错

            6,拓展

                    作用域链确保了标识符的有序访问

1.4 作用域的分类

            1,全局作用域-window对象

            2,局部作用域-函数作用域,函数中代码执行后会被自动销毁

            3,块级作用域(用{}包裹起来的内容):ES5没有块级作用域

            4,let和const声明的变量特性:只能在所在的代码块内被访问

1.5 ES6箭头函数(精通)

            1,语法  :(参数1,参数2)=>{...函数语句....}

            2,简写

                    1,如果传入参数只有1个 ()可以省略

                    2,如果函数体内只有一行代码{}可省略,此时必须return return可以省略

            3,箭头函数和一般函数的区别(高频)

                    1,函数体内this对象,就是函数定义时所在的对象,而不是调用时所在的对象

                    2,不可以当做构造函数,不可以使用new命令,否则报错

                    3,没有arguments对象

1.6 函数的形参和实参

            1,形参

                    函数定义时所列的参数变量

            2,实参

                    函数调用时所传递的值

1.7 arguments

            1, arguments是一个类数组对象,它包含所有的传入函数的参数

            2,arguments指的是实际传入的参数值的情况

            3,拥有数组的方法,可以取值

1.8 函数的默认参数

             直接在参数列表写=
<script>
    function log(x,y='world'){
        // y=y||'world';
        console.log(x,y);
    }
    log('hello')
    log('hello','你好')
</script>

1.9 ES6的rest参数

            写法:...变量名  它是一个真正的数组

            示例:
<script>
    //求和ES5
    function sum(){
        let sum=0;
        for (let i = 0; i < arguments.length; i++) {
            sum+=arguments[i];
            }
        return sum;
    }
       console.log(sum(1,2,3,4))
       //求和ES6
    const sum1=(...values)=>{
        let result=0;
        values.forEach((item,index)=>{
            result+=item;
        })
        return result;
    }  
    console.log(sum1(1,2,3,4,5))
</script>

1.10 函数的调用方式(6种)

            1,一般函数的调用

            2,对象的方法调用

            3,回调函数调用

            4,构造函数调用

            5,bind(),call(),apply()

            6,立即执行函数表达式  IIFE

1.11立即执行函数表达式

            1,写法:(function(){ ..内容.. })()  后面()调用
<script>
    (function(){
        console.log('立即执行函数表达式')
    })()
</script>
            2, IIFE作用

                    形成局部函数作用域,避免直接访问变量,可以实现简单的模块化

1.12 闭包(精通)

            1,闭包的形成?

                    变量的跨作用域访问,形成了闭包

            2,闭包是什么?

                    函数以及函数内部跨作用域所能访问的变量

            3,闭包使得函数内部能够访问函数创建时所处作用域的变量

            示例
<script>
    let money=500;
    function spendmoney(){
        console.log(money)
        money-=100;
    }
   spendmoney()
</script>

1.13 闭包的常见使用场景-嵌套函数中使用闭包

            示例
<script>
    function mum(){
        let money=500;
    function spendmoney(){
        console.log(money)
        money-=100;
    }
        return spendmoney
    }
   const spend= mum();
   spend()  // 500
   spend()  // 400
</script>
            1,父包含子,子访问父,最后再把子函数return或者挂到window上。形成常见的闭包方式。

1.14 IIFE中使用闭包

            示例
<script>
    //实现永不重复的计数器
   const getNum=(function(){
       let num=100;
       return function(){
            return num++;
       }
    })()
    console.log(getNum())
    console.log(getNum())
</script>
            1,闭包使得跨作用域访问的变量,不被销毁

1.15 闭包解决for循环定时器问题(经典问题打印5个5)

<script>
    //闭包解决for循环定时器问题
    // var i为全局作用域
    for (var i = 0; i < 5; i++) {//ES5没有块级作用域
    (function(k){
        window.setTimeout(()=>{
           console.log(k)
       },1000)
    })(i)
    }

     for (let i = 0; i < 5; i++) {
        window.setTimeout(()=>{
           console.log(i)
       },1000)
    }
</script>

1.16 闭包的作用

                    间接访问变量或者隐藏变量

1.17 js常见面试题(重点)

            1,使用for循环,forEach(),map()方法都可以遍历一个数组,他们之间的关系?(map返回数组 )

            2,谈谈你对DOM(文档对象模型 树 )的理解

            3,谈谈你对作用域的理解

            4,箭头函数与一般函数的区别(写法不同,指向不同,arguments)

            5,什么是闭包(函数 作用域)?闭包的作用?

2,面向对象的程序设计

2.1 面向对象与面向过程(熟练掌握)

            1,面向过程POP

                    侧重于分析步骤

            2,面向对象OOP

                    侧重于分析个体,考虑职责,能力,个体间的关系

                    优势:更贴近真实的事务,更能分析复杂且庞大的问题

2.2 类与实例对象

            1,类:具有相同特征的一类事物的抽象

            2,实例对象:具有各自差异的个体

            3,类与实例对象的关系?

                    通过类可以创建具有相同特征的实例对象

            4,js的内置类:Object,Array,String等

2.3 对象的创建

            1,使用内置对象创建

            2,使用字面量创建

            3,工厂模式
<script>
    // 使用内置对象创建
    const yuan=new Object();
    yuan.name='lisa';
    yuan.age=12;
    console.log(yuan)
    //使用字面量创建
    const yuan1={
       name:'lisa',
       age:12
    }
    console.log(yuan1)
    //工厂模式  -设计模式
    // 工厂函数  批量生产相似对象
    function creatPlayer(name,age){
        //创建空对象
        let obj={ }
        // 对象属性赋值
        obj.name=name;
        obj.age=age;
        obj.sayName=function(){
            console.log(this.name)
        }
        // 返回对象
        return obj;
    }
    const yuan2=creatPlayer('hell',14)
    console.log(yuan2)
    console.log(yuan2.sayName())
    </script>

2.4 构造函数模式创建对象

            1,工厂模式的缺点   

                    虽然解决了对象的批量创建,没有解决对象的识别问题(对象属于哪一类?)                 2,语法:new 构造函数  得到  实例对象
<script>
    //构造函数
    function Player(name,age){
        //将属性和方法挂到this
        this.name=name;
        this.age=age;
        //方法
        this.sayName=function(){
            console.log(this.name)
        }
    }
    //调用
    const yuan=new Player('lisa',12)
    const yuan1=new Player('lisa1',22)
    const yuan2=new Player('lisa2',32)
</script>
            3,构造函数与一般函数的区别   

                    (1)命名采用大驼峰

                    (2)把属性和方法挂到this上,this指向最终创建出来的实例对象   

                    (3)不需要返回值     默认return最终创建出来的实例对象
<script>
    //构造函数
    function Player(name,age){
        //将属性和方法挂到this
        this.name=name;
        this.age=age;
        //方法
        this.sayName=function(){
            console.log(this.name)
        }
    }
    //调用
    const yuan=new Player('lisa',12)
    const yuan1=new Player('lisa1',22)
    const yuan2=new Player('lisa2',32)
</script>
             4,面试-使用关键字new创建对象的过程

                    (1)创建一个空对象

                    (2)把this指向空对象

                    (3)this上挂属性和方法

                    (4)返回对象

2.5 方法过载

                每个方法在不同的实例对象上都不一样,方法没办法共享

2.6 原型对象

            1,原型对象:构造函数.prototype,它是一个对象,保存着被实例所共享的属性和方法                  ![](https://img-blog.csdnimg.cn/3da2d243680149209e08b4e1b8183b2e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAc3RheSBjYWxtfg==,size_20,color_FFFFFF,t_70,g_se,x_16)    

            1,面试-请你谈谈对原型对象的理解?

                    (1)函数创建时会自动创建prototype属性、他是一个原型对象,保存着被实例所共享的属性和方法

                    (2)原型对象中有constructor属性,指向构造函数

                    (3)实例对象有一个隐藏属性__proto__,指向原型对象

2.7 原型模式优化

<script>
    //构造函数
    function Player(name,age){
        //将属性和方法挂到this
        this.name=name;
        this.age=age;
        //将方法放在原型对象中,方法会被共享
        Player.prototype.sayName=function(){
            console.log(this.name)
        }
    }
    //调用
    const yuan=new Player('lisa',12)
    const yuan1=new Player('lisa1',22)
    const yuan2=new Player('lisa2',32)
</script>

2.8 原型链(精通)

             1,原型链的形成

             2,万物皆对象

            3,面试-请你谈谈对原型链的理解?

                (1)一个构造函数有他对应的原型,原型又可以是另一个构造函数创建出来的实例,实例也有他所对应的原型 ,这种关系层层递进,形成的链式结构就是原型链

                (2)作用:在对象上查找标识符,会在自己身上找,如果找不到,往原型链上查找,直到找到object,否则报错

2.9 修改prototype

            修改底层push方法
  Array.prototype.push=function(){
        console.log('到此一游')
    }

2.10 this的前六种指向

            1,全局中 ----> window对象  

            2,一般函数中指向调用者

            3,对象方法中指向调用者

            4,事件处理函数中 指向事件源 触发事件的元素

            5,构造函数中 实例对象

            6,定时器中指向window
<!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>
    <button id="btn">点我</button>
</body>
</html>
<script>
    //全局中
    console.log(this)
    // 一般函数中  指向调用者
    function fn(){
        console.log(this)
    }
    fn();
    //对象方法中
    const person ={
        name:'lisa',
        age:12,
        sayName(){//sayName:function(){}
            console.log(this.name)
        }
    }
    person.sayName();
    var name='Dave';
    var say=person.sayName;
    say();
    //事件处理函数中  指向事件源 触发事件的元素
    document.getElementById('btn').addEventListener('click',function(){
        console.log(this)
    })
    // 构造函数中   实例对象
    // 定时器中
    window.setTimeout(function(){
        console.log(this)
    },1000)

</script>

2.11 bind() call() apply()

            1,作用:修改this

            2,function.prototype.call:传入要改变的this以及参数列表,并调用

            3,function.prototype.apply:用法与call一致,传入参数数组

            4,function.prototype.bind:得到一个改变this的函数
<script>
    const person={
        name:'lisa',
        age:12,
        sayName(type,num){
            console.log(`我是${this.name},我今年${this.age}岁了,我喜欢的音乐风格${type},我储存了${num}首`)
        }
    }
    const person1={
        name:'dave',
        age:23
    }
    //使用call 传入要改变的this以及参数列表
    person.sayName('流行',332)
    person.sayName.call(person1,'古典',122)
    //使用apply 传入参数数组
    person.sayName.apply(person1,['古典',122])
    // 使用bind  得到一个新的函数
    var sayPerson1=person.sayName.bind(person1);
    sayPerson1('国风',1234)

</script>
            7,谈谈bind,call和apply的区别?(面试)

                    (1)首先都能改变this指向

                    (2)从执行结果来看:call与apply是调用函数,bind是得到了一个新的函数

                    (3)传参不同:call与bind传参数列表,apply传参数数组

2.12 箭头函数中的this(面试常问)

            箭头函数的this指向定义时所在的作用域,而不是调用时的

3,变量的进阶

3.1 基本类型与引用类型的内存分配

            1, 基本类型(6):String Number Boolean null Symbol(ES6新增)

            2, 引用类型(1):Object(函数,数组,对象,Date,RegExp等等)

            3,基本类型:存在栈内存

            4,引用类型:实际的数据存在堆内存,地址存在栈内存中

            5,在js中如何访问引用数据类型?

                    先在栈内存找地址,然后在堆内存中找实际数据

3.2 变量的拷贝

            1,基本类型拷贝的是值

            2,引用类型拷贝的是地址,新旧变量共享堆内存中的数据
<script>
    //基本类型
    let a=100;
    let b=a;

    // 引用类型
    let  person={
        name:'lisa',
        age:12
    }
    //共享地址
    // let user=person;
    // user.age=13;
    // console.log(person.age)
    //新对象 新地址
    let user1=person;
    user1={
        name:'lisa',
        age:22
    }
    console.log(person.age)
</script>

3.3 函数传参

            1,函数的传参相当于把外面的变量拷贝给参数

            2,传参

                    (1)基本类型  将传递的值拷贝给参数

                    (2)引用类型  将传递的地址拷贝给参数
<script>
    //基本类型
    let a=10;
    function fn(b){
        b=20;
    }
    fn(a)
    console.log(a)
    //引用类型
    let person={
        name:'lisa',
        age:23
    }
    function fn1(b){
        // b.age=12;
        //反例
        b={
            age:12
        }
    }
    fn1(person)
    console.log(person.age)
</script>

3.4 对象的拷贝(深浅)

            1,对象的拷贝,根据拷贝层级区分深拷贝和浅拷贝

            2,浅拷贝:只拷贝一层,遇到引用类型的数据,拷贝地址

            3,深拷贝:无限层级的拷贝,新旧对象互不干扰

3.5 for-in循环以下示例为浅拷贝

<script>
    //for in 
    const person={
        name:'lisa',
        age:23,
        like:['打游戏']
    }

    let user={}//新对象
    for (const key in person) {
       console.log(person[key])
       user[key]=person[key];
    }
    console.log(user)
    user.age=11;
    console.log(person.age)//23

    user.like.push('看书')
    console.log(person.like)// 打游戏 看书
</script>

3.6 Object.assign()和JSON方法拷贝对象

            1,Object.assign()将原对象的属性拷贝到目标对象,得到新对象

            2,JSON方法

                    (1)将旧对象转成字符串

                    (2)将字符串解析成新对象

                    (3)优势:新旧对象互不影响

                    (4)劣势:无法拷贝函数方法

3.7 lodash的

_.cloneDeep(value)

深拷贝(可拷贝方法)

            lodash.cloneDeep | Lodash 中文文档 | Lodash 中文网

3.8 变量类型检测

<script>
    //基本类型
    typeof('你好')
    console.log(typeof('你好'))//string
    typeof(22)   //number
    typeof(false)   //boolean
    typeof(undefined)  //undefined
    typeof(null)        //object
    typeof(Symbol('a'))  //symbol
    //引用类型
    typeof({})  //object
    typeof([])  //object
    typeof(function fn(){}) //function
</script>
            1,typeof检测基本类型相对准确null为object

            2,typeof检测引用类型除函数是function之外其余都为object

3.9 instanceof

            公式:变量 instanceof 类型(构造函数)

            原理:检测构造函数的原型是否在实例变量的原型链上

3.10 Object.prototype.toString.call(),变量类型检测基本完美

            相当于借用Object.prototype上的toString()方法,不是将数据值转换为字符串,将类型信息以"[object Type]"格式输出
 //基本类型
    console.log(Object.prototype.toString.call('你好'))
    console.log(Object.prototype.toString.call(22))
    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(Symbol('a')))

    //引用类型
    console.log(Object.prototype.toString.call(function fn(){}))
    console.log(Object.prototype.toString.call([]))
    console.log(Object.prototype.toString.call({}))

3.11 原型链继承

             1,最大的问题

                    原型上引用类型属性的数据,会被所有实例共享,一旦数据发生变化,影响所有的实例

3.12 Object.create()

  const obj={
        sayName(){
            console.log("自我介绍")
        }
    }
    //得到一个新对象,传入一个对象  传入的对象是新对象的原型
    const obj1=Object.create(obj)
    console.log(obj1)

3.13 寄生组合式继承

           寄生式:通过Object.create()连接子类原型与父类原型,避免了多余的父类构造函数的执行;

           组合式:通过调用父类构造函数,来继承继承属性+通过父类原型来继承方法

4,ES6的新特性

4.1 ES6概念

            1,ES6是什么?H5与ES6都是语言标准,ES6泛指下一代语言标准,每年都更新。

4.2 Babel转码器

            1,它是一个js编辑器,能将ES6代码转换为ES5代码

4.3 变量的解构赋值(按照一定的结构为变量赋值)

            1,数组的解构赋值
    <script>
        let [a,b,c]=[1,2,3]
        console.log(a,b,c)
        //
        let [x,y]=['xxx']
        console.log(x,y)
    </script>
            2,对象的解构赋值
<script>
    //对象的解构赋值
    const user={
        name:'lisa',
        age:12
    }

    const {name,age}=user;
    console.log(name,age)

    const {x,y='yyy'}={x:'xxx'} 
    console.log(x,y)
</script>
            3,函数参数的解构赋值
<script>
    function add(arr){
        return arr[0]+arr[1]
    }

      function add([x,y]){
        return x+y
    }
    console.log(add([1,2]))
    //默认值0 0
    function move({x=0,y=0}={}){
        return [x,y]
    }   
    console.log(move({x:1}))
    console.log(move({x:1,y:2}))
    console.log(move({}))
    console.log(move())
</script>

4.4 展开运算符(...)

            1,函数的rest参数

            2,展开字符串
<script>
    const str='你好everyone';
    console.log(...str)//你 好 e v e r y o n e
    console.log([...str])//['你', '好', 'e', 'v', 'e', 'r', 'y', 'o', 'n', 'e']
    console.log(...[...str].reverse())//e n o y r e v e 好 你
    console.log([...str].reverse().join(''))//enoyreve好你
</script>
            3,展开数组
<script>
    let arr1=['a','b','c'];
    console.log(...arr1)//a b c
    //数组的浅拷贝
    let arr2=[...arr1];
    console.log(arr2)
    //数组拼接  重要
    const arr3=['A','B','C'];
    const arr4=[5,45,3,...arr3,...arr1];
    console.log(arr4)
    // 伪数组转真数组
    function fn(){
        console.log([...arguments])
    }
    fn(1,2)
</script>
            3,展开对象

                    1,必须用{}承接
<script>
    const person={
        name:'lisa',
        age:23
    }
    console.log({...person})
    //对象的浅拷贝
    const person1={...person};
    console.log(person1)
    //对象的拼接
    const dave={
        name:'Dave',
        like:"swim"
    }
     const linda={
         name:'lin',
         ...person1,
         ...dave
     }
     console.log(linda)
</script>

4.5 模板字符串

            使用反引号,换行符和空格都会保留,变量使用${}拼接

4.6 对象的简洁表示

<script>
    let name='lisa';
    //ES5
    const  person={
        name:name,
        sayName:function(){
            console.log("自我介绍")
        }
    }
    //ES6
    const person1={
        name,
        sayName(){
            console.log("自我介绍")
        }
    }
    console.log(person1)
</script>

4.7 ES6class

<script>
    //声明一个类
    class Person{
        //构造函数
        constructor(name,age){
            //实例属性
            this.name=name;
            this.age=age;
        }
        // 声明原型方法
        show(){
            console.log(this.name)
        }
        //构造函数  不加关键字为原型方法
        static say(){
            console.log('你好')
        }
    }
    const user=new Person('lisa',23);
    console.log(user)
    user.show()
    console.log(Object.prototype.toString.call(Person))//检测类型  [object Function]
    Person.say()
</script>
            1,class用它声明一个类,函数类型

            2,constructor:构造函数,可以传参,通过this绑定实例属性

            3,原型方法:不需要使用构造函数.prototype,写在最顶层

            4,静态方法:类的方法,实例不能调。关键字static

            5,实例属性可以写在最顶层(固定值,没办法传参)

4.8 ES6模块化

            1,模块化解决什么问题?

                    (1)命名冲突

                    (2)职责分离

            2,ES6模块化的优势?

                    ES6模块化在编译时就能确定模块之间的依赖关系,以及输出与输入的变量

4.9 ES6class实现类的继承

<script>
    class Father{
        constructor(name,age){
            //实例属性
            this.name=name;
            this.age=age;
        }
        //实例属性
        skills=['swim','run','read'];

        // 原型方法
        getFatherSkills(){
            console.log(this.skills)
        }
    }
      //子类
      class Son extends Father{
            constructor(name,age){
                //super是父类构造函数
                super(name,age);//等价于Father.call(this,name,age)
            }
            color='red';
        }
</script>

5,异步编程

5.1 同步与异步

            1,同步

                    代码从上往下依次执行,后面的代码要等待前面的代码执行之后,才能执行

            2,异步

                    代码从上往下依次执行,遇到异步代码,异步代码会先走开在一边等待,等所有的同步代码执行完,在执行异步代码

5.2 异步常见的编码场景

            1,定时器window.setTimeout(),延迟执行;window.setInterval(),固定时间间隔调用

            2,事件处理

            3,Ajax处理

                    原生js,$.ajax()

            4,回调函数

                    作用:可以放心大胆地执行异步代码,不用担心错过执行时机

5.3 Promise的概念

            1,Promise是用来管理异步操作的,可以用同步的方式编写异步代码

            2,Promise是构造函数

            3,new Promise构造函数=实例

            4,Promise状态  进行中pending  已成功 fulfilled  已失败 rejected,状态的特点,状态切换不可逆,要么成功要么失败

5.4 Promise的基本语法

<script>
    //Promise构造函数
    new Promise((resolve,reject)=>{//Promise构造函数的参数,是1个函数
        if(true){
            resolve('200')//传递成功时的数据
        }else{
            reject('500')
        }
    }).then((data)=>{
        console.log("成功时调用")
        console.log(data)
    })//原型
    .catch((err)=>{
        console.log("失败时调用",err)
    })
</script>

5.5 Promise解决回调地狱问题

<script src="./jquery.js"></script>
<script>
    new Promise((resolve)=>{
        //写同步异步代码均可以
        $.ajax({
            type:'GET',
            url:'./data.json',
            success:function(res){
                   resolve(res)
            }
        })
    })
    .then((res)=>{
        const {id}=res;
        //返回一个新的Promise实例
        return new Promise((resolve=>{
            $.ajax({//第二次请求
                type:'GET',
                url:'./data1.json',
                success:function(res){
                resolve(res)
            }
            })
        }))
    })
    .then((res)=>{
        const {code}=res;
    })
</script>

5.6 getData函数抽取

<script src="./jquery.js"></script>
<script>
    function getData(url,data){
        return new Promise((resolve)=>{
            $.ajax({
                type:'GET',
                url,
                data,
                success:function(res){
                    resolve(res)
                }
            })
        })
   }
    getData('./data.json') //Promise实例
    .then((res)=>{
        // console.log('取值')
        return getData('./data1.json',{code:res.code})
    })
</script>

5.7 Axios

            1,jQuery优势:DOM操作的封装,css选择器选取DOM元素,浏览器兼容好

            2,Axios库的定位:基于Promise的(面向浏览器和nodejs)的http请求库

            3,调用AxiosAPI,返回Promise实例

5.8 async异步与await等待(熟练掌握)

            1,async使用:写在函数前,表示这个函数中有异步操作
<script>
    //async表示函数中有异步操作
    async function fn(){

    }
    const fn2=async()=>{
        //我有异步操作
    }
</script>
            2,await使用:与async是一对兄弟,必须配合使用
<script>
    //异步
    function timer(){
        return new Promise((resolve)=>{
            window.setTimeout(()=>{
                console.log(2)
                resolve(200)
            },1000)
        })
    }
    async function printfn(){
        console.log(1)
        const res=await timer()//用来等待一个异步操作,一般等待Promise的状态切换
        console.log(res)
        console.log(3)
    }

    printfn()
</script>
标签: javascript 前端

本文转载自: https://blog.csdn.net/qq_50352386/article/details/122893012
版权归原作者 stay calm~ 所有, 如有侵权,请联系我们删除。

“JavaScript高阶”的评论:

还没有评论