详解JS的三座大山:作用域与闭包、原型与原型链、异步与单线程

js 作为前端的中坚力量。那么 javascript 三座大山,你知道是哪些呢?

详解JS的三座大山:作用域与闭包、原型与原型链、异步与单线程

1️⃣ 作用域和闭包

作用域 指代码当前上下文,控制着变量和函数的可见性和生命周期。最大的作用是隔离变量,不同作用域下同名变量不会冲突。

作用域链 指如果在当前作用域中没有查到值,就会向上级作用域查询,直到全局作用域,这样一个查找过程所形成的链条就被称之为作用域链。【推荐学习:javascript视频教程】

作用域可以堆叠成层次结构,子作用域可以访问父作用域,反之则不行。

作用域具体可细分为四种:全局作用域模块作用域函数作用域块级作用域

全局作用域: 代码在程序的任何地方都能被访问,例如 window 对象。但全局变量会污染全局命名空间,容易引起命名冲突。

模块作用域: 早期 js 语法中没有模块的定义,因为最初的脚本小而简单。后来随着脚本越来越复杂,就出现了模块化方案(AMD、CommonJS、UMD、ES6模块等)。通常一个模块就是一个文件或者一段脚本,而这个模块拥有自己独立的作用域。

函数作用域: 顾名思义由函数创建的作用域。闭包就是在该作用域下产生,后面我们会单独介绍。

块级作用域: 由于 js 变量提升存在变量覆盖、变量污染等设计缺陷,所以 ES6 引入了块级作用域关键字来解决这些问题。典型的案例就是 let 的 for 循环和 var 的 for 循环。

// var demofor(var i=0; i

了解完作用域再来谈谈 闭包: 函数A里包含了函数B,而函数B使用了函数A的变量,那么函数B被称为闭包或者闭包就是能够读取函数A内部变量的函数。

可以看出闭包是函数作用域下的产物,闭包会随着外层函数的执行而被同时创建,它是一个函数以及其捆绑的周边环境状态的引用的组合。换而言之,闭包是内层函数对外层函数变量的不释放

闭包的特征:

登录后复制函数中存在函数;内部函数可以访问外层函数的作用域;参数和变量不会被 GC,始终驻留在内存中;有内存地方才有闭包。

所以使用闭包会消耗内存、不正当使用会造成内存溢出的问题,在退出函数之前,需要将不使用的局部变量全部删除。如果不是某些特定需求,在函数中创建函数是不明智的,闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

以下整理了闭包的应用场景:

// demo1 输出 3 3 3for(var i = 0; i 
/* 模拟私有方法 */// 模拟对象的get与set方法var Counter = (function() {var privateCounter = 0;function changeBy(val) {    privateCounter += val;}return {    increment: function() {    changeBy(1);    },    decrement: function() {    changeBy(-1);    },    value: function() {    return privateCounter;    }}})();console.log(Counter.value()); /* logs 0 */Counter.increment();Counter.increment();console.log(Counter.value()); /* logs 2 */Counter.decrement();console.log(Counter.value()); /* logs 1 */

登录后复制

/* setTimeout中使用 */// setTimeout(fn, number): fn 是不能带参数的。使用闭包绑定一个上下文可以在闭包中获取这个上下文的数据。function func(param){ return function(){ alert(param) }}const f1 = func(1);setTimeout(f1,1000);

登录后复制

/* 生产者/消费者模型 */// 不使用闭包// 生产者function producer(){    const data = new(...)    return data}// 消费者function consumer(data){    // do consume...}const data = producer()// 使用闭包function process(){    var data = new (...)    return function consumer(){        // do consume data ...    }}const processer = process()processer()

登录后复制

/* 实现继承 */// 以下两种方式都可以实现继承,但是闭包方式每次构造器都会被调用且重新赋值一次所以,所以实现继承原型优于闭包// 闭包function MyObject(name, message) {  this.name = name.toString();  this.message = message.toString();  this.getName = function() {    return this.name;  };  this.getMessage = function() {    return this.message;  };}// 原型function MyObject(name, message) {  this.name = name.toString();  this.message = message.toString();}MyObject.prototype.getName = function() {  return this.name;};MyObject.prototype.getMessage = function() {  return this.message;};

登录后复制

对于闭包的概念好像懂了但又好像缺少了啥?意犹未尽。我也曾也闭包中迷失,但是看完闭包的生命周期让我重新找回自己。

一张图看懂闭包的生命周期

学完就来一波牛刀小试

function test(a, b){  console.log(b);  return {    test: function(c) {      return test(c,a);    }  }}var a = test(100);a.test(101);a.test(102);var b = test(200).test(201).test(202);var c = test(300).test(301);c.test(302);// undefined  100  100// undefined  200 201// undefined  300 301

登录后复制

2️⃣ 原型和原型链

有对象的地方就有 原型,每个对象都会在其内部初始化一个属性,就是prototype(原型),原型中存储共享的属性和方法。当我们访问一个对象的属性时,js引擎会先看当前对象中是否有这个属性,如果没有的就会查找他的prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。这么一个寻找的过程就形成了 原型链 的概念。

理解原型最关键的是理清楚__proto__、prototype、constructor三者的关系,我们先看看几个概念:

__proto__属性在所有对象中都存在,指向其构造函数的prototype对象;prototype对象只存在(构造)函数中,用于存储共享属性和方法;constructor属性只存在于(构造)函数的prototype中,指向(构造)函数本身。一个对象或者构造函数中的隐式原型__proto__的属性值指向其构造函数的显式原型 prototype 属性值,关系表示为:instance.__proto__ === instance.constructor.prototype除了 Object,所有对象或构造函数的 prototype 均继承自 Object.prototype,原型链的顶层指向 null:Object.prototype.__proto__ === nullObject.prototype 中也有 constructor:Object.prototype.constructor === Object构造函数创建的对象(Object、Function、Array、普通对象等)都是 Function 的实例,它们的 __proto__ 均指向 Function.prototype。

看起来是不是有点乱??别慌!!一张图帮你整理它们之间的关系

原型关系图

相同的配方再来一刀

const arr = [1, 2, 3];arr.__proto__ === Array.prototype; // truearr.__proto__.__proto__ === Object.prototype; // trueArray.__proto__ === Function.prototype; // true

登录后复制

3️⃣ 异步和单线程

JavaScript 是 单线程 语言,意味着只有单独的一个调用栈,同一时间只能处理一个任务或一段代码。队列、堆、栈、事件循环构成了 js 的并发模型,事件循环 是 JavaScript 的执行机制。

为什么js是一门单线程语言呢?最初设计JS是用来在浏览器验证表单以及操控DOM元素,为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程。

既然是单线程也就意味着不存在异步,只能自上而下执行,如果代码阻塞只能一直等下去,这样导致很差的用户体验,所以事件循环的出现让 js 拥有异步的能力。

事件循环链路图

更多编程相关知识,请访问:编程教学!!

以上就是详解JS的三座大山:作用域与闭包、原型与原型链、异步与单线程的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2695669.html

(0)
上一篇 2025年3月7日 18:23:45
下一篇 2025年2月25日 06:25:46

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 总结20个常见的JavaScript数组操作

    javascript中的array对象与其他编程语言中的数组一样,是一组数据的集合。在javascript中,数组里面的数据可以是不同类型的,并具有用于执行数组常见操作的方法。 声明数组 有三种不同的声明方式 1. 常规方式 const h…

    编程技术 2025年3月7日
    200
  • 一文浅析Node中的TCP和UDP

    Node 是一个面向网络而生的平台,它具有事件驱动、无阻塞、单线程等特性,具备良好的可伸缩性,使得它十分轻量,适合在分布式网络中扮演各种各样的角色。 Node 提供了 net、dgram、http、http2、https 等模块,分别用于处…

    2025年3月7日 编程技术
    200
  • 深入理解React的自定义Hook

    在 React 项目中,我们经常会使用到 React 自带的几个内置 Hooks,如 useState,useContext 和useEffect。但有时,我们可能希望有一个特定目的的 Hook :例如获取数据 useData,获取连接 u…

    2025年3月7日
    200
  • 一文详解JavaScript中的闭包

    javascript 闭包是一种重要的概念,在 javascript 编程中被广泛使用。尽管它可能会让初学者感到困惑,但它是理解 javascript 语言核心的关键概念之一。本文将深入探讨 javascript 闭包,让你了解它是如何工作…

    2025年3月7日
    200
  • 深入了解Node中的Buffer

    在 Stream 篇结中,我们留下了一个问题,下述代码输出的 chunk 是一个什么东西? 通过打印,我们发现 chunk 是 Buffer 对象,其中的元素是16进制的两位数,即0~255的数值。【相关教程推荐:nodejs视频教程、编程…

    2025年3月7日 编程技术
    200
  • 一文理解JavaScript中的单例模式

    js 单例模式是一种常用的设计模式,它可以保证一个类只有一个实例。这种模式主要用于管理全局变量,避免命名冲突和重复加载,同时也可以减少内存占用,提高代码的可维护性和可扩展性。 价值场景 JS 单例模式通常适用于以下场景: 管理全局变量 使用…

    2025年3月7日
    200
  • 一文聊聊Node中的内存控制

    基于无阻塞、事件驱动建立的node服务,具有内存消耗低的优点,非常适合处理海量的网络请求。在海量请求的前提下,就需要考虑“内存控制”的相关问题了。 1. V8的垃圾回收机制与内存限制 Js由垃圾回收机制来进行自动内存管理,开发者不需要像其它…

    2025年3月7日 编程技术
    200
  • 【整理分享】7个热门的React状态管理工具

    最近在做项目技术栈整理工作; 由于团队越来越大、人员增多、项目增多; 统一技术栈是一件非常有必要的事; React 状态管理工具有很多,但是选择一个合适的状态管理工具其实很重要; 今天跟大家分享一下我整理的几个非常热门的 React状态管理…

    2025年3月7日 编程技术
    200
  • 在JavaScript中实现智能金融和智慧政务的应用场景

    随着现代社会的不断发展,金融和政务的重要性越来越凸显。然而,传统的金融和政务服务方式已经无法满足人们的需求,迫切需要一种智能、高效、安全的解决方案。在这一背景下,javascript作为一种易于学习、运用广泛的编程语言,具有较广泛的应用前景…

    编程技术 2025年3月7日
    200
  • 如何使用JavaScript实现游戏开发和虚拟社交网络

    随着互联网的普及和技术的不断进步,游戏和虚拟社交网络的需求越来越大。在这个时代,javascript成为了游戏开发和虚拟社交网络开发中必备的技术之一。那么,如何使用javascript实现游戏开发和虚拟社交网络呢?本文将详细介绍。 一、游戏…

    编程技术 2025年3月7日
    200

发表回复

登录后才能评论