Node.js가 무엇인지 이해하시나요?

零下一度
풀어 주다: 2017-06-26 11:47:57
원래의
1199명이 탐색했습니다.

Node.js 이해

Node.js의 작동 방식을 이해하려면 먼저 Javascript를 서버 측 개발에 적합하게 만드는 몇 가지 주요 기능을 이해해야 합니다. Javascript는 단순하면서도 유연한 언어이며, 이러한 유연성을 통해 시간이 지나도 테스트를 견딜 수 있습니다. 함수 및 클로저와 같은 기능으로 인해 Javascript는 웹 개발에 이상적인 언어입니다.

자바스크립트는 신뢰할 수 없다는 편견이 있는데, 그렇지 않습니다. Javascript에 대한 사람들의 편견은 DOM에서 비롯됩니다. DOM은 Javascript가 브라우저와 상호 작용할 수 있도록 브라우저 제조업체에서 제공하는 API입니다. 브라우저 제조업체마다 구현하는 DOM에는 차이가 있습니다. 그러나 Javascript 자체는 다양한 브라우저와 Node.js에서 실행될 수 있는 잘 정의된 언어입니다. 이 섹션에서는 먼저 Javascript의 몇 가지 기본 사항과 Node.js가 Javascript를 사용하여 뛰어난 성능을 갖춘 웹 개발 플랫폼을 제공하는 방법을 소개합니다.

Variables

Javascript는 var 키워드를 사용하여 변수를 정의합니다. 예를 들어, 다음 코드는 foo라는 변수를 생성하고 이를 명령줄에 출력합니다. (nodevariable.js를 통해 명령줄에서 다음 코드 파일을 실행할 수 있습니다.)var关键字定义变量。例如下面的代码创建了一个名为foo的变量,并在命令行中输出。(可以通过node variable.js在命令行中执行下面的代码文件。)

代码文件 variable.js
var foo = 123;console.log(foo); // 123
로그인 후 복사

Javascript运行环境(浏览器或者Node.js)通常会定义一些我们可以使用的全局变量,例如console对象,console对象包含一个成员函数loglog函数能够接受任意数量的参数并输出它们。我们接下来会遇到更多的全局对象,你将会发现,Javascript具有一个优秀的编程语言应该包含的大部分特性。

数值

Javascript支持常见的算数操作符(+-*/%)。例如下列代码:

var foo = 3;
var bar = 5;
console.log(foo+1); //4
console.log(foo / bar); //0.6
console.log(foo * bar); //15
console.log(foo - bar); //-2
console.log(foo % 2); //取余:1
로그인 후 복사

布尔值

布尔值包括truefalse。你可以给变量赋值为truefalse,并对其进行布尔操作。例如下列代码:

var foo = true;
console.log(foo); //true//常见的布尔操作符号: &&,||, !
console.log(true && true); //true
console.log(true && false); /false
console.log(true || false); //true
console.log(false || false); //false
console.log(!true); //false
console.log(!false); //true
로그인 후 복사

数组

在Javascript中,我们可以通过[]创建数组。数组对象包含很多有用的函数,例如下列代码所示:

var foo = [];

foo.push(1); //添加到数组末尾
console.log(foo); // [1]

foo.unshift(2);  //添加到数组头部
console.log(foo); // [2, 1]//数组起始位置从0开始
console.log(foo[0]); // 2
로그인 후 복사

对象字面量

Javascript中通常使用对象字面量{}创建对象,例如下列代码所示:

var foo = {};
console.log(foo); // {}
foo.bar = 123;
console.log(foo); // {bar: 123}
로그인 후 복사

上面的代码在运行时添加对象属性,我们也可以在创建对象时定义对象属性:

var foo = {  bar: 123
};
console.log(foo); // {bar: 123}
로그인 후 복사

对象字面量中可以嵌套其它对象字面量,例如下列代码所示:

var foo = {
  bar: 123,
  bas: {
    bas1: 'some string',
    bas2: 345
  }
};
console.log(foo);
로그인 후 복사

当然,对象字面量中也可以包含数组:

var foo = {  bar: 123,  bas: [1,2,3]
};
console.log(foo);
로그인 후 복사

数组当中也可以包含对象字面量:

var foo = {  bar: 123,  bas: [{      qux: 1
    },
    {      qux: 2
    },
    {      qux: 3
    }]
};
console.log(foo.bar); //123
console.log(foo.bas[0].qux); // 1
console.log(foo.bas[2].qux); // 2
로그인 후 복사

函数

Javascript的函数非常强大,我们接下来将通过一系列的例子来逐渐了解它。
通常情况下的Javascript函数结构如下所示:

function functionName(){  //函数体
}
로그인 후 복사

Javascript的所有函数都有返回值。在没有显式声明返回语句的情况下,函数会返回undefined。例如下面代码所示:

function foo(){return 123;}console.log(foo); // 123function bar(){ }console.log(bar()); // undefined
로그인 후 복사

立即执行函数

我们在定义函数以后立即执行它,通过括号()包裹并调用函数。如下列代码所示:

(function foo(){
  console.log('foo was executed!');
})();
로그인 후 복사

出现立即执行函数的原因是为了创建新的变量作用域。ifelsewhile不会创建新的变量作用域,如下列代码所示:

var foo = 123;if(true){  var foo = 456;
}console.log(foo); // 456
로그인 후 복사

在Javascrit中,我们通过函数创建新的变量作用域,例如使用立即执行函数:

var foo = 123;if(true){
  (function(){      var foo = 456;
  })();
}console.log(foo); // 123
로그인 후 복사

在上面的代码中,我们没有给函数命名,这被称为匿名函数。

匿名函数

没有名字的函数被称为匿名函数。在Javascript中,我们可以把函数赋值给变量,如果准备将函数当作变量使用,就不需要给函数命名。下面给出了两种等价的写法:

var foo1 = function nameFunction(){  console.log('foo1');
}
foo1(); // foo1var foo2 = function(){  console.log('foo2');
}
foo2(); // foo2f
로그인 후 복사

据说如果一门编程语言能够把函数当作变量来对待,它就是一门优秀的编程语言,Javascript做到了这一点。

高阶函数

由于Javascript允许我们将函数赋值给变量,所以我们可以将函数作为参数传递给其它函数。将函数作为参数的函数被称为高阶函数。setTimeout就是常见的高阶函数。

setTimeout(function(){console.log('2000 milliseconds have passed since this demo started');
}, 2000);
로그인 후 복사

如果在Node.js中运行上面的代码,会看到命令窗口2秒钟后输出信息。在上面的代码中,我们传递了一个匿名函数作为setTimeout

코드 파일 variable.js
function foo(){  console.log('2000 milliseconds have passed since this demo started');
}
setTimeout(foo, 200);
로그인 후 복사

Javascript 런타임 환경(브라우저 또는 Node.js)은 일반적으로 console 개체와 같이 사용할 수 있는 일부 전역 변수를 정의합니다. console 개체에는 log< 멤버 함수가 포함되어 있습니다. /code >, <code>log 함수는 원하는 수의 매개변수를 허용하고 이를 출력할 수 있습니다. 다음에는 더 많은 전역 객체를 접하게 될 것이며, Javascript에는 좋은 프로그래밍 언어에 포함되어야 하는 대부분의 기능이 있다는 것을 알게 될 것입니다.

숫자 값

Javascript는 일반적인 산술 연산자(+, -, *, /, < code)를 지원합니다. >%). 예를 들어 다음 코드는

function outerFunction(arg){  var variableInOuterFunction = arg;  function bar(){console.log(variableInOuterFunction);
  }

  bar();
}

outerFunction(&#39;hello closure!&#39;);   // hello closure!
로그인 후 복사
로그인 후 복사

Boolean value

🎜Boolean 값에는 truefalse가 포함됩니다. 변수에 true 또는 false 값을 할당하고 해당 변수에 대해 부울 연산을 수행할 수 있습니다. 예를 들어 다음 코드는 🎜
function outerFunction(arg){  var variableInOuterFunction = arg;  return function(){console.log(variableInOuterFunction);
  }
}var innerFunction = outerFunction(&#39;hello closure!&#39;);

innerFunction(); // hello closure!
로그인 후 복사
로그인 후 복사
🎜Array🎜🎜Javascript에서는 []를 통해 배열을 생성할 수 있습니다. 배열 객체에는 다음 코드에 표시된 것처럼 유용한 함수가 많이 포함되어 있습니다. 🎜
function longRunningOperation(callback){
  setTimeout(callback, 3000);
}function UserClicked(){  console.log(&#39;starting a long operation&#39;);
  longRunningOperation(function(){      console.log(&#39;ending a long operation&#39;);
  })
}
UserClicked();
로그인 후 복사
로그인 후 복사
🎜객체 리터럴🎜🎜객체 리터럴 {}는 일반적으로 다음 코드에 표시된 것처럼 Javascript에서 객체를 생성하는 데 사용됩니다. 🎜
function longRunningOperation(callback){
  setTimeout(callback, 3000);
}function webRequest(request){  console.log(&#39;starting a long operation for request:&#39;, request.id);
  longRunningOperation(function(){console.log(&#39;ending a long operation for request:&#39;, request.id);
  });
}

webRequest({id: 1});
webRequest({id: 2});

//输出
//starting a long operation for request: 1//starting a long operation for request: 2//ending a long operation for request: 1//ending a long operation for request: 2
로그인 후 복사
로그인 후 복사
🎜 위의 코드는 런타임에 객체 속성을 추가합니다. 객체를 생성할 때 객체 속성을 정의할 수도 있습니다. 🎜
console.time(&#39;timer&#39;);
setTimeout(function(){  console.timeEnd(&#39;timer&#39;);  //timer: 1002.615ms
}, 1000)
로그인 후 복사
로그인 후 복사
🎜다음 코드에서 볼 수 있듯이 다른 객체 리터럴은 객체 리터럴에 중첩될 수 있습니다. 🎜
console.time(&#39;timeit&#39;);function fibonacci(n){  if(n<2){return 1;
  }else{return fibonacci(n-2) + fibonacci(n-1);
  }
}
fibonacci(44);console.timeEnd(&#39;timeit&#39;);  //我的电脑耗时 11863.331ms,每台电脑会有差异
로그인 후 복사
로그인 후 복사
🎜물론 객체 리터럴은 배열도 포함될 수 있습니다: 🎜
function fibonacci(n){  if(n<2){return 1;
  }else{return fibonacci(n-2) + fibonacci(n-1);
  }
}console.time(&#39;timer&#39;);
setTimeout(function(){  console.timeEnd(&#39;timer&#39;);  // 输出时间会大于 1000ms
}, 1000)

fibonacci(44);
로그인 후 복사
로그인 후 복사
🎜배열은 객체 리터럴도 포함할 수 있습니다. 🎜
var foo;console.log(foo);  //undefined
로그인 후 복사
로그인 후 복사
🎜Function🎜🎜Javascript 함수는 일련의 예제를 통해 점차적으로 이해하게 될 것입니다. 🎜일반적인 Javascript 함수 구조는 다음과 같습니다. 🎜
var foo = {bar: 123};
console.log(foo.bar); // 123
console.log(foo.bas); // undefined
로그인 후 복사
로그인 후 복사
🎜Javascript의 모든 함수에는 반환 값이 있습니다. 명시적인 반환 문이 없으면 함수는 정의되지 않음을 반환합니다. 예를 들어 다음 코드는 다음과 같습니다. 🎜
console.log(5 == &#39;5&#39;); // true
console.log(5 === &#39;5&#39;); // false
로그인 후 복사
로그인 후 복사

즉시 함수 실행

🎜함수를 정의한 후 즉시 실행하고 괄호 ()를 통해 함수를 래핑하고 호출합니다. 다음 코드와 같이 🎜
function printableMessage(){  var message = &#39;hello&#39;;  function setMessage(newMessage){if(!newMessage) throw new Error(&#39;cannot set empty message&#39;);
    message = newMessage;
  }  function getMessage(){return message;
  }  function printMessage(){
    console.log(message);
  }  return {
    setMessage: setMessage,
    getMessage: getMessage,
    printMessage: printMessage
  };
}var awesome1 = printableMessage();
awesome1.printMessage(); //hellovar awesome2 = printableMessage();
awesome2.setMessage(&#39;hi&#39;);
awesome2.printMessage(); // hi

awesome1.printMessage(); //hello
로그인 후 복사
로그인 후 복사
🎜즉시 실행 기능이 나타나는 이유는 새로운 변수 범위를 생성하기 위해서입니다. if, else, while은 다음 코드에 표시된 것처럼 새 변수 범위를 생성하지 않습니다. 🎜
var foo = {  bar: 123,  bas: function(){console.log(&#39;inside this.bar is: &#39;, this.bar);
  }
}console.log(&#39;foo.bar is:&#39;, foo.bar); //foo.bar is: 123
foo.bas(); //inside this.bar is: 123
로그인 후 복사
로그인 후 복사
🎜Javascript에서는 함수를 전달합니다. 예를 들어 즉시 실행 함수를 사용하여 새 변수 범위를 만듭니다. 🎜
function foo(){  console.log(&#39;is this called from globals? : &#39;, this === global); //true
}
foo();
로그인 후 복사
로그인 후 복사
🎜 위 코드에서는 함수에 이름을 지정하지 않았으며 이를 익명 함수라고 합니다. 🎜

익명 함수

🎜이름이 없는 함수를 익명 함수라고 합니다. Javascript에서는 함수를 변수에 할당할 수 있습니다. 함수를 변수로 사용하려는 경우 함수 이름을 지정할 필요가 없습니다. 두 가지 동등한 작성 방법이 아래에 나와 있습니다. 🎜
var foo = {  bar: 123
};function bas(){  if(this === global){console.log(&#39;called from global&#39;);
  }  if(this === foo){console.log(&#39;called from foo&#39;);
  }
}//指向global
bas(); //called from global//指向foo
foo.bas = bas;
foo.bas(); //called from foo
로그인 후 복사
로그인 후 복사
🎜프로그래밍 언어가 함수를 변수로 처리할 수 있다면 이는 훌륭한 프로그래밍 언어이며 Javascript가 이를 달성했다고 합니다. 🎜

고차 함수

🎜Javascript를 사용하면 함수를 변수에 할당할 수 있으므로 함수를 매개변수로 다른 함수에 전달할 수 있습니다. 함수를 인수로 취하는 함수를 고차 함수라고 합니다. setTimeout은 일반적인 고차 함수입니다. 🎜
function foo(){  this.foo = 123;
  console.log(&#39;Is this global? : &#39;, this == global);
}

foo(); // Is this global? : true
console.log(global.foo); //123var newFoo = new foo(); //Is this glocal ? : false
console.log(newFoo.foo); //123
로그인 후 복사
로그인 후 복사
🎜Node.js에서 위 코드를 실행하면 2초 후에 정보를 출력하는 명령창이 나옵니다. 위 코드에서는 setTimeout의 첫 번째 매개변수로 익명 함수를 전달했습니다. 일반 함수를 전달할 수도 있습니다: 🎜
var foo ={};
foo._proto_.bar = 123;
console.log(foo.bar); //123
로그인 후 복사
로그인 후 복사
🎜 이제 객체 리터럴과 함수에 대해 배웠으므로 클로저의 개념에 대해 알아 보겠습니다. 🎜🎜클로저🎜🎜클로저는 다른 함수 내부의 변수에 액세스할 수 있는 함수입니다. 함수 내부에 다른 함수를 정의하면 내부 함수가 외부 함수의 변수에 액세스할 수 있습니다. 이는 일반적인 클로저 형태입니다. 몇 가지 예를 들어 설명하겠습니다. 🎜아래 코드에서는 내부 함수가 외부 함수의 변수에 액세스할 수 있음을 확인할 수 있습니다. 🎜
function outerFunction(arg){  var variableInOuterFunction = arg;  function bar(){console.log(variableInOuterFunction);
  }

  bar();
}

outerFunction(&#39;hello closure!&#39;);   // hello closure!
로그인 후 복사
로그인 후 복사

令人惊喜的是:内部函数在外部函数返回之后依然可以访问外部函数作用域中的变量。这是因为,变量仍然被绑定于内部函数,不依赖于外部函数。例如:

function outerFunction(arg){  var variableInOuterFunction = arg;  return function(){console.log(variableInOuterFunction);
  }
}var innerFunction = outerFunction(&#39;hello closure!&#39;);

innerFunction(); // hello closure!
로그인 후 복사
로그인 후 복사

现在,我们已经了解了闭包,接下来,我们会探究一下使Javascript成为一门适合服务器端编程的语言的原因。

Node.js性能

Node.js致力于开发高性能应用程序。接下来的部分,我们会介绍大规模I/O问题,并分别展示传统方式及Node.js是如何解决这个问题的。

大规模I/O问题

大多数Web应用通过硬盘或者网络(例如查询另一台机器的数据库)获取数据,从硬盘或网络获取数据的速度远远慢于CPU的处理周期。当收到一个HTTP请求以后,我们需要从数据库获取数据,请求会一直等待直到获取数据完成。这些创建的连接和还未结束的请求会消耗服务器的资源(内存和CPU)。为了使同一台Web服务器能够处理大规模请求,我们需要解决大规模I/O问题。

每一个请求创建一个进程

传统的Web服务器为每一个请求创建一个新的进程,这是一种对内存和CPU开销都很昂贵的操作。PHP最开始就是采用的这种方法。在等待响应期间,进程仍然会消耗资源,并且进程的创建更慢。所以现代Web应用大多使用线程池的方法。

线程池

现代Web服务器使用线程池来处理每个请求。线程和进程相比,更加轻量级。在创建线程池以后,我们就不再需要为开始或结束进程而付出额外代价。当收到一个请求,我们为它分配一个线程。然而,线程池仍然会浪费一些资源。

单线程模式

我们知道为请求分别创建进程或者线程会导致系统资源浪费。与之相对,Node.js采取了单线程来处理请求。单线程服务器的性能优于线程池服务器的理念并不是Node.js首创,Nginx也是基于这种理念。Nginx是一种单线程服务器,能够处理极大数量的并发请求。
Javascript是单线程的,如果你有一个耗时操作(例如网络请求),就必须使用回调。下面的代码使用setTimeout模拟了一个耗时操作,可以用Node.js执行。

function longRunningOperation(callback){
  setTimeout(callback, 3000);
}function UserClicked(){  console.log(&#39;starting a long operation&#39;);
  longRunningOperation(function(){      console.log(&#39;ending a long operation&#39;);
  })
}
UserClicked();
로그인 후 복사
로그인 후 복사

让我们模拟一下Web请求:

function longRunningOperation(callback){
  setTimeout(callback, 3000);
}function webRequest(request){  console.log(&#39;starting a long operation for request:&#39;, request.id);
  longRunningOperation(function(){console.log(&#39;ending a long operation for request:&#39;, request.id);
  });
}

webRequest({id: 1});
webRequest({id: 2});

//输出
//starting a long operation for request: 1//starting a long operation for request: 2//ending a long operation for request: 1//ending a long operation for request: 2
로그인 후 복사
로그인 후 복사

更多的Node.js细节

Node.js的核心是一个event loopevent loop使得任何用户图形界面应用程序可以在任何操作系统中工作。当事件被触发时(例如:用户点击鼠标),操作系统调用程序的某个函数,程序执行函数中的代码。之后,程序准备响应已经在队列中的事件或尚未出现的事件。

线程饥饿

通常,在GUI程序中,当由一个事件调用的函数执行期间,其它事件不会被处理。因此,当你在相关函数中执行耗时操作时,GUI会变得无响应。这种CPU资源的短缺被成为饥饿
Node.js基于和GUI应用程序相同的event loop原则。因此,它也会面临饥饿的问题。为了帮助更好的理解,我们通过几个例子来说明:

console.time(&#39;timer&#39;);
setTimeout(function(){  console.timeEnd(&#39;timer&#39;);  //timer: 1002.615ms
}, 1000)
로그인 후 복사
로그인 후 복사

运行这段代码,与我们期望的相同,终端显示的数字在1000ms左右。
接下来我们想写一段耗时更长的代码,例如一个未经优化的计算Fibonacci数列的方法:

console.time(&#39;timeit&#39;);function fibonacci(n){  if(n<2){return 1;
  }else{return fibonacci(n-2) + fibonacci(n-1);
  }
}
fibonacci(44);console.timeEnd(&#39;timeit&#39;);  //我的电脑耗时 11863.331ms,每台电脑会有差异
로그인 후 복사
로그인 후 복사

现在我们可以模拟Node.js的线程饥饿。setTimeout用于在指定的时间以后调用函数,如果我们在函数调用以前,执行一个耗时方法,由于耗时方法占用CPU和Javascript线程,setTimeout指定的函数无法被及时调用,只能等待耗时方法运行结束以后被调用。例如下面的代码:

function fibonacci(n){  if(n<2){return 1;
  }else{return fibonacci(n-2) + fibonacci(n-1);
  }
}console.time(&#39;timer&#39;);
setTimeout(function(){  console.timeEnd(&#39;timer&#39;);  // 输出时间会大于 1000ms
}, 1000)

fibonacci(44);
로그인 후 복사
로그인 후 복사

所以,如果你面临CPU密集型场景,Node.js并不是最佳选择,但也很难找到其它合适的平台。但是Node.js非常适用于I/O密集型场景。

数据密集型应用

Node.js适用于I/O密集型。单线程机制意味着Node.js作为Web服务器会占用更少的内存,能够支持更多的请求。与执行代码相比,从数据库获取数据需要花费更多的时间。下图展示了传统的线程池模型的服务器是如何处理用户请求的:


Node.js服务器处理请求的方式如下图。因为所有的工作都在单线程内完成,所以消耗更少的内存,同时因为不需要切换线程,所以CPU负载更小。

V8 Javascript引擎

Node.js中的所有Javascript通过V8 Javascript引擎执行。V8产生于谷歌Chrome项目,V8在Chrome中用于运行Javascript。V8不仅速度更快,而且很容易被集成到其它项目。

更多的Javascript

精通Javascript使得Node.js开发者不仅能够写出更加容易维护的项目,而且能够利用到Javascript生态链的优势。

默认值

Javascript变量的默认值是undefined。如下列代码所示:

var foo;console.log(foo);  //undefined
로그인 후 복사
로그인 후 복사

变量不存在的属性也会返回undefined

var foo = {bar: 123};
console.log(foo.bar); // 123
console.log(foo.bas); // undefined
로그인 후 복사
로그인 후 복사

全等

需要注意Javascript当中 =====的区别。==会对变量进行类型转换,===不会。推荐的用法是总是使用===

console.log(5 == &#39;5&#39;); // true
console.log(5 === &#39;5&#39;); // false
로그인 후 복사
로그인 후 복사

null

null是一个特殊的Javascript对象,用于表示空对象。而undefined用于表示变量不存在或未初始化。我们不需要给变量赋值为undefined,因为undefined是变量的默认值。

透露模块模式

透露模块模式的关键在于Javascript对闭包的支持以及能够返回任意对象的能力。如下列代码所示:

function printableMessage(){  var message = &#39;hello&#39;;  function setMessage(newMessage){if(!newMessage) throw new Error(&#39;cannot set empty message&#39;);
    message = newMessage;
  }  function getMessage(){return message;
  }  function printMessage(){
    console.log(message);
  }  return {
    setMessage: setMessage,
    getMessage: getMessage,
    printMessage: printMessage
  };
}var awesome1 = printableMessage();
awesome1.printMessage(); //hellovar awesome2 = printableMessage();
awesome2.setMessage(&#39;hi&#39;);
awesome2.printMessage(); // hi

awesome1.printMessage(); //hello
로그인 후 복사
로그인 후 복사

理解this

this总是指向调用函数的对象。例如:

var foo = {  bar: 123,  bas: function(){console.log(&#39;inside this.bar is: &#39;, this.bar);
  }
}console.log(&#39;foo.bar is:&#39;, foo.bar); //foo.bar is: 123
foo.bas(); //inside this.bar is: 123
로그인 후 복사
로그인 후 복사

由于函数basfoo对象调用,所以this指向foo。如果是纯粹的函数调用,则this指向全局变量。例如:

function foo(){  console.log(&#39;is this called from globals? : &#39;, this === global); //true
}
foo();
로그인 후 복사
로그인 후 복사

如果我们在浏览器中执行上面的代码,全局变量global会变为window
如果函数的调用对象改变,this的指向也会改变:

var foo = {  bar: 123
};function bas(){  if(this === global){console.log(&#39;called from global&#39;);
  }  if(this === foo){console.log(&#39;called from foo&#39;);
  }
}//指向global
bas(); //called from global//指向foo
foo.bas = bas;
foo.bas(); //called from foo
로그인 후 복사
로그인 후 복사

如果通过new操作符调用函数,函数内的this会指向由new创建的对象。

function foo(){  this.foo = 123;
  console.log(&#39;Is this global? : &#39;, this == global);
}

foo(); // Is this global? : true
console.log(global.foo); //123var newFoo = new foo(); //Is this glocal ? : false
console.log(newFoo.foo); //123
로그인 후 복사
로그인 후 복사

通过上面代码,我们可以看到,在通过new调用函数时,函数内的this指向发生改变。

理解原型

Javascript通过new操作符及原型属性可以模仿面向对象的语言。每个Javascript对象都有一个被称为原型的内部链接指向其他对象。
当我们调用一个对象的属性,例如:foo.bar,Javascript会检查foo对象是否存在bar属性,如果不存在,Javascript会检查bar属性是否存在于foo._proto_,以此类推,直到对象不存在_proto_。如果在任何层级发现属性的值,则立即返回,否则,返回undefined

var foo ={};
foo._proto_.bar = 123;
console.log(foo.bar); //123
로그인 후 복사
로그인 후 복사

当我们通过new操作符创建对象时,对象的_proto_会被赋值为函数的prototype属性,例如:

function foo(){};
foo.prototype.bar = 123;var bas = new foo();console.log(bas._proto_ === foo.prototype); //trueconsole.log(bas.bar);
로그인 후 복사

函数的所有实例共享相同的prototype

function foo(){};
foo.prototype.bar = 123;

var bas = new foo();
var qux = new foo();
console.log(bas.bar); //123
console.log(qux.bar); //123

foo.prototype.bar = 456;
console.log(bas.bar); //456
console.log(qux.bar); //456
로그인 후 복사

只有当属性不存在时,才会访问原型,如果属性存在,则不会访问原型。

function foo(){};
foo.prototype.bar = 123;var bas = new foo();var qux = new foo();

bas.bar = 456;console.log(bas.bar);//456console.log(qux.bar); //123
로그인 후 복사

上面的代码表明,如果修改了bas.bar, bas._proto_.bar就不再被访问。

错误处理

Javascript的异常处理机制类似其它语言,通过throw关键字抛出异常,通过catch关键字捕获异常。例如:

try{
  console.log(&#39;About to throw an error&#39;);  throw new Error(&#39;Error thrown&#39;);
}
catch(e){
  console.log(&#39;I will only execute if an error is thrown&#39;);
  console.log(&#39;Error caught: &#39;, e.message);
}finally{
  console.log(&#39;I will execute irrespective of an error thrown&#39;);
}
로그인 후 복사

总结

本章,我们介绍了一些Node.js及Javascript的重要概念,知道了Node.js适用于开发数据密集型应用程序。下章我们将开始介绍如何使用Node.js开发应用程序。


위 내용은 Node.js가 무엇인지 이해하시나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿