什么是作用域, 什么事闭包, 什么事原型链

什么是作用域

作用域即作用范围,在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

原文地址:https://www.cnblogs.com/lcf1314/p/11820953.html

时间: 2025-01-19 21:29:48

什么是作用域, 什么事闭包, 什么事原型链的相关文章

作用域链、闭包和原型链

Function:  匿名函数,作用域,作用域链和闭包 函数的重载:  什么是:函数名相同,参数列表不同.根据传入函数的参数的不同,整形不同的逻辑. 何时用:如果一项任务,根据不同的参数,不执行不用的逻辑. 优点:减轻调用者的负担.  问题:js语法不知函数的重载. 解决办法:在函数中都有arguments的属性,专门用于接收传入函数的所有参数值的类数组对象. 匿名函数:  什么是:在函数定义时,不给函数名,即不被任何变量引用. 何时用:确定函数只使用一次.  优点:节约内存. 如何用:1.自调

闭包,原型链

闭包 在[函数定义]的时候,[函数对象]的[scope属性]便会引用包含该函数的上一级函数在运行时所生成的[执行上下文]的[活动对象],因为发生对象属性之间的相互依赖,导致包含此函数的[scope属性]所指向的活动变量,在上一级函数[执行完毕]将要[释放执行上下文]的时候[不能释放]其包含的[活动变量]. 自己的理解: 闭包的产生首先要有一个地址被引用所指向 函数与对象的关系 函数就是对象的一种 对象是函数创建的 prototype原型 prototype是函数的一个属性 每一个构造函数都有pr

闭包和原型链

闭包: 简单的理解就是:闭包就是能够读取其他函数内部变量的函数,它两个最大的用处:①可以读取函数内部的变量,②让变量的值始终保持在内存中.闭包与它的词法环境绑在一起,因此闭包让我们能够从一个函数内部访问其外部函数的作用域 . 原型链: 对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的 链条,称之为原型链. 原文地址:https://www.cnblogs.com/JankinLiu/p/10347293

L1 - 闭包和原型链

先来一炮尝尝: var i = 10; function myFunc(){ var i = 20; function innerFunc(){ alert(i); } return innerFunc; } var func = myFunc(); func(); 此栗为什么弹出20,而不是10?为什么定义在 myFunc 内部的 innerFunc 返回了以后,还能访问到 myFunc 内部的变量 i ? 这是因为在 innerFunc 返回了以后,仍然保留着函数运行的实例.执行环境和作用域

javascript原型链与作用域

现在校招也基本结束了,所以有时间把这段时间遇到的问题做个总结.在很多的笔试题目中,发现有很多对JS作用域方面的考察,所以查阅资料总结一下. 众所周知,js不像其他OOP语言那样,他是一种弱类型的语言,对数据类型没有很明显的区别.还有一点不同是它的作用域,引起这点不同主要是因为js的继承方式是通过原型链的方式来实现的. a)js没有块级作用域,所谓块级作用域即if,for,while(花括号括起来的部分)语句里面的部分.测试如下(Chrome浏览器). 下面为输出结果 从结果可以看出,js不存在块

JavaScript概念总结:作用域、闭包、对象与原型链

1 JavaScript变量作用域 1.1 函数作用域 没有块作用域:即作用域不是以{}包围的,其作用域完成由函数来决定,因而if /for等语句中的花括号不是独立的作用域. 如前述,JS的在函数中定义的局部变量只对这个函数内部可见,称之谓函数作用域. 嵌套作用域变量搜索规则:当在函数中引用一个变量时,JS会搜索当前函数作用域,如果没有找到则搜索其上层作用域,一直到全局作用域. [javascript] view plain copy print? var  value = 'global';

作用域、原型链、闭包等概念理解

1.执行环境及作用域 (1).执行环境: 定义了变量或函数有权访问的其它数据,决定了它们的各自行为.每个执行环境都有一个与之关联的变量对象(variable object, VO),执行环境中定义的所有变量和函数都会保存在这个对象中,解析器在处理数据的时候就会访问这个内部对象. 全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的.每个函数都有自己的执行环境,当执行流进入一个函数的时候,函数的环境会被

标识符解析、作用域链、运行期上下文、原型链、闭包

本文讲到的是如何从数据访问层面上提高JS 代码的执行效率.总的来讲有以下几条原则: 函数中读写局部变量总是最快的,而全局变量的读取则是最慢的: 尽可能地少用with 语句,因为它会增加with 语句以外的数据的访问代价: 闭包尽管强大,但不可滥用,否则会影响到执行速度以及内存: 嵌套的对象成员会明显影响性能,尽量少用: 避免多次访问对象成员或函数中的全局变量,尽量将它们赋值给局部变量以缓存. 这么几句话看似简单,但要深刻理解其中的道理则需涉及到JS的 标识符解析.作用域链.运行期上下文(又称为执

js-高级(原型与原型链、作用域与作用域链、闭包)

## 原型与原型链 * 所有函数都有一个特别的属性:   * `prototype` : 显式原型属性 * 所有实例对象都有一个特别的属性:   * `__proto__` : 隐式原型属性 * 显式原型与隐式原型的关系   * 函数的prototype: 定义函数时被自动赋值, 值默认为{}, 即用为原型对象   * 实例对象的__proto__: 在创建实例对象时被自动添加, 并赋值为构造函数的prototype值   * 原型对象即为当前实例对象的父对象 * 原型链   * 所有的实例对象