>  기사  >  웹 프론트엔드  >  JavaScript 작동 방식에 대한 자세한 설명

JavaScript 작동 방식에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2019-11-26 15:24:472452검색

JavaScript 작동 방식에 대한 자세한 설명

자바스크립트란 무엇인가요?

JavaScript의 정의를 확인해 보겠습니다. JavaScript는 해석된 동적 언어입니다.

컴파일된 언어에 비해 해석된 언어가 존재합니다. 소스 코드는 직접 타겟 코드로 컴파일되지 않고 중간 코드로 변환된 후 인터프리터에 의해 해석되고 실행됩니다.

주요 프로그래밍 언어에는 컴파일(예: C++), 해석(예: JavaScript), 반해석 및 반컴파일(예: Java)이 포함됩니다.

[관련 강좌 추천: JavaScript 동영상 튜토리얼]

코드는 어떻게 실행되나요?

먼저 코드가 어떻게 실행되는지 이해해 봅시다.

우리는 코드가 CPU에 의해 실행된다는 것을 알고 있으며, 현재 CPU는 if...else와 같은 명령문을 직접 실행할 수 없으며 바이너리 명령어만 실행할 수 있습니다. 하지만 이진 명령어는 인간에게 정말 비우호적입니다. 이진 명령어 1000010010101001가 나타내는 것이 무엇인지 빠르고 정확하게 판단하기가 어렵습니다. 그래서 과학자들은 어셈블리 언어를 발명했습니다. if…else之类的语句,它只能执行二进制指令。但是二进制指令对人类实在是太不友好了:我们很难快速准确的判断一个二进制指令1000010010101001代表什么?所以科学家们发明汇编语言。

汇编语言

汇编语言实际上就是二进制指令的助记符。

假设10101010代表读取内存操作,内存地址是10101111,寄存器地址是11111010,那么完整的操作101010101010111111111010就代表读取某个内存地址的值并装载到寄存器,而汇编语言并没有改变这种操作方式,它只是二进制指令的映射:

LD:10101010 
id:10101111
R:11111010

这样上述指令就可以表达为LD id R ,大大增强了代码的可读性。

但是这样还不够友好,CPU只能执行三地址表达式,和人的思考方式、语言模式相距甚远。所以伟大的科学家们又发明了高级语言。

高级语言

“代码是写给人看的,不是写给机器看的,只是顺便计算机可以执行而已。”

高级语言之所以称之为“高级”,就是因为它更加符合我们的思维和阅读习惯。if…else这种语句看起来要比1010101010

어셈블리 언어

어셈블리 언어는 실제로 이진 명령어에 대한 니모닉입니다.

10101010이 메모리 읽기 작업을 나타내고, 메모리 주소가 10101111이고, 레지스터 주소가 11111010이라고 가정하면 전체 작업은 다음과 같습니다. 101010101010111111111010는 특정 메모리 주소의 값을 읽고 이를 레지스터에 로드하는 것을 의미합니다. 어셈블리 언어는 이 연산 방법을 변경하지 않습니다. <p></p> <pre class="brush:php;toolbar:false">function square(n){  return n*n; }</pre> <span style="font-size: 14px;">이렇게 하면 위의 명령어는 <code>LD id R로 표현될 수 있으며, 이는 코드의 가독성을 크게 향상시킵니다. 그러나 이것은 충분히 친숙하지 않습니다. CPU는 인간의 사고와 언어 패턴과는 거리가 먼 3개의 주소 표현만 실행할 수 있습니다. 그래서 위대한 과학자들이 고급 언어를 발명했습니다.

고급 언어

“코드는 사람이 읽을 수 있도록 작성된 것이지 기계가 읽을 수 있도록 작성된 것은 아닙니다.”
그 이유 고급 언어는 우리의 사고 및 읽기 습관과 더 일치하기 때문에 "고급 언어"라고 불립니다. if...else와 같은 문은 1010101010보다 훨씬 편안해 보입니다. 하지만 컴퓨터는 고급 언어를 직접 실행할 수 없기 때문에 고급 언어를 어셈블리 언어/기계 명령어로 변환한 후에 실행해야 합니다. 이 프로세스는 컴파일입니다.

JavaScript를 컴파일해야 하나요?

JavaScript는 의심할 여지 없이 고급 언어이므로 실행되기 전에 반드시 컴파일이 필요합니다. 그런데 왜 우리는 그것을 해석된 언어라고 부를까요? 컴파일된 언어와 반해석 및 반컴파일된 언어의 차이점은 무엇입니까? 컴파일부터 시작해 보겠습니다.

컴파일

우리는 이미 컴파일의 개념을 이해했습니다. 플랫폼에 대해 이야기해 보겠습니다. 동일한 C++ 코드가 Windows에서는 .obj 파일로 컴파일되고, Linux에서는 .o 파일이 생성됩니다. . 둘 다 보편적으로 사용할 수는 없습니다. 실행 파일에는 코드 외에도 운영 체제 API, 메모리, 스레드, 프로세스 및 기타 시스템 리소스가 필요하며 운영 체제마다 구현이 다르기 때문입니다. 예를 들어, 우리가 잘 알고 있는 I/O 멀티플렉싱(이벤트 중심의 영혼), Windows의 구현 솔루션은 IOCP 솔루션, Linux에서는 epoll입니다. 따라서 컴파일된 언어는 플랫폼에 따라 별도로 컴파일하거나 작성해야 하며, 생성되는 실행 파일의 형식도 다릅니다.

Cross-platform

🎜🎜Java는 바이트코드를 도입하여 크로스 플랫폼 작업을 구현합니다. .java 파일이 컴파일되는 운영 체제에 관계없이 .class 파일입니다. 바이트코드 파일, 객체 코드의 중간 형태). 그런 다음 Java는 바이트코드 파일을 해석하고 실행할 수 있도록 다양한 시스템에 다양한 Java 가상 머신을 제공합니다. 해석과 실행은 목적 코드를 생성하지 않지만, 결국 컴퓨터 실행을 위한 어셈블리/바이너리 명령으로 변환됩니다. 🎜🎜간단한 운영체제를 완전히 독립적으로 작성하면 Java를 실행할 수 있나요? 분명히 이 시스템에 해당하는 JVM이 없기 때문에 불가능합니다. 따라서 Java의 크로스 플랫폼과 다른 언어의 크로스 플랫폼에는 제한이 있습니다. 🎜🎜반해석 및 반컴파일을 사용하는 Java의 장점은 개발 효율성을 크게 향상시키지만 그에 따라 코드 실행 효율성이 감소한다는 것입니다. 결국 가상 머신은 성능 손실을 겪게 됩니다. 🎜🎜🎜🎜설명 및 실행🎜🎜🎜🎜JavaScript는 한 단계 더 발전했습니다. 이는 완전히 해석된 실행 또는 적시 컴파일입니다. 중간 코드 생성이나 대상 코드 생성이 없습니다. 이 프로세스는 일반적으로 호스트 환경(예: 브라우저, Node.js)에서 처리됩니다. 🎜🎜🎜🎜편집 과정🎜🎜🎜

现在我们确认了,即使是解释执行的语言,也是需要编译的。那么代码是如何编译的呢?我们来简单了解一下。

词法分析

词法分析会把语句分解成词法单元,即Token。

function square(n){
 return n*n;
}

这个函数会被词法分析器识别为function square(n){return,,n ,*n}并且给它们加上标注,代表这是一个变量还是一个操作。

语法分析

这个过程会把Token转化成抽象语法树(AST):

{
 type:'function',
    id:{
        type:'id'
        name:'square'
    },
    params:[
        {
            type:'id',
            name:'n'
        }
    ]
    ...
}

优化及代码生成

在这一步编译器会做一些优化工作,比如删除多余运算、删除未用赋值、合并部分变量等等操作,最后生成目标代码。

由于即时编译型语言的编译通常发生在运行前几微秒,所以编译器来不及做太多的优化工作。这也是相比编译型语言,早期JavaScript性能孱弱的原因之一。不过就现在而言,益于 V8 引擎(相比早期的JavaScript的引擎转换成字节码或解释执行,Node.js可以用 V8 提供的 JS2C 工具将 JavaScript 转译为 C++代码),JavaScript 和其他语言性能上的差距已经不足为道了。

链接及装载

目标代码基本不能独立运行。应用程序一般都会由多个部分(模块)组成 ,比如C++中一个简单的输出就要引入标准库 iostream

#include <iostream>
using namespace std;
int main(){    
    cout <p>编译器需要把多份目标代码(库)链接起来才能生成可执行文件。至此,我们简单的了解了编译过程。但实际上编译比我们所讲的要复杂得多,在此就不在展开了。</p>
<p><strong><span style="font-size: 18px;">什么是动态语言,动态类型?</span></strong></p>
<p>我们还知道,JavaScript是动态语言。那么什么是动态语言?</p>
<p>通常来说,这是指在运行时代码可以根据某些条件改变自身结构的语言。比如JavaScript在运行时新的函数、对象、甚至代码都可以被引进(eval);又比如Objective-C,它也可以在运行时修改对象,但它不能动态创建类,也没有 eval 方法。那Objective-C算是动态语言吗?所以我认为,动态语言是个程度的问题,我们不必在这个概念上太过纠结,可以更多的关注其应用。APP中常用的热更新功能就是基于动态语言特性而得以实现的。</p>
<p>JavaScript又是一门动态类型的语言,动态类型又是什么?动态类型的定义倒是很明确:数据类型不是在编译阶段确定,而是在运行时确定。</p>
<p>那么 TypeScript 是什么类型的语言呢?它有静态类型检查,它是静态语言吗?实际上它只是 JavaScript 的一个方言。TypeScript 最终还是要转译为 JavaScript 才能执行(tsc),就如同我们使用babel 把 ES6 代码转译为 ES5 一样。这个过程严格上来说不是编译。</p>
<p>TypeScript 最大的优势就是静态类型检查和类型推断,这是 JavaScript 严重缺失的能力。但实际上如果我们忽略IDE 给的报错提示强行运行 TS 代码,也还是有几率能够成功跑起来的。</p>
<p><span style="font-size: 18px;"><strong>错误</strong></span></p>
<p>刚刚我们提到报错,不妨再扩展说一说错误。通常来说错误分为以下几种:</p>
<ul>
<li>编译时错误</li>
<li>链接时错误</li>
<li>运行时错误</li>
</ul>
<p>是不是和编译过程能够严格对应起来?</p>
<p><strong>编译时错误</strong></p>
<p>编译时错误分为:</p>
<ul>
<li>
<p>语法错误</p>
<pre class="brush:php;toolbar:false">var str ='s ;

这就是典型的语法错误,这种代码无法生成AST,在词法分析阶段就会报错。通常我们这么写代码,IDE 就会报错。这是IDE的优化工作,和词法分析相关。

  • 类型错误

    编译器会检查我们声明的变量和函数的类型,JavaScript中我们非常熟悉的Type Error:undefined is not object就是此类错误。

  • 链接时错误

    在链接阶段发生的异常。这种情况 JavaScript 中比较少见,在编译型语言中比较常见。

    运行时错误

    这是最难排查的错误了,举例来说:

    int pider(int a,int b){
        return a/b;
    }

    上面的代码在编辑编译、链接阶段都没问题,也能够正常的生成可执行文件。但是一旦如此使用pider(1,0)就会报错了,这就是典型的运行时错误。通常来说运行时错误都是程序不够健壮导致的。

    JavaScript中最常见的十个错误:

    下图是某错误处理平台收集统计的JavaScript Top10 错误,其中7个TypeError,1个 ReferenceError:

    JavaScript 작동 방식에 대한 자세한 설명

    분명히 TypeScript를 사용하면 코딩 초기 단계에서 이러한 8가지 문제를 적시에 처리할 수 있습니다.

    결론

    이제 우리는 JavaScript가 어떻게 작동하는지 이해했습니다. 하지만 이것을 이해하면 더 나은 코드를 작성하는 데 도움이 될까요?

    답은 그렇습니다. TypeScript가 유형 검사 및 유형 추론을 개선하는 데 도움이 될 수 있다는 점은 말할 것도 없고, JavaScript의 범위와 범위도 컴파일 프로세스와 밀접하게 관련되어 있으며 현재 주류 소규모 프로그램 프레임워크는 하나의 코드 세트와 여러 플랫폼을 지원할 수 있다고 믿습니다. 이 기사를 읽은 후 마지막으로 이러한 기술의 기본 원리를 전반적으로 이해하게 되었습니다.
    해킹을 즐겨보세요!

    이 기사는 js tutorial 칼럼에서 가져온 것입니다. 배우신 것을 환영합니다!

    위 내용은 JavaScript 작동 방식에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제