原型链与闭包笔记

函数的prototype属性

  • 每个函数都有一个prototype,它默认指向一个Object空对象(即称为:原型对象)
  • 原型对象中有一个属性constructor,它指向函数对象
  • 给原型对象添加属性(一般都是方法)
  • 作用:函数的所有实例对象自动拥有原型中的属性(方法)

显示原型与隐式原型

  • 每个函数function都有一个prototype,即显示原型
  • 每个实例对象都有一个__proto__,可称为隐式原型
  • 对象的隐式原型的值为其对应构造函数的显示原型的值
  • 总结:
    • 函数的prototype属性:在定义函数时自动添加的,默认值是一个空的Object对象
    • 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
    • 程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)

原型链

  • 函数的显示原型链指向的对象默认是空object实例对象(但object不满足)
  • 所有函数都是Function的实例(包含Function)
  • object的原型对象是原型链尽头
    在这里插入图片描述
    在这里插入图片描述

原型链属性的问题

  • 读取对象的属性值时:会自动到原型链中查找
  • 设置对象的属性值时:不会查找原型链,如果当目前对象中没有此属性,直接添加此属性并设置其值
  • 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn(){

}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a,fn1)
var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn2.a,fn2)

在这里插入图片描述

function Person(name,age){
   this.name = name
   this.age = age
 }
 Person.prototype.setName = function (name){
   this.name = name
 }
 var p1 = new Person('Tom', 12)
 p1.setName('Annie')
 console.log(p1)
 var p2 = new Person('Jack',18)
 p2.setName('Haili')
 console.log(p2)
 console.log(p1.__proto__ === p2.__proto__)			//true

在这里插入图片描述

instanceof用法

  • instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上

简单面试题

  • 测试题1
var A = function(){

}
A.prototype.n = 1

var b = new A()
A.prototype = {
  n: 2,
  m: 3
}
var c = new A()
console.log(b.n,b.m,c.n,c.m) // 1 undefined 2 3
  • 测试题2
function F(){}
Object.prototype.a = function(){
  console.log('a()')
}
Function.prototype.b = function(){
  console.log('b()')
}
var f = new F()
f.a()	//a()
f.b()	//报错
F.a()	//a()
F.b()	//b()

作用域与执行上下文

  • 区别1
    • 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定,而不是在函数调用是
    • 全局执行上下文环境实在全局确定之后,js代码马上执行之前创建
    • 函数执行上下文是在调用函数时,函数体代码执行之前创建
  • 区别2
    • 作用域是静态的,只要函数定义好了就一直存在,且不会再变化
    • 执行上下文是动态的,调用函数时创建,函数调用结束时上下文环境就会被释放
  • 联系
    • 上下文环境(对象)是从属于所在的作用域
    • 全局上下文环境==>全局作用域
    • 函数上下文环境==>对应的函数使用域

闭包

  • 如何产生闭包?
    • 当一个嵌套的内部(子)函数应用看嵌套的外部(父)函数的变量(函数)时,就产生了闭包
  • 闭包到底是什么?
    • 使用chrome调试查看
    • 理解1:闭包是嵌套的内部函数(绝大部分人)
    • 理解2:包含被应用变量(函数)的对象(绝少数人)
    • 注意:闭包存在于嵌套的内部函数中
  • 产生闭包的条件?
    • 函数嵌套
    • 内部函数应用了外部函数的数据(变量/函数)
  • 闭包的作用
    • 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
    • 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
  • 问题:
    • 函数执行外后,函数内部生命的局部变量是否存在?一般是不存在,存在于闭包中的变量才可能存在
    • 在函数外部能直接访问函数内部变量吗?不能,但我们可以通过闭包让外部操作它

闭包的生命周期

  • 产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
  • 死亡:在嵌套的内部函数成为垃圾对象时
function fn1(){
 //此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
 var a = 2
  function fn2(){
    a++
    console.log(a)
  }
  return fn2
}

var f = fn1()
f()
f()
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)

闭包缺点

  • 函数执行后,函数内的局部变量没有释放,占用内存时间变长
  • 容易造成内存泄漏
  • 解决:
    • 能不用闭包就不用
    • 及时释放

闭包面试题

function fun(n,o){
   console.log(o)
   return {
     fun: function(m){
       return fun(m,n)
     }
   }
 }
 var a = fun(0)
 a.fun(1)
 a.fun(2)
 a.fun(3)  //undefined,0,0,0

 var b = fun(0).fun(1).fun(2).fun(3) //undefined,0,1,2
 var c = fun(0).fun(1)
 c.fun(2)
 c.fun(3)  //undefined,0,1,1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值