• 什么是作用域, 什么是闭包, 什么是原型链,什么是递归, 什么是函数函数声明,什么是函数表达式,继承,this 指向


     
    什么是作用域
    作用域即作用范围,在js中采用的是词法作用域,所谓的词法作用域之的是在代码编写的过程中体现出来的作用范围,代码一旦写好,不用执行作用范围就已经决定了,这个就是词法作用域
    在js中作用域的规则,
    * 函数运行访问函数外的数据
    * 在整个代码中只有函数可以限定作用域
    * 首先需要考虑提升规则
    * 如果当前作用域中已经有名字,就不再考虑函数外的名字(就近原则)
     
    # 作用域链
    1. 在js中只有函数可以制造作用域,只要有代码就会有一个作用域即全局作用域,凡是代码中有函数那么这个函数就构成了一个新的作用域,如何函数中还有函数,那么在这个作用域中就会再有一个新的作用域诞生,这样将所有的作用域列出来就构成了作用域链
     
    # 变量的访问
    * 首先看变量在第几条链上(即哪个作用域),在该链上看是否存在变量的定义与赋值,如果有直接拿来使用,
    * 如果没有去上一层链去查找,如果有直接使用,停止继续查找
    * 如果还没有就继续查找.直到找到全局作用域,如果全局作用有中没有,就是is not defined
    * 同级链是不可以混合查找的
    #代码预解析(变量提升)
    # 在程序执行的过程中,会先将代码读取内存中,会将所有的声明在此时进行标记,所谓的标记就是告诉解释器知道有这个名字,后面再使用名字的时候,不会出现未定义的错误,这个标记过程就是变量名提升
    # 名字声明:
    即变量名提升 :告诉解释器知道已 经有这个名字了。且只提升变量名(没有任何数据与其对应)
    # 函数声明:函数声明包括两个部分:
    1. 首先函数声明告诉解释器,这个名字已经存在,还阶段与变量名提升一样
    2. 告诉解释器,这个名字对应的函数体是什么
    * . 函数声明与函数表达有区别,函数声明单独写在一个结构中,不存在任何语句。逻辑判断等结构中
    * . 函数后面不加括号
     
    什么是闭包?
    1. 闭包的含义就是闭合,简单的说就是一个具有封闭风格与包裹功能的一个结构,所以闭包就是一个具有封闭对外不公开的包裹结构或空间
    2. 在js中函数可以构成闭包,即一个函数是一个代码结构的封闭结构,即包裹的特性。根据作用域规则,只允许函数访问外部的数据,外部无法访问函数内部的数据,即封闭的对外不公开的特性,因此说函数可以构成闭包
    举个例子:
    var foo = (function(){
      return {}
      或者 return function(){}
    })()
     
    # 闭包要解决的问题
    1.  闭包不允许外界访问
    2. 要解决的问题就是直接或间接的范围内部数据
    ## 函数可以构成闭包,解决的问题就是外部可以访问函数内部的数据 
     1. 函数内部的数据直接return 是可以访问到函数内部的数据的,但是该数据不能第二次访问,
    因为第二次访问的时候又要调用一个函数,表示会有一个新的数据出来
    3. 在函数内部的数据,不能直接被函数外部访问,所以在函数内部定义一个函数,那么这个内部函数是可以直接被访问的(即访问闭包中的数据)
    4. 0 级俩无法访问1级链中的数据,所以可以通过操作2级链来访问1级链的数据
    # 闭包的基本结构
    1. 一般闭包的问题就是要使用访问间接的获取函数内部数据的使用权:有2个基本使用模型
    * 写一个函数,函数内部定义一个新函数,返回这个新函数,利用函数获取内部的数据
    * 写一个函数,函数内部定义一个对象,对象中绑定多个函数,返回对象,利用对象的方法访问函数内部的数据
    # 闭包的基本用法
    1 . 闭包是为了实现具有私有访问空间的函数
    2. 带有私有访问数据的对象
    * 私有数据,就是值有函数内部可以访问的数据,或对象内部的方法可以访问的数据
    3. 带有私有数据的函数
    # 闭包的性能问题
     1. 函数执行需要内存,那么函数定义的变量,会在函数执行结束后自动回收(即垃圾回收),凡是因为闭包被引出的数据,如果还有变量在引用,这些数据就不会被回收。,
    2. 引出使用闭包的时候,如果不使用某一些数据了,一定要给他赋值一个NULL(IE浏览器一定要写)
    3. 函数运行需要内存,函数运行结束,内存回收
    4. 闭包中的数据被外界访问后,函数执行结束后不能将其回收,如果闭包过过,会造成
    内存泄露(即闭包中的数据被访问后不会被回收,如果闭包过多,数据一致堆叠在内存中,会找出内存泄露)(所以有一些数据不在使用的时候,如果有变量还在引用这个数据,就把这个变量赋值为空)
    # 什么是递归
    1 . 在程序中,递归就是函数直接或间接的调用自己
    2. 递归而言最重要的就是跳出结构,跳出了才会有结果(一般通过判断条件跳出)
    # 所谓的递归就是化归思想
    下面可以不答
    (1. 递归的调用,写递归函数,最终还是包要转换为自己这个函数
    2. 递归思想就是将一个问题转换为一个已解决的问题来实现)
    # 什么是函数函数声明,什么是函数表达式
    1. 函数声明function foo(){}
     * 会提升 在函数声明之前也可以调用
    * 不能写在逻辑块,语句,表达式中间
    * 必须保证函数声明代码上面或下面不是一个逻辑体
    * 可以声明函数的位置:全局作用域,函数中
    2. 函数表达式 var foo = function(){}
    * 使用运算符可以将函数转换成表达式(function(){})!function(){}在前面加运算符,所有非空对象,转换成boolean值都是真
    * 放在if while fo do while ...的中间
    * 表达式是一个赋值语句,所以foo作为变量名可以提升,但是函数不会提升,不能在函数前面调用,至于你说赋值后调用
    #什么是原型(神秘对象就是函数.prototype)
    1. 原型能存储一些方法,构造函数创建的对象能够访问这些方法,原型能实现继承
    2. 在创建一个函数时候,会同时创建一个特殊的神秘对象,该对象使用函数.prototype引用,称其为函数的原型属性
    3. 创建出来的神秘对象针对于构造函数,称为构造函数的原型属性
    4. 创建出来的神秘对象针对于构造函数创建出来的实例对象,称为构造函数的原型对象
    5. 构造函数创建的实例对象直接'含有'神秘对象的方法,即原型继承
    6. 实例对象在调用当前对象的属性和方法的时候,如果当前对象中没有这些属性和方法,那么就会到原型对象中去找
    # __proto__
    * 以前要访问原型,必须使用构造函数来实现,无法直接使用实例对象来访问原型
    * 火狐最早引入属性'__proto__'表示使用实例对象引用原型,但是早期是非标准的
    * 通过该属性可以允许使用实例对象直接访问原型
    * 可以使用实例对象.__proto__也可以直接访问神秘对象
    * 实例对象.__proto__  == 构造函数.prototype
    # 什么对象的结构
    1. 神秘对象中默认都有一个熟悉'constructor',翻译为构造器,表示该原型是与什么构造函数联系起来的。
    2. '__proto__'有什么用?
    * 可以访问原型
    * 在开发中除非特殊要求,不要使用实例去修改原型的成员,因此该属性开发时使用较少
    * 但是在调试的过程中会非常方便,可以轻易的访问原型进行查看成员
    3. 在早期的浏览器中使用实例需要访问原型如何处理?
    * 可以使用实例对象访问构造器,然后使用构造器访问原型
    o.constructor.prototype
    4. 如果给实例继承自原型的属性赋值
    * 会给自己添加属性 不会改变原型中的属性
    * 如果访问数据,当前对象中如果没有该数据就到构造函数的原型属性中去找
     # 继承
    1 . 最简单的继承就是 将别的对象的属性强加在当前对象的上面,那么当前对象就有这个成员了
    2. 利用原型也可以实现继承,不需要在当前对象身上添加任何成员,只要原型有了,当前对象就有了
    3. 将属性,方法等成员利用混入的方式,加到构造函数的原型上,那么构造函数的实例就具有属性,和方法了
    ##混合式继承赋值描述
    ##使用点语法给原型添加成员,与使用直接替换修改原型对象有什么区别?
    1. 原型指向发生了变化
    2. 构造函数所创建的对象所继承的原型不同
    3. 新增的对象默认是没有constructor属性
    注意: 在使用替换的方式修改原型的时候,一般会添加constructor属性
    4. 构造函数在调用的时候,根据不同的参数创建不同的对象
    * $()使用
    * 可以放入字符串:转换成html字符串,也可以作为选择器
    * dom:包装成jq对象
    * jq对象:便于操作
    5. 有时候根据需要在构造函数的内部还会调用构造函数
    * 为了在构造函数内部通过constructor创建对象
    6. 在这种情况下不要使用构造函数的名字,而要使用'this.constructor'
    #属性搜索原则
    1. 原型链
    2. 属性搜索原则
    * 所谓的属性搜索原则,就是对象在访问属性和方法的时候,首先在当前对象中查找
    * 如果当前对象中存在该属性或方法,停止查找,直接使用该属性与方法
    * 如果对象没有该成员,那么在其原型对象中查找
    * 如果原型对象含有该成员,那么停止查找,直接使用
    * 如果原型还没有,就到原型的原型中查找
    * 如此往复,指导找到Object.prototype还没有 就返回undefined
    * 如果是调用方法就报错,该方法不是一个函数
    # 原型的概念
    1. 关于面向对象的概念
    * 类 class:在js中就是构造函数
             * 在传统的面向对象语言中,使用一个叫做类的东西定义模板,然后使用模板创建对象
             * 在构造方法中也具有类似的功能,因此称其为类
    * 实例(instance)与对象(Object)
             * 实例一般是指某一个构造函数创建出来的对象,我就称为某构造函数的实例
             * 实例就是对象,对象是一个泛称
             * 实例与对象是一个近义词
    * 键值对与属性和方法
             * 在js中键值对的集合称为对象
             * 如果值为数据(非函数),就称该键值对为属性
             * 如果值为函数(方法),就成该键值对为方法
    * 父类与子类
             * 传统的面向对象语言中使用类来实现继承,那么就有父类,子类的概念
             * 父类又称为基类,子类又称为派生类
             * 在js中常常称为父对象 子对象 即基对象  派生对象
    2. 原型相关的概念
    * 神秘对象针对构造函数称为 “原型属性"  (神秘对象与构造函数的关系)
             * 神秘对象就是构造函数的原型属性
             * 简称原型
    * 神秘对象与构造函数所创建出来的对象也有一定关系 (神秘对象与构造函数创建的对象的关系)
               * 关系是什么
                     * 在该对象访问某一个方法或属性的时候,如果该对象中没有,就会到这个神秘对象中查找
               * 神秘对象针对构造函数创建出来的对象称为原型对象
               * 简称原型
    * 对象继承自其原型(什么是原型继承)
               * 构造函数创建的对象继承自构造函数的原型属性
               * 构造函数创建的对象 继承自该对象的原型对象
               * 构成函数所创建出来的对象,与构造函数的原型属性表示的对象,是两个不同的对象
                      * 原型中的成员(无论方法和属性),可以直接被实例对象所使用 
                      * 也就是说实例对象直接'含有' 原型中的成员
                      * 因此实例对象继承自原型
                      * 这样的继承就是‘原型继承
     
     
    ## JS的对象比较
    由于js是解释执行的语言,那么在代码中出现函数与对象如果重复执行,会创建多个副本
    1. 由于js是解释执行的语言,
    4. 传统的构造方法的定义方式会影响性能,容易造成多个对象有多个方法副本,应该将方法单独抽取出来。
    5.可以考虑将方法全部放到外面,但是有安全隐患
    * 在开发中会引入多个框架或库,自定义成员越多,出现命名冲突的几率越大
    * 可能在开发中会有多个构造函数,每一个构造函数应该有多个方法,那么就hi变得不容易维护
    6. 任意一个对象都会默认的链接到它的原型中
    * 创建一个函数,会附带的创建一个特殊的对象,该对象使用函数.prototype引用,称其为函数的原型属性
    * 每一个由该函数作为构造函数创建的对象,都会默认的链接到该对象上
    * 在该对象访问某一个方法或属性的时候,如果该对象中没有,就会到这个神秘对象中查找
    * 如果访问数据,当前对象中如果没有该数据就到构造函数的原型属性中去找
    * 如果写数据,当对象中有该数据的时候,就是修改值。如果对象没有该数据,那么就添加值
       #对象的原型链
    1. 凡是对象就有原型
    2. 原型也是对象
    3. 凡是对象向就有原型,原型又是对象,因此凡是给定义一个对象,那么就可以找到他的原型,原型还有原型,那么如此下去,就构成一个对象的序列,称该结构为原型链
    #原型链结构
    1. 凡是使用构造函数,创建出对象,并且没有利用赋值的方式修改原型,就说该对象保留默认的原型链
    2.默认原型链的机构
    当前对象 →构造函数.prototype→Object.prototype→null
    3. 实现继承的时候,有时会利用替换原型链结构的方式实现原型继承,那么原型链结构就会发生改变
    #原型式继承
    1. 所谓的原型式继承就是利用修改原型链的结构(增加一个节点,删除一个节点,修改节点中的成员)来使得实例对象可以使用整条原型链中的所有成员
    2. 使用规则必须满足属性搜索原则
    #函数的构造函数Function
    1. 在js中使用Function可以实例化函数对象,在js中函数与普通对象一个也是一个对象类型,函数是js中的一等公民
    2. 函数是对象,就可以使用对象的动态特性
    3. 函数是对象,就有构造函数创建函数
    4. 函数是函数,可以创建其他对象
    5. 函数是唯一可以限定变量作用域的结构
     
    ##函数Function的实例
     new Function();
    1. Function中的参数全是字符串
    2. 该构造函数的作用是将参数链接起来组成函数
    * 如果参数只有一个,那么表示函数体
    * 如果参数有多个,那么最后一个参数表示新函数体,前面的所有参数表示函数的新参数
    * 如果没有参数,表示创建一个空函数
    #arguments对象 argument(参数) 
    1. arguments是一个伪数组对象,表示在函数调用的过程中传入的所有参数的集合
    * 在函数调用的过程中没有规定参数的个数与类型,因此函数调用就具有灵活的特性,那么为了方便使用,
    * 在每一个函数调用的过称重,函数代码体内有一个默认的对象arguments,它存储着实际传入的所有参数
    * 在代码设计中,如果需要函数带有任意个参数的时候,一般就不带任何参数,所有的参数利用arguments来获取
    2. js中函数并没有规定必须如何传参,定义函数的不写参数一样可以调用时传递参数
    3. 定义的时候写了参数,调用的时候也可以不传参
    4. 定义的时候写了一个参数,调用的时候可以随意的传递多个参数 
    #this 指向
    . 在js中使用Function可以实例化函数对象,在js中函数与普通对象一个也是一个对象类型,函数是js中的一等公民
    2. 函数是对象,就可以使用对象的动态特性
    3. 函数是对象,就有构造函数创建函数
    4. 函数是函数,可以创建其他对象
    5. 函数是唯一可以限定变量作用域的结构
    #函数的原型链
    1. 任意一个函数,都是相当于Function的实例 类似于{}与new Object()的关系
    2. 函数的当成对象的时候,他的属性为__proto__
    3. 函数的构造函数是什么?Function
    4. 函数应该继承自'Function.prototype'
    5. Function.prototype 继承自 Object.prototype
    6. Object函数是大写Function的实例
    7. Object作为对象 是继承自Function.prototype的,Function.prototype继承自Object.prototype
    8.Function是自己的构造函数
    #对象原型
    1. 在js中任何对象的源点就是Object.prototype
    2. 在js中任何函数的源点就是Function.prototype
  • 相关阅读:
    并发队列、线程池、锁
    JVM、垃圾收集器
    Socket网络编程
    Netty入门
    SpringCloud微服务负载均衡与网关
    Android监听耳机按键事件
    利用本地不同磁盘文件夹作为git远程仓库进行灾备
    chrome浏览器form中button每点击一次,form就会提交一次
    [企业路由器] 一对一NAT映射设置指导
    win7镜像自带IE9的卸载
  • 原文地址:https://www.cnblogs.com/lcf1314/p/11820953.html
Copyright © 2020-2023  润新知