js는 프런트엔드의 백본 역할을 합니다. 그렇다면 자바스크립트의 3대 산이 무엇인지 아시나요?
범위
作用域
指代码当前上下文,控制着变量和函数的可见性和生命周期。最大的作用是隔离变量,不同作用域下同名变量不会冲突。
作用域链
指如果在当前作用域中没有查到值,就会向上级作用域查询,直到全局作用域,这样一个查找过程所形成的链条就被称之为作用域链。【推荐学习:javascript视频教程】
作用域可以堆叠成层次结构,子作用域可以访问父作用域,反之则不行。
作用域具体可细分为四种:全局作用域
、模块作用域
、函数作用域
、块级作用域
全局作用域: 代码在程序的任何地方都能被访问,例如 window 对象。但全局变量会污染全局命名空间,容易引起命名冲突。
模块作用域: 早期 js 语法中没有模块的定义,因为最初的脚本小而简单。后来随着脚本越来越复杂,就出现了模块化方案(AMD、CommonJS、UMD、ES6模块等)。通常一个模块就是一个文件或者一段脚本,而这个模块拥有自己独立的作用域。
函数作用域: 顾名思义由函数创建的作用域。闭包就是在该作用域下产生,后面我们会单独介绍。
块级作用域: 由于 js 变量提升存在变量覆盖、变量污染等设计缺陷,所以 ES6 引入了块级作用域关键字来解决这些问题。典型的案例就是 let 的 for 循环和 var 的 for 循环。
// var demo for(var i=0; i<10; i++) { console.log(i); } console.log(i); // 10 // let demo for(let i=0; i<10; i++) { console.log(i); } console.log(i); //ReferenceError:i is not defined
了解完作用域再来谈谈 闭包
: 函数A里包含了函数B,而函数B使用了函数A的变量,那么函数B被称为闭包或者闭包就是能够读取函数A内部变量的函数。
可以看出闭包是函数作用域下的产物,闭包会随着外层函数的执行而被同时创建,它是一个函数以及其捆绑的周边环境状态的引用的组合。换而言之,闭包是内层函数对外层函数变量的不释放。
闭包的特征:
所以使用闭包会消耗内存、不正当使用会造成内存溢出的问题,在退出函数之前,需要将不使用的局部变量全部删除。如果不是某些特定需求,在函数中创建函数是不明智的,闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
以下整理了闭包的应用场景:
// demo1 输出 3 3 3 for(var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } // demo2 输出 0 1 2 for(let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } // demo3 输出 0 1 2 for(let i = 0; i < 3; i++) { (function(i){ setTimeout(function() { console.log(i); }, 1000); })(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
有对象的地方就有 原型
,每个对象都会在其内部初始化一个属性,就是prototype(原型),原型中存储共享的属性和方法。当我们访问一个对象的属性时,js引擎会先看当前对象中是否有这个属性,如果没有的就会查找他的prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。这么一个寻找的过程就形成了 原型链
는 변수와 함수의 가시성과 수명 주기를 제어하는 코드의 현재 컨텍스트를 나타냅니다. 가장 큰 기능은 변수를 격리하여 다른 범위에서 동일한 이름을 가진 변수가 충돌하지 않도록 하는 것입니다.
Scope Chain
전역 범위
🎜, 🎜모듈 범위
🎜, 🎜함수 범위
🎜 , 🎜 블록 수준 범위
🎜🎜🎜🎜전역 범위: 🎜 코드는 창 개체 등 프로그램 내 어디에서나 액세스할 수 있습니다. 그러나 전역 변수는 전역 네임스페이스를 오염시키고 쉽게 이름 충돌을 일으킬 수 있습니다. 🎜🎜🎜모듈 범위: 🎜 원래 스크립트가 작고 단순했기 때문에 초기 js 구문에는 모듈 정의가 없었습니다. 나중에 스크립트가 점점 더 복잡해지면서 모듈식 솔루션(AMD, CommonJS, UMD, ES6 모듈 등)이 등장했습니다. 일반적으로 모듈은 파일이나 스크립트이며 이 모듈은 자체적인 독립적인 범위를 갖습니다. 🎜🎜🎜함수 범위:🎜 이름에서 알 수 있듯이 함수에 의해 생성된 범위입니다. 클로저는 이 범위에서 생성되며 나중에 별도로 소개하겠습니다. 🎜🎜🎜블록 수준 범위: 🎜 js 변수 승격에는 변수 적용 범위 및 변수 오염과 같은 설계 결함이 있으므로 ES6에서는 이러한 문제를 해결하기 위해 블록 수준 범위 키워드를 도입했습니다. 일반적인 경우는 let의 for 루프와 var의 for 루프입니다. 🎜const arr = [1, 2, 3]; arr.__proto__ === Array.prototype; // true arr.__proto__.__proto__ === Object.prototype; // true Array.__proto__ === Function.prototype; // true
클로저
:🎜 함수 A는 함수 B를 포함하고, 함수 B는 함수 A의 변수를 사용하며, 함수 B를 클로저 또는 클로저 A 패키지라고 합니다. 함수 A의 내부 변수를 읽을 수 있는 함수입니다. 🎜🎜클로저는 함수 범위의 산물임을 알 수 있습니다. 클로저는 외부 함수가 실행됨과 동시에 함수와 주변 환경 상태에 대한 번들 참조가 결합된 것입니다. 즉, 🎜 클로저는 외부 함수 변수를 해제 🎜 하지 않는 내부 함수입니다. 🎜🎜🎜클로저의 특징: 🎜🎜프로토타입이 있다</ code >🎜, 각 객체는 그 내부의 속성, 즉 프로토타입을 초기화하고 프로토타입은 공유 속성과 메서드를 저장합니다. 객체의 속성에 접근할 때, js 엔진은 먼저 현재 객체에 이 속성이 있는지 확인하고, 그렇지 않다면 해당 프로토타입 객체에 이 속성이 있는지 확인하며, Object 내장 객체가 검색될 때까지 계속됩니다. 이러한 검색 과정이 🎜<code>프로토타입 체인
🎜이라는 개념을 형성했습니다. 🎜🎜프로토타입을 이해하는 데 가장 중요한 것은 __proto__, 프로토타입 및 생성자 간의 관계를 명확히 하는 것입니다. 먼저 몇 가지 개념을 살펴보겠습니다. 🎜instance.__proto__ === instance.constructor.prototype
Object.prototype.__proto__ === null
Object.prototype.constructor === Object
看起来是不是有点乱??别慌!!一张图帮你整理它们之间的关系
相同的配方再来一刀
const arr = [1, 2, 3]; arr.__proto__ === Array.prototype; // true arr.__proto__.__proto__ === Object.prototype; // true Array.__proto__ === Function.prototype; // true
JavaScript 是 单线程
语言,意味着只有单独的一个调用栈,同一时间只能处理一个任务或一段代码。队列、堆、栈、事件循环构成了 js 的并发模型,事件循环
是 JavaScript 的执行机制。
为什么js是一门单线程语言呢?最初设计JS是用来在浏览器验证表单以及操控DOM元素,为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程。
既然是单线程也就意味着不存在异步,只能自上而下执行,如果代码阻塞只能一直等下去,这样导致很差的用户体验,所以事件循环的出现让 js 拥有异步的能力。
更多编程相关知识,请访问:编程教学!!
위 내용은 JS의 세 가지 산인 범위 및 폐쇄, 프로토타입 및 프로토타입 체인, 비동기 및 단일 스레드에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!