likes
comments
collection
share

【大白话】说JS的实际应用之闭包,原型&原型链

作者站长头像
站长
· 阅读数 48

前言

大白话说JS内容包括:DOM的一些操作,Promise相关, 微任务宏任务,作用域,变量提升,闭包,变量类型,深浅拷贝,原型和作用域链,后续争取把js重点都记录上,深入浅出。

作用域,变量提升,和闭包

关于作用域,有全局和局部(函数作用域,块级作用域ES6才有),局部能访问全局,全局不能访问局部。在查找变量的时候,变量的父子级关系就是一条作用域链。找同名变量优先局部,注意this引用

变量提升,这得多看几道作用域输出变量的题(下面这张我是去牛客网刷js专项训练截来的) 【大白话】说JS的实际应用之闭包,原型&原型链闭包和匿名函数不要搞混!那么什么是闭包,红宝书说:闭包是有权访问另一个函数作用域的变量函数。也就是说,局部之间并非是不能互相访问的,局部也可以通过闭包访问局部的变量。下面举俩个小例子:

// 函数作为返回值,在定义的地方向上找变量,而不是再调用的地方
function test1 () {
  const a = 1;
  return function () {
    console.log('a', a);  //输出:a 1
  }
}
const a1 = test1();
const a = 2;
a1();

// 函数作为参数
function test2 (fn) {
  const b = 6;
  fn();
}

const b = 7;
function fn () {
  console.log('b', b); //输出:b 7
}
test2(fn);

为什么要使用闭包: 因为正常情况下,函数执行完存储在内存的变量会被销毁,再次调用该函数时重新计算。假设这函数计算量大且耗时,如果每次调用都重新计算,那影响用户体验,这时就需要道闭包。他可以不释放外部的引用,将第一次计算的结果缓存到本地方便下次调用直接拿取。

闭包的弊端:由于闭包的变量被保存在内存中,所以内存消耗很大,容易导致内存泄漏;容易改变父函数内部变量的值。

原型:每一个对象都会从原型继承属性或方法

官话:每一个JavaScript对象在创建的时候就会预制管理另一个对象,这个对象就是我们所说的原型。 大白话: 构造函数内部有个prototype 属性,通过这个属性能访问到原型,这里的原型就是指构造函数.prototype 。 前面也说了,原型是预制管理一个对象,那么那个对象是谁呢?其实是构造函数new出来的实例对象,好了,现在有三个角色:构造函数,原型,实例。

它们是怎么联系的呢?官方设定,实例不能直接访问构造函数,要不设计原型干嘛。

function Person() {
}
Person.prototype.name="南"
const nan = new Person();
console.log(nan.name); //南
console.log(nan instanceof Person);//True
console.log(nan.__proto__ === Person.prototype);//True 实例通过__proto__访问原型
console.log(nan.__proto__.constructor === Person);//True 实例通过__proto__访问原型后在通过constructor 访问构造函数
console.log(Person.prototype.constructor === Person);//True 原型通过constructor 访问构造函数

【大白话】说JS的实际应用之闭包,原型&原型链

说的再多不如结合图看遍代码。

构造函数通过原型的方式添加属性,成功调用实例,说明1.实例确实是通过原型访问到构造函数的属性或方法的。2.通过new 出来的实例可以继承原型方法,instanceof 足以说明两者关系。

现在,你知道上述基础类型判断里的instanceof constructor 为什么能判断对象类型了吧,还是因为原型!

清楚了原型和实例的关系后,更能透彻理解 new 实例化的过程中发生了什么,具体可见我的js复习下篇。

原型链:

每个对象都有属于自己的隐式原型 __proto__,每个函数或方法都有自己的显示原型 prototype 。实例对象继承使用原型方法的时候通过隐式原型向上查找,如果在原型的显示原型中找到,就不用在通过原型的隐式原型再向上找。

这么说有点拗口,其实蛮好理解的。下面通过一张图说明:

【大白话】说JS的实际应用之闭包,原型&原型链 【大白话】说JS的实际应用之闭包,原型&原型链

如图所示,实例 teacher 要想调用 teach 方法,首先通过显示原型查找有没有 teach 这个方法,发现没有就通过 _proto_ 隐式原型查找他的上一级原型(Teacher.prototype),看他有没有。Teacher同样先看自己的显示原型,发现有就返回。同理,如果要找 drink 方法,则还要通过 _proto_ 再向上找原型(Person.prototype)看他有没有,找到就层层返回。

【大白话】说JS的实际应用之闭包,原型&原型链

如果找到尽头都没有那个方法,就回返回null。这样,一条完整的方法查找路径就是原型链。

转载自:https://juejin.cn/post/7130443276427444260
评论
请登录