많은 독자들이 내 책 『자바스크립트 언어와 프로그래밍 실습의 본질』이 읽기 어렵다고 생각하기 때문에 나는 늘 간단하게 읽을 수 있는 책을 쓰고 싶었다. 간단하게, 이번에는 가장 간단한 것을 작성해 보겠습니다.
"프로그래머" 2008.09호에는 "No Nonsense ErLang"이라는 기사가 있었는데, "No Nonsense C", "No Nonsense Book Review" 등 많은 기사가 생각나고, 생각도 나네요. JavaScript에 관한 "말도 안되는" 기사는 없으므로 이 기사를 쓰기로 결정했습니다. 이 결정과 관련된 또 다른 이유는 많은 독자들이 내 책 "JavaScript 언어 및 프로그래밍 실습의 본질"이 읽기 어렵다고 생각하기 때문에 나는 항상 간단한 읽기 책을 쓰고 싶었습니다. 간단하게, 이번에는 가장 간단한 것을 작성해 보겠습니다.
면책조항: 복잡한 내용만 읽고 싶다면 이 글을 읽지 마세요.
1. JavaScript는 원래 절차적이었습니다
1.0 시대부터 시작된 JavaScript는 실제로 절차적입니다. 두 가지 기본 기능만 있습니다. 하나는 웹 페이지의 HTML
태그에 직접 배치하여 이벤트를 인계받을 수 있다는 것입니다. 예를 들어
코드 복사 코드는 다음과 같습니다.
두번째 item은 간단한 Object 생성자(함수)를 지원합니다. 사실 이 시대의 생성자는 초기화 함수로 더 적합합니다.
코드 복사 코드는 다음과 같습니다.
function MyObject() {
this.xxx = '...';
this.yyy = '...'
}
obj = new MyObject();
그러므로 초기 JavaScript에는 의심할 여지없이 "객체 기반 절차적 스크립팅 언어"라는 제목이 붙었는데 이는 전혀 불공평하지 않습니다. 위의 두 가지 기능
외에도 JavaScript에는 다음과 같은 몇 가지 일반적인 스크립팅 언어 속성이 있습니다.
- 전체 .js 파일이 한 번에 실행 환경(예: 웹 브라우저)에 로드되고, 구문 분석, 한 줄씩 실행 시작
- 위 구문 분석 주기에서 "var"로 선언된 (이름이 지정된) 함수와 변수는 스크립트 코드에서 사용할 수 있도록 식별자 테이블에서 전처리됩니다. - 전역 코드 라인이나 함수 호출부터 실행이 시작되며, 전체 프로세스 중에 실행될 수 없는 코드는 오류 검사를 수행하지 않습니다(첫 번째 단계의 구문 오류 검사 제외).
에는 일반적인 절차적 언어의 속성도 있습니다.
- if/for/while/switch 및 기타 문이 있습니다.
- 함수를 사용하여 함수를 선언하고, "(..)"를 사용합니다. 공식 매개변수 목록과 함수 호출 및 매개변수 전송을 나타냅니다.
- 코드 블록을 나타내는 "{..}" 사용을 포함하여 C 언어의 기본 구문과 유사합니다. "!=";
등의 연산 기호 - Java 언어와 유사한 객체 연산 연산자이며 속성, 메서드 등의 기본 개념입니다.
자, 이제 기본 JavaScript 언어를 볼 수 있습니다. 해당 코드에는 C와 같은 함수와 명령문만 있으며 매우 간단한
객체 지향 프로그래밍을 지원합니다. 좋습니다. 이것은 실제로 JavaScript의 거의 전부입니다. 음... 문법의 모든 기본 개념입니다. 조금이라도 입문적인 프로그래밍 언어를 사용해 본 적이 있다면 JavaScript가 실제로 매우 간단하다는 것을 느낄 것입니다.
그렇습니다. "함수를 작성하고 호출하는 것"은 매우 간단합니다. 예:
function hi() {
alert('hello, world.');
}
hi()
2. 데이터가 좀 더 복잡합니다. 유형
JavaScript에는 6가지 기본 데이터 유형이 있으며 두 가지 범주로 나뉩니다. 한 유형은 값 유형, 즉 정의되지 않음, 문자열, 숫자 및 부울이고 다른 유형 은 참조 유형, 즉 함수 및 객체입니다. 데이터 X의 유형을 감지하려면 간단히 "typeof X"를 사용하여 문자열을 반환하면 됩니다.
다른 고급 언어에서는 "액세스 중에 값이 전달되는지 아니면 참조가 전달되는지"에 따라 값 유형과 참조 유형이 구분됩니다. 간단히 말하면, 다음 함수
에서:
function foo(X) {
}
X는 값 자체 또는 값에 대한 참조로 전달됩니다(예: 포인터), X 유형이 무엇인지 나타냅니다.
다른 언어와 달리 JavaScript는 값 전달 방법을 설명하기 위해 호출 항목에 표시자를 추가하지 않습니다. 예:
function foo(var X) {
// 일반적인 고급 언어에서는 var는 전체 값을 나타냅니다. 이는 변수에 대한 참조입니다. 예:
function foo(X) {
...
}
foo('123') // <- string '123' value
foo(aObj); // <- aObj는 객체 참조입니다
이 방법으로 처리할 수 있는 핵심은 JavaScript 유형 시스템이 충분히 간단하다는 것입니다. 6가지 기본 유형에는 실행 가능한 것과 실행 불가능한 것, 존재(가치) 또는 부재(가치)라는 세 가지 철학적 개념이 포함됩니다. 분명히
의 더 복잡하고 독립적인 논리는 함수도 객체이고, 값도 객체이고, 무가치도 값이기 때문에 이 철학적 아이디어를 이해하는 것은 쉽지 않습니다.
자바스크립트 유형 시스템에 대한 내용은 이것입니다. 간단하게 사용하려면 다음 사항을 기억하면 충분합니다.
- 세 가지 간단한 값 유형, 문자열, 숫자 및 부울을 사용하여 표시할 웹 페이지에 전달합니다.
- 객체가 사용됩니다. 다른 객체, 함수 또는 위의 단순 값 유형을 저장하고 '.' 연산을 사용하여 속성 이름을 통해 이를 찾습니다.
- 정의되지 않음은 데이터가 유효한지 여부를 감지하는 데 사용됩니다.
- 함수; 실행하는 데 사용됩니다.
물론, 언어학의 사상가나 미치광이가 되고 싶다면 위의 철학적 명제를 생각해 보세요. 제가 말리지 않겠습니다.
3. 코로 알아낼 수 있는 것은 직접 측정입니다
아마도 자바스크립트의 직접 수량 선언을 이해하지 못하는 분들이 많겠지만, 사실 매우 간단합니다. 이제 대부분의 고급 언어
는 상수 선언을 지원하므로 가장 원시적인 어셈블리 언어도 즉시 값을 지원합니다. 예:
// in C #define ABYTE 256 // in delphi
const
ABYTE = 256
; in asm
mov ah, 256
물론 JavaScript는... 직접 측정을 지원할 수 있어야 합니다. 부끄러움 없이 – 그것들은 실제로 하나의 개념입니다. 예:
// in javascript
var
aByte = 256
그러나 이를 이해할 때 기억해야 할 점은 위의 모든 코드에서 소위 직접 수량 또는 즉치 값이 다음을 의미한다는 것입니다. 해당
변수 또는 상수의 식별자 ABYTE/aByte가 아닌 '256'입니다. 또한 JavaScript는 8가지 유형의 직접 수량 선언을 지원한다는 점을 알아야 합니다.
---------
숫자 값: 정수, 부동 소수점 지원 포인트 및 0x는 기본 접두사와 같습니다.
부울 값: true/false;
값 없음: 정의되지 않음
함수: function() { ... }, 익명이라고도 함 기능
문자열: '..' 또는 ".." 사용, 여러 줄 및 이스케이프 문자 지원
정규 표현식: /../.. 사용, g, i, m 등과 같은 일반 구성 지원; > 배열: 중첩된 배열을 지원하려면 [..]를 사용하세요.
객체: 중첩된 객체 선언을 지원하려면 {...}를 사용하세요.
---------------- - ---
위의 문자 수를 코드 어디에서나 개별적으로 사용할 수 있습니다. 즉, 표현식이나 명령문 라인을 의미합니다. 코
를 사용하여 할 수 있는 추론은 다음과 같습니다.
//쓸 수 있으므로:
aaa = 'hello, ''world'
//그럼 쓸 수 있어야 합니다. :
bbb = [1,2,3] [4,5,6];
//동일하게 작성할 수 있습니다.
ccc = /abc/ /cdf/
//마찬가지로:
// ...
위와 같이 표현식이나 문장 중간에 직접 수량을 모두 넣을 수 있습니다. 때로는 구문 분석의 필요성으로 인해
괄호 쌍을 사용하여 직접 수량을 묶어야 할 수도 있습니다. 그렇지 않으면 다음과 같이 문법적 모호성이 발생합니다.
ddd = (function() { }) (function() {})
그렇습니다. 직접 측정하는 방법은 이렇게 간단합니다. 코가 아직 손상되지 않았으면 좋겠습니다.
4. 프로토타입 상속
프로토타입 상속은 세상에서 가장 간단한 것일 수 있습니다.
우리는 객체가 테이블이라고 가정합니다. 위대한 Anders는 JavaScript 객체가 "속성 모음"이라고 말했습니다.
이러한 테이블은 "이름/값" 쌍을 저장합니다. .
aObj.name
코드를 사용하여 값을 찾으려면 테이블에서 확인하세요(Delphi를 사용하는 경우 TStringList를 기억해야 합니다). 객체, 아, 제가 이전에 이해한
에서 소위 객체는 "상속 관계가 있는 구조(구조체/레코드)"입니다. 그렇다면 상속관계란 무엇인가?
그렇습니다. 위 검색이 실패하면 프로토타입 상속을 위해 aObj 개체의 "프로토타입"만 검색하면 됩니다. 그게 전부입니다.
이 프로토타입도 생성자 함수의 프로토타입 속성에 기록되는 객체입니다. 예:
function MyObject() {
// ...
}
MyObject.prototype = xxx;
var aObj = new MyObject()
zzz = aObj.name ;
aObj에서 속성 이름을 찾을 수 없으면 위의 규칙에 따라 xxx 개체에서 검색합니다. 즉, "xxx.name"을 찾으려고 합니다.
xxx 자체도 객체이므로 생성자 함수(예: xxxObject())도 있으므로 xxx.name을 찾을 수 없으면
xxxObject.prototype으로 이동하여 찾습니다. .그래서... 더 이상 찾을 수 없을 때까지 너무 깊이 파고들면... 정의되지 않은 값이 반환됩니다.
소위 프로토타입 상속은 단순한 검색 규칙일 뿐입니다.
반면에 aObj가 특정 멤버에 액세스하도록 허용해야 하는 경우 해당 멤버(또는 aObj와 유사한 인스턴스) 프로토타입
만 수정하면 됩니다. 이는 JavaScript에서 매우 일반적으로 사용됩니다. 예를 들어, 모든 문자열이 특정 속성을 가지기를 원하는 경우:
String.protoype.MyName = 'string'
또는 모든 객체가 특정 속성(또는 메소드 또는 기타 다른 것)을 가지기를 원하는 경우 then:
Object.prototype.getMyName = function() {
return this.MyName;
}
정말 훌륭합니다. 이제 String도 getMyName을 사용할 수 있고 함수도 getMyName을 사용할 수 있습니다. 모든 것이 사라졌습니다. 이름에도 이름이 있습니다. 물론 이름의
문자는 정의되지 않습니다.
아무 이름도 이름이 아니다. 당신이 철학적인 미치광이가 될지는 생각해본 적이 없다.
5. 함수형
이것은 JavaScript의 발명품이 아니며, 그의 발명품은 여전히 우리를 괴롭히고 있습니다... 마치 에디슨의 램프처럼 거품은 여전히 우리를 비추고 있습니다.
사실 함수형 언어는 명령형 언어만큼 "완전한" 언어 구현 솔루션입니다. 기본 개념은 명령
수식과 동일하므로 이해하기 어려운 명사를 사용하고 싶지 않다면 C 또는 Delphi로 변경하면 됩니다. 언어가 완전히 다르기 때문에 대부분의
경우에는 이러한 전통적이고 일반적인 상용 언어와도 호환되지 않습니다.
사실 매일 사용하고 계시죠.
다음 코드 줄은 함수형 언어 아이디어로 가득 차 있습니다.
a b
정말요? 실제로 " " 기호를 함수로 생각하면 완전히 똑같습니다. 실제로 소위 함수는 실행 프로세스, 작업, 함수 입력... 즉, 코드의 무언가는 데이터이거나 작업입니다. 그리고
연산이라면 "함수"라고 생각하시면 됩니다. 위의 코드 줄에서 - 표현식에서 a와 b는 명백히 데이터이고 숫자는 이에 대한 연산을 수행하는 연산이므로 자연스럽게 "함수, 프로세스 또는 연산"으로 간주될 수 있습니다. 따라서... 두 숫자의 합에 대해 작동하는 "함수"는
다음과 같이 작성할 수 있습니다:
func_add(a, b)
또는 다음과 같이:
( a b)
그 모든 것은 단지 텍스트일 뿐 표기법이 다를 뿐입니다. 마치 내가 이 기호를 '지아'라고 했는데 당신이 '안데'라고 고집하면 다른
사람은 '아-디-디'라고 발음하라고 고집하는 것과 같습니다. 차이점이 있나요? 아니요.
모든 프로그래머는 매일 문장, 표현식, 연산 로직을 작성합니다. 이런 것들이 하나의... 음... 매우 큰
함수로 작성될 수도 있고, 셀 수 없이 작고 아름다운 함수로 분할될 수도 있다는 것은 누구나 알고 있습니다. 이 모든 기능이 차례로 실행되면
"기능적 언어"가 됩니다. 따라서 "함수형 언어의 할아버지"로 알려진 LISP는 다음과 같이 "함수적 연산을 연결"하는 언어입니다.
코드 복사 코드는 다음과 같습니다. 🎜>
(defun subst (x y z)
(cond ((atom z)
(cond ((eq z y) x)
('t z)))
(' t (cons (subst x y (car z))
(subst x y (cdr z))))))
어떤 사람들은 추악한 스파게티라고 생각하고, 어떤 사람들은 가장 단순한 언어라고 생각합니다. 오, 그것은 당신에게 달려 있습니다. 당신이 그것을 이해하는 한 그것이 어떻게 보이는지는 중요하지 않습니다.
기능적 언어는 연속적으로 기능을 실행하기 때문에 "문"이 없으며 논리적 무결성을 달성해야 합니다. 간단히 말해서
연속 실행 과정에서 "시퀀스, 분기 및 루프"의 세 가지 기본 논리를 구현해야 합니다. 기능적 해결책은 if/then/else를 대체하기 위해 삼항 조건 연산
을 사용하는 것입니다. 이는 다음 코드입니다.
if a then b else c
//는
a ? b와 동일합니다. c
또한 루프를 구현하기 위해 재귀(함수 호출 함수)를 사용합니다. 재귀 함수 호출이 스택 오버플로(Stack Overflow at...)로 이어진다는 점을 고려하여
함수형 언어는 "꼬리 재귀"를 제안합니다. 즉, 코드를 작성할 때 함수 Recursive에서 마지막 호출만 "보장"합니다. 작동 중 전화.
이런 방식으로 이 재귀 호출은 스택을 유지할 필요가 없습니다. 후속 작업이 없기 때문에
반환할 필요가 없는 jmp 어셈블리 명령의 한 줄로 최적화할 수 있습니다.
세상은 정말 아름답습니다. 소위 함수식은 jmp, jmp, jmp뿐만 아니라 연산 항목의 집합입니다. 하지만, 그렇지 않습니까? 이 CPU?
6. 더욱 발전된 함수식(1)
사실 세상은 아름답지 않습니다.
CPU가 그냥 놓여 있으면 시퀀스, 분기, 루프와 같은 명령만 있을 것입니다. 그런데 실행 중일 때
시계가 똑딱거리고... 똑딱거리고... 멀티코어라면 그런 것들이 동시에 똑딱거리게 될 것입니다.
이것이 문제입니다. 세상은 원래 단일한 시간 순서도 아니고 법칙도 아닙니다. 따라서 동시성, 중단 및 예외가 발생합니다. 함수형 언어는
스파게티처럼 무한히 확장되어야 합니다. 그럼 틱이 여러 개 있으면 스파게티도 여러 개 있어야 할까요? 그런데 이 경우에는
아직도 스파게티라고 부르나요?
함수식의 해를 연속과 노드라고 합니다. 계속은 현재 프로세스를 중지하고 다른 위치로 이동한 다음 반환합니다. 노드는 한 위치의 코드가 독립적이고 완전하며 다른 노드와 관련이 없음을 보장합니다. 기능적 언어에서 다중 노드는 평행 우주와 같습니다. 대부분의 경우 서로 투명하게 연결하려면 엄청난 양의 에너지와... 웜홀이 필요합니다.
다중 노드 문제를 깊이 파고들 필요는 없습니다. 다중 공간 접근으로 인해 발생하는 시공간 문제는 천문학자와 시공간 다차원 이론가들이 연구하는 문제입니다
. : 여러 노드 사이에 교차 접속 관계가 있는 경우 세계/우주가 파괴됩니다. 이러한 지침은 기본적으로 여러 우주를 지원하는 ErLang과 같은 언어에 대한 백서, 참조 매뉴얼 및 우주비행사의 일일 가이드에 기록되어 있습니다. 문제의 근원을 파악하고 싶고 300개 이상의 고급 숫자, 물리학 및 천문학 용어를 명확하게 이해하고 있다고 생각한다면 여기 프로그래머를 위한 입문 가이드가 있습니다. 여기에서 시작하는 것이 좋습니다.
http://www.php.cn/
계속하는 것은 상태 문제를 해결하는 방법 중 하나입니다. 간단히 말해서, 시간이 있으면 상태가 있습니다. 과거, 현재, 미래가 있습니다. 과거는 역사가 있고 과거에 일어난 일로 인해 지금 일어나는 일을 결정할 것입니다. 예를 들어 어제 너무 많이 마셨기 때문에 오늘은 죽만 먹을 수 있고 지금은 내일이기 때문에 내일을 준비하라. 오늘의 상태를 기록하기 위해 무엇을 할 수 있는가? 예를 들어, 오늘은 죽을 먹었다. 내일은 당연히 일어날 일이 많기 때문에 하나씩 준비해야 한다.
아, 중요한 것은 '준비'입니다. 이를 컴퓨터 시스템에서는 이벤트라고 합니다. 아니면 계획이라고 부르거나 긴급상황이라고 부르세요. 우리 PC가 왜 실행되는지 아시나요? En... 충분히 작은 시간 단위로 명령을 실행하는 명령 파이프라인이 있기 때문입니다. 컴퓨팅 시스템의 경우 이 예약된 명령어 액세스 동작은 인터럽트입니다. 그러던 어느 날 친구가 나에게 물었습니다. 실행 논리가 시퀀스, 분기 및 루프뿐이라면 프로세스 시스템의 트리거는 무엇입니까? 오랫동안 고민했지만 해결책이 없었습니다. 이제 이 질문에 대답하려면 "시간"이라는 차원을 추가해야 합니다. 소위 버스트, 동시성 및 이와 유사한 것들이 타이밍 개념의 논리입니다.
미래에 무언가를 트리거할 준비를 "준비"할 때 간단히 말해서 시계 핸들러라고 생각하면 됩니다(Windows에서는 OnTimer라고 하고 브라우저에서는 setTimeout/setInterval이라고 함). 이때 기능적 언어로 스파게티 식사를 하라고 주문하면 "우리는 이미 준비가 되어 있다", "얼마나 준비가 되어 있는지"라고 설명한다. 기능적 스타일의 기본 원칙에 따르면 기능은 상태와 아무런 관련이 없으며 "미래"의 타이밍과도 관련이 없습니다. 이것은 모순이 되었습니다.
사실 우리는 이미 이런 모순과 정면충돌한 적이 있다. 이것이 바로 '사이클'이다. 루프에는 루프의 진행 상황을 나타내기 위해 상태량이 필요하기 때문에
이 "진행"은 타이밍과 관련이 있습니다. 함수형 스타일은 이를 해결하기 위해 "재귀"를 사용합니다. 즉, 재귀 함수의 매개변수를 통해 진행 상황을 전달합니다. "재귀 매개변수" 인터페이스의 양쪽에서 함수 표현식은 시간 독립적입니다. 결과적인 문제는 스택 오버플로이고 해결책은 꼬리 재귀입니다. 결과적인 문제는 프로그래밍 복잡성이며, 꼬리 재귀가 모든 재귀를 대체할 수 있는지 여부는... Weinberg는 말했습니다. 그렇습니다. 문제에 대한 모든 해결책은 다음과 같습니다. 새로운 것. 아... 또 와인버그네요. 이제 시스템이 하나 이상의 시계열, 즉 CPU에서 실행되므로 "더 많은 상태"가 분명히 필요합니다. 노드가 있고 "웜홀 없음"을 보장하더라도 여전히 CPU의 과거, 현재, 미래의 문제를 해결해야 합니다.
기능 전문가들은 끈기라는 두 단어를 말했습니다. 간단합니다. 과거, 현재 상태, 미래에 대한 준비를 함수의 매개변수로 전달하면 됩니다. '지금'은 과거와 현재의 상태와 변화뿐만 아니라 미래의 활동까지 포함해야 하기 때문에 폭발할 것 같습니다. 따라서 새로운 해결책은 다음과 같습니다. 지금 폭발하지 않으려면 "연속" 인터페이스에서 계산을 수행하지 마십시오.
'과거' 데이터를 기반으로 의사결정을 내리는 '미래'를 기반으로 하는 작업이 바로 연속성입니다. 이를 지원하는 기능적 특징은 지연 평가입니다. 간단히 말해서,
function f(x, c) {
...
c(x)
}
f(data, f)
전송 인터페이스로 인해; f()에서는 c 자체가 평가되지 않으므로 향후 c(x)가 작동될 때 폭발이 발생할 수도 있고 발생하지 않을 수도 있습니다.
우주의 엔트로피에 한계가 있다면, 이 한계는 미지의 미래에도 있을 것입니다. 게다가 알 수 없는 미래에는 왜곡이 현재로 되돌아오는 것도 가능하다.
지속의 두 가지 원칙은 다음과 같습니다.
---------
성공적인 지속 후에는 새로운 지속(또는 process )
실패하면 이전 선택지점으로 계속 돌아갑니다
---------
바로 그 이유는 persistence 상태, 그리고 이것이 상태와 지속성 자체가 함수 매개변수를 통해 전달되기 때문에 '선택지점으로 복귀'는 미래의 자신을 위한 결정
일 뿐이며 현재 상태와는 아무런 관련이 없습니다.
7. 고급 함수식(2)
어쨌든 프로그래밍 패러다임에서는 일종의 자기순수성을 유지하기 위해 다양한 함수식의 복잡성이 존재합니다. 예를 들어 생성기(generator)
의 문제는 일괄 데이터 생성(증분 등) 사이에 관계가 있고 생성 프로세스가 타이밍과 관련되어 있기 때문입니다(항상 한 번의 호출로 얻어지는 것은 아닙니다
). 모든 데이터)이므로 함수형 언어는 "생성기"와 같은 함수 개념을 정의합니다.
이 수익은 "미래"에서 "현재"로의 웜홀입니다. 이 웜홀을 통해 시계열 관련 데이터를 얻을 수 있습니다. 다음
은 이에 대한 예입니다(Mozilla의 피보나치 수열 예):