자바스크립트란 무엇인가요?
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>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">function square(n){
return n*n;
}</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>
<span style="font-size: 14px;">이렇게 하면 위의 명령어는 <code>LD id R
로 표현될 수 있으며, 이는 코드의 가독성을 크게 향상시킵니다. 그러나 이것은 충분히 친숙하지 않습니다. CPU는 인간의 사고와 언어 패턴과는 거리가 먼 3개의 주소 표현만 실행할 수 있습니다. 그래서 위대한 과학자들이 고급 언어를 발명했습니다. 고급 언어“코드는 사람이 읽을 수 있도록 작성된 것이지 기계가 읽을 수 있도록 작성된 것은 아닙니다.”
그 이유 고급 언어는 우리의 사고 및 읽기 습관과 더 일치하기 때문에 "고급 언어"라고 불립니다. if...else
와 같은 문은 1010101010
보다 훨씬 편안해 보입니다. 하지만 컴퓨터는 고급 언어를 직접 실행할 수 없기 때문에 고급 언어를 어셈블리 언어/기계 명령어로 변환한 후에 실행해야 합니다. 이 프로세스는 컴파일입니다.
컴파일
우리는 이미 컴파일의 개념을 이해했습니다. 플랫폼에 대해 이야기해 보겠습니다. 동일한 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:
분명히 TypeScript를 사용하면 코딩 초기 단계에서 이러한 8가지 문제를 적시에 처리할 수 있습니다.
결론
이제 우리는 JavaScript가 어떻게 작동하는지 이해했습니다. 하지만 이것을 이해하면 더 나은 코드를 작성하는 데 도움이 될까요?
답은 그렇습니다. TypeScript가 유형 검사 및 유형 추론을 개선하는 데 도움이 될 수 있다는 점은 말할 것도 없고, JavaScript의 범위와 범위도 컴파일 프로세스와 밀접하게 관련되어 있으며 현재 주류 소규모 프로그램 프레임워크는 하나의 코드 세트와 여러 플랫폼을 지원할 수 있다고 믿습니다. 이 기사를 읽은 후 마지막으로 이러한 기술의 기본 원리를 전반적으로 이해하게 되었습니다.
해킹을 즐겨보세요!
이 기사는 js tutorial 칼럼에서 가져온 것입니다. 배우신 것을 환영합니다!
위 내용은 JavaScript 작동 방식에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!