JS函数高级:原型,执行上下文,作用域与闭包

函数高级

原型

1.原型:
(1)函数的prototype属性(图)
每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
原型对象中有一个属性constructor,它指向函数对象
(2)给原型对象添加属性(一般都是方法)
作用:函数的所有实例对象自动拥有原型中的属性(方法)
2.显示原型与隐式原型
(1)每个函数function都有一个prototype,即显示原型(属性)
(2)每个实例对象都有一个__proto__,称为隐式原型(属性)
(3)对象的隐式原型的值为其对应构造函数的显示原型的值
(4)内存结构(图)
在这里插入图片描述

(5)总结:
函数的prototype属性:在定义函数时自动添加的,默认值是一个空的object对象
对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)
3.原型链
(1) 原型链(图解)
在这里插入图片描述

访问一个对象的属性时,先在自身属性中查找,找到返回
若没有,再沿着__proto__这条链向上查找,找到返回
若最终没有找到,则返回undefined
别名:隐式原型链
作用:查找对象的属性(方法)
(2) 函数的显示原型指向对象默认是空object实例对象(但object不满足)
所有函数都是Function的实例(包含Function)
Object的原型对象是原型链的尽头
(3)构造函数/原型/实体对象的关系(图解)
在这里插入图片描述

(4)构造函数/原型/实体对象的关系2(图解)
在这里插入图片描述

4.原型链的属性问题
(1)读取属性的属性值时,会自动到原型链中查找
(2)设置对象的属性值时,不会查找原型链,如果当前对象没有此属性,直接添加此属性并设置其值
(3)方法一般定义在原型中,属性一般通过构造函数定义在对象本身上。
5.instanceof
(1)instanceof是如何判断的?
表达式:A instanceof B
A是实例对象,有隐式原型属性,能看见原型上面的方法
B是构造函数,有显示原型属性
如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
(2)unction是通过new自己产生的实例

1.执行上下文与执行上下文栈
(1) 变量声明提升
通过var定义(声明)的变量,在定义语句之前就可以访问到
值:undefined
(2)函数声明提升
通过function声明的函数,在之前就可以直接调用
值:函数定义(对象)
(3)变量提升和函数提升是如何产生的

面试题:输出undefined
var a = 3
function fn(){
console.log(a)
//声明未赋值,相当于var a; console.log(a)

			var a = 4
		}
		fn()

2.执行上下文,只能有一个
(1).代码分类(位置)
全局代码
函数(局部)代码
(2)全局执行上下文
在执行全局代码前window确定为全局执行上下文
对全局数据进行预处理
var定义的全局变量==>undefined,添加window属性
function声明的全局函数==>赋值(fun),添加为window的方法
this==>赋值(window)
开始执行全局代码
(3)函数执行上下文
在调用函数前,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在与栈中)
对局部数据进行预处理
形参变量==>赋值(实参)>添加为执行上下文的属性
arguments
>赋值(实参列表),添加为执行上下文的属性
var定义的局部变量==>undefined,添加为执行上下文的属性
function声明的函数==>赋值(fun),添加为执行上下文的方法
this==>赋值(调用函数的对象)
开始执行函数体代码
3.执行上下文栈
(1)在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
(2)在全局执行上下文(window)确定后,将其添加到栈中(压栈)
(3)在函数执行上下文创建后,将其添加到栈中(压栈)
(4)在当前函数执行完以后,将栈顶的对象移除(出栈)
(5)当所有的代码执行完以后,栈中只剩下window

作用域与作用域链
1.作用域
在这里插入图片描述

(1)理解
就是一块"地盘", 一个代码段所在的区域
它是静态的(相对于上下文对象), 在编写代码时就确定了
(2)分类
全局作用域
函数作用域
没有块作用域(ES6有了)
(3)作用
隔离变量,不同作用域下同名变量不会有冲突
2.作用域与执行上下文
区别
(1)全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时。
全局执行上下文环境是在全局作用域确定之后,JS代码马上执行之前创建
函数执行上下文是在调用函数时,函数体代码执行之前创建
(2)作用域是静态的,只要函数定义好了就一直存在,且不会再变化
执行上下文是动态的。调用函数时创建,函数调用结束时就会自动释放
联系:
上下文环境(对象)是从属于所在的作用域
全局上下文环境==>全局作用域
函数上下文环境==>对应的函数使用域
在这里插入图片描述

3.作用域链
在这里插入图片描述

(1) 理解
多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
查找变量时就是沿着作用域链来查找的
(2) 查找一个变量的查找规则
在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
4.
(1)如何产生闭包?
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的,就产生了闭包
(2)什么是闭包?
使用chrome调试查看
理解一:闭包是嵌套的内部函数(绝大部分人)
理解二:包含被引用变量(函数)的对象(极少数人)
注意:闭包存在于嵌套的内部函数中
(3)产生闭包的条件?
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
5.闭包
(1)将函数作为另一个函数的返回值
(2)将函数作为实参传递给另一个函数调用
6.闭包
(1)使内部函数的变量在函数执行后,仍然存活在内存中(延长了局部变量的生命周期)
(2)让函数外部可以操作(读写)到函数内部的数据(变量/函数)
7. 闭包的生命周期:
(1)产生:在嵌套内部函数定义执行完时就产生了(不是调用)
(2)死亡:在嵌套的内部函数称为垃圾对象时
8.闭包的应用:定义JS模块
具有特定功能的js模块
将所有的数据和功能封装在一个函数内部(私有的)
只向外暴露一个包含n个方法的对象或函数
模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
9.闭包的缺点及解决方法
缺点:
函数执行完以后,函数内的局部变量没有释放,占有内存时间变长
容易造成内存泄漏
解决:
尽量不用闭包
及时释放
10.
内存溢出:
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就出现抛出内存溢出的错误
内存泄漏:
占用的内存没有及时释放
内存泄漏积累多了就容易导致内存溢出
常见的内存泄漏:
意外的全局变量
没有及时清理的计算器或回调函数
闭包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值