Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
這部分示例將致力于用 Node.js 模擬一個(gè)類似于 Apache 的 Web 服務(wù)器,處理瀏覽器端的請(qǐng)求,將相關(guān)的頁(yè)面響應(yīng)給瀏覽器。首先,我們要在code目錄下執(zhí)行mkdir 03_webSever命令來(lái)創(chuàng)建用于存放這一組示例的目錄。然后執(zhí)行以下步驟:
1、index.htm:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>首頁(yè)</title>
</head>
<body>
<h1>你好,nodejs!</h1>
<p> <a href="login.htm">請(qǐng)登錄!</a> </p>
</body>
</html>
2、login.htm:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>登錄頁(yè)面</title>
</head>
<body>
<h1>你已經(jīng)登錄。。。</h1>
<p> <a href="index.htm">回首頁(yè)!</a> </p>
</body>
</html>
3、style.css:
body {
background: gray;
}
2、在code/03_webSever目錄下執(zhí)行touch 03-webServer.js命令,創(chuàng)建腳本文件,并輸入如下代碼:
const http = require('http')
const fs = require('fs')
const server = http.createServer()
server.on('request', function(req, res) {
const webRoot = './www'
const url = req.url
if ( url === '/' ) {
url = '/index.htm'
}
fs.readFile(webRoot+url, function(err, data) {
if ( err !== null ) {
console.error('錯(cuò)誤信息:' + err.message)
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
res.end(data)
})
})
server.listen(8080, function(){
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
3、保存所有文件后,在code/03_webSever目錄下執(zhí)行node 03-webServer.js命令,然后打開瀏覽器并訪問http://localhost:8080/,就會(huì)看到如下頁(yè)面:
這一部分本示例將以生成個(gè)人信息頁(yè)面為例,演示在服務(wù)器端基于 Node.js 使用art-template模板引擎來(lái)生成網(wǎng)頁(yè)。為此,我們需要在code目錄下執(zhí)行mkdir 04_templatingEngine命令來(lái)創(chuàng)建用于存放這一組示例的目錄。
首先來(lái)示范一下如何使用art-template模版引擎的渲染單一模版文件,請(qǐng)跟著以下步驟來(lái)構(gòu)建示例:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>{{ name }}的個(gè)人信息</title>
</head>
<body>
<h1>{{ name }}的個(gè)人信息</h1>
<table>
<tr><td>姓名:</td><td>{{ name }}</td></tr>
<tr><td>年齡:</td><td>{{ age }}</td></tr>
<tr><td>性別:</td><td>{{ sex }}</td></tr>
<tr>
<td>愛好:</td>
<td>{{ each items }} {{ $value }} {{ /each }}</td>
</tr>
</table>
</body>
</html>
3、在code/04_templatingEngine目錄下執(zhí)行touch 04-useTemplating_engine.js命令,創(chuàng)建一個(gè)腳本文件,具體如下:
const http = require('http')
const fs = require('fs')
const template = require('art-template')
class human {
constructor(name, age, sex, items=[])
{
this.name = name
this.age = age
this.sex = sex
this.items = items
}
}
const server = http.createServer()
server.on('request', function(req, res){
const url = req.url
let boy = null
if ( url === '/' ) {
boy = new human('凌杰', '37', '男', ['看書', '看電影','旅游'])
} else if ( url === '/wang' ) {
boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作'])
}
if ( boy === null ) {
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
fs.readFile('./singleTpl.htm', function(err, data){
if ( err !== null ) {
return res.end('<h1>404 沒找到模版文件!</h1>')
}
const strHtml = template.render(data.toString(), {
name : boy.name,
age : boy.age,
sex : boy.sex,
items: boy.items
})
res.end(strHtml)
})
})
server.listen(8080, function(){
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
4、保存所有文件后,在code/04_templatingEngine目錄下執(zhí)行node 04-useTemplating_engine.js命令,然后打開瀏覽器并訪問http://localhost:8080/wang,就會(huì)看到如下頁(yè)面:
在同一 Web 應(yīng)用中,所有的頁(yè)面通常都由相同的頭部和底部元素,所以為了減少代碼的冗余,提高重用率,開發(fā)者們通常會(huì)考慮將重復(fù)的部分獨(dú)立成一個(gè)單獨(dú)的模版文件,然后用相互包含的方式組合成頁(yè)面。下面就繼續(xù)以art-template模板引擎為例來(lái)演示一下如何將多個(gè)模版組合渲染成單一的 HTML 頁(yè)面,其具體步驟如下:
1、tpl1.art :
<header>
<h1>查看個(gè)人信息</h1>
<br>
</header>
2、tpl2.art :
<footer>
<div>
<p>? 2016 owlman.org;本站系純HTML5站點(diǎn)。</p>
</div>
</footer>
2、在code/04_templatingEngine目錄下執(zhí)行touch multiTpl.htm命令創(chuàng)建用于組合的 HTML 頁(yè)面文件,并在其中輸入以下代碼:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>查看個(gè)人信息</title>
</head>
<body>
{{ include './tpl1.art' }}
<h2>{{ name }}的個(gè)人信息</h2>
<table>
<tr><td>姓名:</td><td>{{ name }}</td></tr>
<tr><td>年齡:</td><td>{{ age }}</td></tr>
<tr><td>性別:</td><td>{{ sex }}</td></tr>
<tr>
<td>愛好:</td>
<td>{{ each items }} {{ $value }} {{ /each }}</td>
</tr>
</table>
{{ include './tpl2.art' }}
</body>
</html>
3、在code/04_templatingEngine目錄下執(zhí)行
cp 04-useTemplating_engine.js 04-useTemplating_engine2.js命令,將之前的代碼復(fù)制一份,并修改如下:
const http = require('http')
const fs = require('fs')
const template = require('art-template')
template.defaults.root = __dirname // 配置模版的查找根目錄
class human {
constructor(name, age, sex, items=[])
{
this.name = name
this.age = age
this.sex = sex
this.items = items
}
}
const server = http.createServer()
server.on('request', function(req, res){
const url = req.url
let boy = null
if ( url === '/' ) {
boy = new human('凌杰', '37', '男', ['看書', '看電影','旅游'])
} else if ( url === '/wang' ) {
boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作'])
}
if ( boy === null ) {
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
fs.readFile('./multiTpl.htm', function(err, data){ // 修改了要讀取的模版文件
if ( err !== null ) {
return res.end('<h1>404 沒找到模版文件!</h1>')
}
const strHtml = template.render(data.toString(), {
name : boy.name,
age : boy.age,
sex : boy.sex,
items: boy.items
})
res.end(strHtml)
})
})
server.listen(8080, function(){
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
4、保存所有文件后,在code/04_templatingEngine目錄下執(zhí)行node 04-useTemplating_engine2.js命令,然后打開瀏覽器并訪問http://localhost:8080,就會(huì)看到如下頁(yè)面:
當(dāng)然,如果重復(fù)的元素只有頭部和尾部的話,有時(shí)候使用模版繼承語(yǔ)法來(lái)渲染頁(yè)面會(huì)是一個(gè)更好的選擇,下面就來(lái)繼續(xù)演示一下art-template模板引擎的繼承語(yǔ)法來(lái)渲染 HTML 頁(yè)面,其具體步驟如下:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title>{{ name }}的個(gè)人信息</title>
</head>
<body>
<header>
<h1>查看個(gè)人信息</h1>
<br>
</header>
{{ block 'message' }}
{{ /block }}
<footer>
<div>
<p>? 2016 owlman.org;本站系純HTML5站點(diǎn)。</p>
</div>
</footer>
</body>
</html>
2、在code/04_templatingEngine目錄下執(zhí)行touch extendTpl.htm命令,創(chuàng)建子模版文件,然后在該文件中輸入以下代碼:
{{ extend 'baseTpl.art' }}
{{ block 'message' }}
<h1>{{ name }}的個(gè)人信息</h1>
<table>
<tr><td>姓名:</td><td>{{ name }}</td></tr>
<tr><td>年齡:</td><td>{{ age }}</td></tr>
<tr><td>性別:</td><td>{{ sex }}</td></tr>
<tr>
<td>愛好:</td>
<td>{{ each items }} {{ $value }} {{ /each }}</td>
</tr>
</table>
{{ /block }}
3、在code/04_templatingEngine目錄下執(zhí)行cp 04-useTemplating_engine.js 04-useTemplating_engine3.js命令,將之前的代碼復(fù)制一份,并修改如下:
// 用Node.js生成動(dòng)態(tài)頁(yè)面
// 作者:owlman
// 時(shí)間:2019年07月12日
const http = require('http')
const fs = require('fs')
const template = require('art-template')
template.defaults.root = __dirname
class human {
constructor(name, age, sex, items=[])
{
this.name = name
this.age = age
this.sex = sex
this.items = items
}
}
const server = http.createServer()
server.on('request', function(req, res) {
const url = req.url
let boy = null
if (url === '/') {
boy = new human('凌杰', '37', '男', ['看書', '看電影','旅游'])
} else if (url === '/wang') {
boy = new human('蔓兒', '25', '女', ['看書', '看電影','寫作'])
}
if (boy === null) {
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
fs.readFile('./extendTpl.htm', function(err, data) {
if ( err !== null ) {
return res.end('<h1>404 沒找到模版文件!</h1>')
}
const strHtml = template.render(data.toString(), {
name : boy.name,
age : boy.age,
sex : boy.sex,
items: boy.items
})
res.end(strHtml)
})
})
server.listen(8080, function(){
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
4、保存所有文件后,在code/04_templatingEngine目錄下執(zhí)行node 04-useTemplating_engine3.js命令,然后打開瀏覽器并訪問http://localhost:8080,就會(huì)看到與之前相同的頁(yè)面。
這一部分示例將致力于演示用 Node.js 處理 Web 表單,我們將會(huì)分別示范如何用get和post兩種方法來(lái)處理表單的請(qǐng)求。首先,我們要在code目錄下執(zhí)行mkdir 05_webForm命令來(lái)創(chuàng)建用于存放這一組示例的目錄。
先用一個(gè)信息查詢程序來(lái)演示一下如何處理使用get方法來(lái)發(fā)送請(qǐng)求的表單。首先,在code/05_webForm目錄下執(zhí)行mkdir get_form命令,并執(zhí)行以下步驟:
在code/05_webForm/get_form目錄下執(zhí)行npm install art-template命令,將art-template安裝到當(dāng)前示例項(xiàng)目中。
在code/05_webForm/get_form目錄下執(zhí)行touch index.htm,創(chuàng)建一個(gè)模版文件,具體如下: <!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>個(gè)人信息查詢</title>
</head>
<body>
<h1>個(gè)人信息查詢</h1>
<form action="/query" method="GET">
<label for="message">請(qǐng)輸入要查詢的姓名:</label>
<input type="text" name="qname" />
<input type="submit" value="查詢" />
</form>
<br />
{{ if name }}
<table>
<caption>{{ name }}的個(gè)人信息</caption>
<tr><td>姓名:</td><td>{{ name }}</td></tr>
<tr><td>年齡:</td><td>{{ age }}</td></tr>
<tr><td>性別:</td><td>{{ sex }}</td></tr>
<tr>
<td>愛好:</td>
<td>{{ each items }} {{ $value }} {{ /each }}</td>
</tr>
</table>
{{ else if query_error }}
<h2>沒有找到相關(guān)信息!</h2>
{{ /if }}
</body>
</html>
3、在code/05_webForm/get_form目錄下執(zhí)行touch app.js,創(chuàng)建一個(gè)腳本文件,具體如下: const http = require('http')
const fs = require('fs')
const url = require('url')
const template = require('art-template')
class human {
constructor(name, age, sex, items=[])
{
this.name = name
this.age = age
this.sex = sex
this.items = items
}
}
const db = [
new human('凌杰', '37', '男', ['看書', '看電影','旅游']),
new human('蔓兒', '25', '女', ['看書', '看電影','寫作']),
new human('張語(yǔ)', '32', '女', ['看書', '旅游','繪畫'])
]
const server = http.createServer(function(req, res){
const query = url.parse(req.url, true)
let obj = null
let query_error = false
if ( query.pathname === '/' ) {
query_error = false
}
else if (query.pathname === '/query') {
for(let i = 0; i < db.length; ++i) {
if (db[i].name == query.query["qname"]) {
obj = db[i]
}
}
if ( obj === null ) {
query_error = true
}
} else {
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
fs.readFile('./index.htm', function(err, data){
if ( err !== null ) {
return res.end('<h1>404 沒找到模版文件!</h1>')
}
let strHtml = null
if ( obj !== null ) {
strHtml = template.render(data.toString(), {
name : obj.name,
age : obj.age,
sex : obj.sex,
items: obj.items,
query_error: query_error
})
} else {
strHtml = template.render(data.toString(), {
name : false,
query_error: query_error
})
}
res.end(strHtml)
})
})
server.listen(8080, function() {
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
4、保存所有文件后,在code/05_webForm/get_form目錄下執(zhí)行node app.js命令,結(jié)果如下:
先來(lái)演示如何處理使用post方法來(lái)發(fā)送請(qǐng)求的表單。首先,在code/05_webForm目錄下執(zhí)行mkdir post_form命令,并執(zhí)行以下步驟:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>個(gè)人信息管理</title>
</head>
<body>
<h1>個(gè)人信息管理</h1>
<table>
<caption>個(gè)人數(shù)據(jù)表</caption>
<tr><th>姓名</th><th>年齡</th><th>性別</th><th>愛好</th></tr>
{{ each db }}
<tr>
<td>{{ $value.name }} </td>
<td>{{ $value.age }} </td>
<td>{{ $value.sex }} </td>
<td>{{ each $value.items }} {{ $value }} {{ /each }}</td>
</tr>
{{ /each }}
</table>
<form action="/add" method="POST">
<table>
<caption>錄入新人員</caption>
<tr><td>姓名:</td><td><input type="text" name="uname" /></td></tr>
<tr><td>年齡:</td><td><input type="text" name="age"></td></tr>
<tr><td>性別:</td><td><input type="text" name="sex"></td></tr>
<tr><td>愛好:</td><td><input type="text" name="items"></td></tr>
</table>
<input type="submit" value="添加" />
</form>
</body>
</html>
3、在code/05_webForm/post_form目錄下執(zhí)行touch app.js,創(chuàng)建一個(gè)腳本文件,具體如下:
const http = require('http')
const fs = require('fs')
const url = require('url')
const querystring = require('querystring')
const template = require('art-template')
class human {
constructor(name, age, sex, items=[])
{
this.name = name
this.age = age
this.sex = sex
this.items = items
}
}
const db = [
new human('凌杰', '37', '男', ['看書', '看電影','旅游']),
new human('蔓兒', '25', '女', ['看書', '看電影','寫作']),
new human('張語(yǔ)', '32', '女', ['看書', '旅游','繪畫'])
]
const server = http.createServer(function(req, res){
const query = url.parse(req.url, true)
if ( query.pathname === '/' ) {
fs.readFile('./index.htm', function(err, data) {
if ( err !== null ) {
return res.end('<h1>404 沒找到模版文件!</h1>')
}
const strHtml = template.render(data.toString(), {
"db": db
})
res.end(strHtml)
})
}
else if ( query.pathname === '/add' ) {
req.on('data', function(chunk) {
const obj = querystring.parse(chunk.toString())
db.push(new human(
obj['uname'],
obj['age'],
obj['sex'],
obj['items'].split(','),
))
})
res.writeHead(302, {
'location': `/`
})
res.end()
} else {
return res.end('<h1>404 頁(yè)面沒找到!</h1>')
}
})
server.listen(8080, function(){
console.log('請(qǐng)?jiān)L問http://localhost:8080/,按Ctrl+C終止服務(wù)!')
})
4、保存所有文件后,在code/05_webForm/post_form目錄下執(zhí)行node app.js命令,結(jié)果如下:
毒來(lái)了,程序員也要學(xué)習(xí)啊!何況你的電腦還沒中病毒!
以JavaScript和V8引擎為核心,事件驅(qū)動(dòng)架構(gòu)和可擴(kuò)展性開箱即用,Node.js已經(jīng)快速成為創(chuàng)建Web應(yīng)用和SaaS產(chǎn)品的新事實(shí)標(biāo)準(zhǔn)。許多框架,如Express,Sails和Socket.IO,使程序員能夠只關(guān)注業(yè)務(wù)邏輯,無(wú)需考慮其他問題。
當(dāng)然,Node.js目前的普及度遠(yuǎn)低于JavaScript。JavaScript支持許多不同風(fēng)格的編程方式,包括函數(shù)式編程,程序編程和面向?qū)ο缶幊蹋试S程序員靈活運(yùn)用各種編程風(fēng)格。
但JavaScript是把雙刃劍,JavaScript的多重性質(zhì)意味著幾乎一切都是可變的。因此,在編寫Node.js代碼時(shí),程序員無(wú)法清除對(duì)象和范圍突變的概率。因?yàn)镴avaScript缺少尾調(diào)用優(yōu)化(允許遞歸函數(shù)重用堆棧幀進(jìn)行遞歸調(diào)用),所以使用遞歸進(jìn)行大量迭代是很危險(xiǎn)的。除了這些陷阱之外,Node.js是單線程的,因此開發(fā)人員必須編寫異步代碼。
下面我將分享編寫高效和可擴(kuò)展Node.js代碼最重要的10個(gè)JavaScript概念:
1、立即調(diào)用函數(shù)表達(dá)式
一個(gè)立即調(diào)用的函數(shù)表達(dá)式(IIFE)是一個(gè)在創(chuàng)建時(shí)可立即執(zhí)行的函數(shù)。它與任何事件或異步執(zhí)行無(wú)關(guān)。您可以定義一個(gè)IIFE,如下所示:
第一對(duì)括號(hào)function(){...}將括號(hào)內(nèi)的代碼轉(zhuǎn)換為表達(dá)式。第二對(duì)括號(hào)調(diào)用表達(dá)式生成的函數(shù)。IIFE也可以被描述為一個(gè)自我調(diào)用的匿名函數(shù),最常見的用法是限制通過(guò)var或者封裝上下文變量的范圍,以避免名稱沖突。
2、閉包
JavaScript中的閉包是內(nèi)部函數(shù),即使在外部函數(shù)返回控件后也可以訪問其外部函數(shù)的作用域。閉包使內(nèi)部函數(shù)的變量為私有,一個(gè)簡(jiǎn)單例子如下所示:
count變量分配了一個(gè)外部函數(shù),外部函數(shù)只運(yùn)行一次,將計(jì)數(shù)器設(shè)置為零并返回內(nèi)部函數(shù)。 _counter變量只能由內(nèi)部函數(shù)訪問,這樣就可以像私有變量一樣運(yùn)行。
3、Prototype
每個(gè)JavaScript函數(shù)都有一個(gè)用于附加屬性和方法的prototype,此屬性不可枚舉,它允許程序員將方法或成員函數(shù)附加到其對(duì)象。JavaScript僅通過(guò)prototype屬性支持繼承。在繼承對(duì)象的情況下,prototype指向父對(duì)象,將方法附加到函數(shù)的常見方法是使用prototype,如下所示:
4、私有屬性,使用閉包
JavaScript允許程序員使用下劃線前綴定義私有屬性,如上述示例所示。但這可能妨礙用戶直接訪問或修改私有屬性。使用閉包定義私有屬性將解決這個(gè)問題,在對(duì)象本身上定義需要訪問私有屬性的成員函數(shù),可以使用閉包制作私有屬性,如下所示:
5、Module模式
Module模式是JavaScript中最常用的設(shè)計(jì)模式,用于實(shí)現(xiàn)松散耦合,結(jié)構(gòu)良好的代碼。 它允許程序員創(chuàng)建公共和私有兩種訪問級(jí)別,實(shí)現(xiàn)Module模式的一種方式如下所示:
Revealing Module模式類似于Module模式,上述示例使用Revealing Module模式編寫如下:
6、Hoisting
在代碼執(zhí)行之前,JavaScript將變量和函數(shù)聲明移動(dòng)到其范圍頂部。無(wú)論程序員將代碼中的函數(shù)和變量聲明放在哪里,它們都將由解釋器移動(dòng)到其范圍的頂部。這可能是好的,也可能不是。
在執(zhí)行任何代碼之前先處理變量聲明。具有諷刺意味的是,未聲明的變量在賦予值之前不存在,這將導(dǎo)致所有未聲明的變量成為全局變量,雖然函數(shù)聲明已經(jīng)懸掛,但函數(shù)表達(dá)式未被懸停。提升變量和函數(shù)時(shí),JavaScript具有優(yōu)先級(jí)。優(yōu)先級(jí)從上到下依次是可變分配、函數(shù)聲明、變量聲明。為了避免錯(cuò)誤,程序員應(yīng)該在每個(gè)范圍的開始處聲明變量和函數(shù)。
7、Currying
Currying是使函數(shù)更靈活的方法。使用curried函數(shù),程序員可以傳遞函數(shù)期望的所有參數(shù)并獲取結(jié)果,或者只傳遞部分參數(shù),并接收等待其余參數(shù)。一個(gè)簡(jiǎn)單例子如下:
原始功能可以直接將參數(shù)逐個(gè)傳遞給一個(gè)單獨(dú)的括號(hào),如下所示:
8、apply,call和bind方法
任何JavaScript程序員必須了解apply,call和bind之間的區(qū)別。這三個(gè)函數(shù)是相似的,因?yàn)樗鼈兊牡谝粋€(gè)參數(shù)始終要給出調(diào)用該方法函數(shù)的“this”值或上下文。三個(gè)之中,call最簡(jiǎn)單,它與調(diào)用函數(shù)上下文相同。以下是一個(gè)例子:
apply幾乎和call一樣。唯一的區(qū)別是將參數(shù)作為數(shù)組傳遞,而不是單獨(dú)傳遞。數(shù)組在JavaScript中更容易操作,為處理函數(shù)打開了更多可能性。以下是使用apply和call的示例:
bind方法允許將參數(shù)傳遞給函數(shù)而不調(diào)用。返回一個(gè)新的函數(shù),其中的參數(shù)在任何其他參數(shù)前面都是有界限的。例子如下:
9. Memoization
Memoization是一種優(yōu)化技術(shù),可以加快函數(shù)執(zhí)行,并在再次發(fā)生同一組輸入時(shí)返回緩存的結(jié)果。JavaScript對(duì)象的行為就像關(guān)聯(lián)數(shù)組,使JavaScript易于記憶。例如,我們可以將遞歸階乘函數(shù)轉(zhuǎn)換成一個(gè)記憶的階乘函數(shù),如下所示:
10. 方法重載
方法重載允許多個(gè)方法具有相同的名稱但不同的參數(shù)。編譯器或解釋器根據(jù)傳遞的參數(shù)數(shù)量確定要調(diào)用的函數(shù)。JavaScript不直接支持方法重載。但是你可以像下面所示完成一些事情:
當(dāng)你足夠了解Node.js,你會(huì)發(fā)現(xiàn)很多方法可以解決幾乎遇到的所有問題,但一定要采取正確的做法,不然很可能要重寫整個(gè)邏輯。本文中的10個(gè)JavaScript概念是每個(gè)Node.js開發(fā)人員應(yīng)該知道的基礎(chǔ)知識(shí)。但只是冰山一角,希望程序員們可以持續(xù)學(xué)習(xí)。
者按:很多人都在尋找一個(gè)能夠統(tǒng)一編程語(yǔ)言江湖的“老大哥”,戰(zhàn)火也重來(lái)沒有停止過(guò)。Jonny Asmar在hackernoon上發(fā)表了一篇文章指出,因?yàn)镹ode的存在,JavaScript具備了多功能性,已經(jīng)有了坐穩(wěn)“頭把交椅”的勢(shì)頭。文章由36氪編譯。
作者寫在前面的話:這篇文章已經(jīng)引起了大量的反對(duì),因?yàn)楹芏嗳瞬⒉徽J(rèn)為JavaScript是編程語(yǔ)言中的勝利者。
盡管我承認(rèn),我的標(biāo)題可能會(huì)引起爭(zhēng)議,可能會(huì)更加讓人有點(diǎn)擊欲望。但我還是想強(qiáng)調(diào),這篇文章并不是說(shuō)JS是“最好”的語(yǔ)言。
我只是在文章中簡(jiǎn)單地描述了它所覆蓋的領(lǐng)域,以及它能夠讓簡(jiǎn)單的前端開發(fā)人員做更多事情的方法。
在編程的世界里,有一場(chǎng)曠日持久的戰(zhàn)爭(zhēng)。自從計(jì)算機(jī)問世以來(lái),科學(xué)家們一直在尋找一種完美的編程語(yǔ)言。一個(gè)接一個(gè)的新語(yǔ)言被創(chuàng)造出來(lái),以適應(yīng)某種目的。隨著新語(yǔ)言的出現(xiàn),也會(huì)出現(xiàn)新的技術(shù)時(shí)代,新的技術(shù)社區(qū),和大量的開源貢獻(xiàn)。當(dāng)然還會(huì)有不可避免的新的限制。自從在Java應(yīng)用程序和Flash(我曾經(jīng)是Flash開發(fā)者)在互聯(lián)網(wǎng)上長(zhǎng)期占據(jù)主導(dǎo)地位以來(lái),我們已經(jīng)看到有各種各樣的語(yǔ)言的涌現(xiàn),各種各樣的語(yǔ)言毫無(wú)理由的消失,因?yàn)樗鼈円呀?jīng)毫無(wú)用武之地。
世界正在朝著不同的方向前進(jìn)……
那些曾經(jīng)耀眼的新語(yǔ)言現(xiàn)在已經(jīng)過(guò)時(shí)了,開發(fā)者越來(lái)越少,而新的語(yǔ)言也開始制造噪音。
到現(xiàn)在,JavaScript已經(jīng)有幾十年的歷史了。所以,你可能會(huì)想,“它將會(huì)到何處去?”這篇文章其實(shí)不是關(guān)于“JavaScript”語(yǔ)言的。也不會(huì)去討論在它之前許多語(yǔ)言的崛起和衰落。同時(shí),也不是關(guān)于JavaScript是如何“新鮮有光澤”的。
這篇文章是關(guān)于Node的。
真的很有必要,在一開始就區(qū)分這一點(diǎn)。因?yàn)镹ode不只是一種語(yǔ)言。而是一個(gè)生態(tài)系統(tǒng)。
這就是這篇文章的主旨。
不過(guò)也不完全是這樣。我不打算詳細(xì)講述這個(gè)生態(tài)系統(tǒng)是世界上有史以來(lái)最具創(chuàng)新性的開源合作的推動(dòng)者。這是另一個(gè)的話題。
我要說(shuō)明的是,Node是如何通過(guò)遍歷現(xiàn)代編程的五個(gè)關(guān)鍵領(lǐng)域,贏得了一場(chǎng)關(guān)于完美語(yǔ)言的古老戰(zhàn)爭(zhēng)的。
React、Angular和Vue都是當(dāng)今最重要的前端框架。總的來(lái)說(shuō),F(xiàn)acebook,Google和FOSS社區(qū)共同開發(fā)出了一種令人興奮的開發(fā)交互式用戶界面的高效工具。
因此,現(xiàn)在你在網(wǎng)絡(luò)上做的所有事情都是通過(guò)一個(gè)高度互動(dòng)、美觀、易用的界面來(lái)實(shí)現(xiàn)的。這些框架之所以能夠完全實(shí)現(xiàn),完全是因?yàn)镹ode生態(tài)系統(tǒng),你已經(jīng)知道了。
你看,毫無(wú)疑問,JavaScript在前端Web開發(fā)中占據(jù)了主導(dǎo)地位,但React,Angular和Vue已經(jīng)將它提升到了一個(gè)新的高度。
這是用戶界面的時(shí)代。
前端開發(fā)人員不再回避構(gòu)建復(fù)雜的單頁(yè)面Web應(yīng)用程序和完整的軟件套件的時(shí)代。我曾經(jīng)是一名Web開發(fā)人員,現(xiàn)在我是一名軟件開發(fā)人員。
就這樣……JavaScript贏得了Web開發(fā)。
這一部分不僅只是闡述Node在Mobile領(lǐng)域的成功,還將提出另一個(gè)關(guān)鍵問題:
Node是跨平臺(tái)的。
這不僅僅是“哦,酷,它也能在我的手機(jī)上工作!”,也不僅僅是“哇,我的手機(jī)、平板電腦、筆記本電腦和電視都可以使用YouTube!”。
Node跨平臺(tái)的方式是最重要的。對(duì)于開發(fā)者來(lái)說(shuō),這是一個(gè)真正的跨平臺(tái)生態(tài)系統(tǒng)。那些真正建立起“噢,酷”和“哇”的東西的人都喜歡這個(gè)。
React Native只是Node生態(tài)系統(tǒng)中開發(fā)的框架的一個(gè)例子,它以前所未有的方式彌合了前端開發(fā)和移動(dòng)應(yīng)用開發(fā)之間的鴻溝,這是其他任何框架都沒有的。
移動(dòng)開發(fā)的最大壓力一直是Web的拉動(dòng)。但是,通過(guò)React Native和Node生態(tài)系統(tǒng),開發(fā)者可以構(gòu)建一個(gè)兼容Web、iOS和Android的應(yīng)用。沒有其他語(yǔ)言能提供這種多功能性。
就這樣……JavaScript贏得了移動(dòng)開發(fā)。
當(dāng)然,并不是所有的事情都發(fā)生在Web上。桌面應(yīng)用程序?qū)τ谖覀儺?dāng)前這個(gè)依賴技術(shù)的世界的運(yùn)營(yíng)中也至關(guān)重要。
但是,既然Web現(xiàn)在能夠提供功能齊全的應(yīng)用程序,為什么我們還要開發(fā)桌面軟件,并對(duì)其進(jìn)行不同的處理呢?
實(shí)際上,JavaScript趕上桌面端的性能需求,只是個(gè)時(shí)間問題。
所以,Electron誕生了。
當(dāng)然,在桌面編程的時(shí)候,還有更高效的語(yǔ)言可以使用,但對(duì)于我們今天使用的大多數(shù)應(yīng)用程序來(lái)說(shuō),JavaScript已經(jīng)足夠了。
多虧了Cheng Zhao和Github,創(chuàng)建了一個(gè)能夠改變桌面計(jì)算面貌的框架。
Electron不僅讓桌面應(yīng)用程序的開發(fā)變得更加簡(jiǎn)單,而且也能兼容Mac, Windows和Linux,它構(gòu)建的應(yīng)用可在這三個(gè)操作系統(tǒng)上面運(yùn)行。
雖然Windows仍然是當(dāng)今最普及的操作系統(tǒng),Mac的穩(wěn)定增長(zhǎng)已經(jīng)持續(xù)了15年,越來(lái)越多的開發(fā)者每天都在使用Linux。此外,像樹莓派這樣的小玩具也會(huì)讓Linux出現(xiàn)在許多以前只有windows或Mac的家庭中。我認(rèn)為你可以理解為什么跨操作系統(tǒng)的開發(fā)會(huì)具有巨大的優(yōu)勢(shì)……而這僅僅是個(gè)開始。
截止到現(xiàn)在,Node生態(tài)系統(tǒng)已經(jīng)能夠完全覆蓋Web開發(fā)、移動(dòng)開發(fā)和桌面開發(fā)。提供了一個(gè)能夠在這些所有的平臺(tái)建立相同用戶界面的技能組合。
就這樣……JavaScript贏得了桌面開發(fā)。
我不想在這里介紹NPM(節(jié)點(diǎn)包管理器)上提供的無(wú)數(shù)軟件包,這些包可以方便后端開發(fā),因此,我只會(huì)提到Express sjs,有一個(gè)簡(jiǎn)單但深刻的理由:
Node是為后端而構(gòu)建的。
而且,Node生態(tài)系統(tǒng)中的JavaScript已經(jīng)成為了一種多用途的工具,已經(jīng)被用于開發(fā)自己的服務(wù)器應(yīng)用程序。在Node創(chuàng)建之前,JavaScript基本上只支持瀏覽器。它不需要執(zhí)行復(fù)雜的服務(wù)器端操作,如數(shù)據(jù)庫(kù)讀取、圖像轉(zhuǎn)換或壓縮。但現(xiàn)在它可以……
而且,正如以上幾個(gè)例子一樣,這種對(duì)代碼共享和重用顯著的簡(jiǎn)化也產(chǎn)生了一些明顯的副作用。
其中一個(gè)副作用就是服務(wù)器端渲染。
你get到了嗎?
渲染
這兩件事有什么共同點(diǎn)?
傳統(tǒng)意義上來(lái)說(shuō),沒什么。但“前端”(JavaScript)或“后端”(PHP、Java、Python、Ruby等)的開發(fā)通常是由兩個(gè)完全獨(dú)立的團(tuán)隊(duì)來(lái)維護(hù)。
兩個(gè)團(tuán)隊(duì)的人非常不同。
但現(xiàn)在不再是了!
感謝Node,我們現(xiàn)在能夠在用戶的瀏覽器需要渲染一件東西之前,在服務(wù)器端組裝復(fù)雜的用戶界面。這就是為什么現(xiàn)在Web如此時(shí)髦的原因。因?yàn)镹ode已經(jīng)消除了后端和前端之間的界限。
就這樣……JavaScript贏得了后端開發(fā)。
我把這個(gè)放到了最后,因?yàn)樗⒉皇钦嬲摹癗ode”,而是JavaScript的東西,我想稍微寬泛一些:
JavaScript的成功不是因?yàn)樗鼉?yōu)于其他語(yǔ)言。它的成功是一個(gè)直接的結(jié)果,它對(duì)幾乎每個(gè)社區(qū)都能夠適應(yīng)。
JavaScript開發(fā)者并非純粹主義者。
我們喜歡我們的語(yǔ)言(不是),版本分散、依賴于轉(zhuǎn)譯、跨平臺(tái)、前沿、不斷發(fā)展,以及以前沒有語(yǔ)言的地方。
就像游戲開發(fā)!
當(dāng)Unity 3D首次推出基于JavaScript的“UnityScript”作為游戲開發(fā)工具的時(shí)候,我當(dāng)時(shí)就意識(shí)到,JavaScript將會(huì)做一些非常酷的事情。這是該公司首次進(jìn)軍非Web開發(fā)領(lǐng)域。
這是一個(gè)明確的跡象,表明JavaScript可以做的不僅僅是打開“飛出”菜單,在頁(yè)面上調(diào)整字體大小。它可以做更多的事情,讓你給這篇文章或者一張圖片點(diǎn)贊。它可以處理沉浸式的跨平臺(tái)游戲體驗(yàn)。那些曾經(jīng)被限制在Chrome、Firefox和Internet Exploder的開發(fā)者,突然之間也成了一名游戲開發(fā)者。
雖然Unity最近宣布他們將不在支持UnityScript,但我還是要說(shuō):
就這樣……JavaScript贏得了游戲開發(fā)。
好吧,也許不是。
我不知道這個(gè)征服會(huì)在什么時(shí)候停止,但Node正在瘋狂爆發(fā)。它正在顛覆一個(gè)又一個(gè)的發(fā)展難題,為一個(gè)軟件開發(fā)的世界鋪平了道路,在這個(gè)世界里,一種語(yǔ)言可以統(tǒng)治所有。我確實(shí)覺得我需要重申一下——以防被忽視:
在任何一個(gè)領(lǐng)域,JavaScript都不是最佳語(yǔ)言。
JavaScript的優(yōu)勢(shì)在于它的多功能性。它來(lái)自開放式的社區(qū),它采用了這種無(wú)分類、多態(tài)的腳本語(yǔ)言,并將其轉(zhuǎn)變?yōu)楫?dāng)今最強(qiáng)大的開發(fā)生態(tài)系統(tǒng)。
如果你有不同的看法,歡迎在留言區(qū)互動(dòng)。
編譯組出品。編輯:郝鵬程
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。