NodeJs の基本構文と型の概要

不言
不言オリジナル
2018-06-30 15:57:172057ブラウズ

この記事では、NodeJ の基本的な構文と種類に関する関連情報を主に紹介します。 Googol でそれを要約するには、 の記事を見ましたが、元のリンクはもうありません。この記事をスナップショットから取り出してください。元の著者に質問がある場合は、私に連絡してください。

この記事はすべて JS の基本に関するものです。専門家は自動的にスキップします。私はこれまで js についてあまり書いたことがなく、この分野は比較的苦手なので、node を書くときにもトラブルに遭遇しました。ここで自分自身にいくつかの知識を追加します。

Text

Node.js は JavaScript スクリプト言語に基づいています。ほとんどのスクリプト言語に共通する特徴は「弱い型付け」です。

PHP とは異なり、PHP は新しい変数があっても新しい変数を宣言する必要はありませんが、JavaScript では変数を宣言するために var が必要です。そして、この var は、C++ の int、string、char などのすべての型、さらには関数の意味をカバーします。 この記事と次の記事のすべての内容は、Linux または Cygwin 上の vim を使用して編集され (そうでない場合は、独自の方法に変換してください)、コマンド ラインで結果を表示します。

基本構文

変数宣言

C/C++では、次のように変数を宣言します:

"C++

void foo() {}
int a = 0;
char b = 'a';
float c = 1.0f;
void (*d)() = foo; ///< 忘了是不是这么写的了,总之是函数指针
Node.jsでは次のようになります:

"javascript

function foo() {}
var a = 0;
var b = &#39;a&#39;;
var c = 1.0;
var d = foo;

したがって、いいえ変数の型に関係なく、Node.js の var で解決されます。

ループ ステートメント

for...i

このループ ステートメントは基本的に C/C++ と同じで、両方とも "C++

for(int i = 0; i < foo; i++)
{
//...
}

そして、Node.js は弱く型付けされているため、必要なのは次のとおりです:

「javascript

for(var i = 0; i < foo; i++) {
    //...
}
for…in

これは、PHP の foreach に似た、post 型のループ ステートメントです。

たとえば、次のような JSON オブジェクトがあります:


javascript

var foo = {
    "hello"     : "world",
    "node"      : "js",
    "blahblah"  : "bar"
};

この時点で、for...in を使用してループスルーできます:

javascript

for(var key in foo) {
    console.log(key + ": " + foo[key]);
}

コマンドで次のコマンドを入力すると、行:

$ node foo.js

次の内容が画面に表示されます:

hello
: world
node: js
blahblah: bar

ヒント: 上記からわかるように、for...in ステートメントは、JSON オブジェクト、配列、オブジェクトのキー名を走査するために使用されます。ただし、キー値のトラバースは提供されません。キー値を取得したい場合は、foo[] の形式でのみ取得できます。これは、PHP の foreach とは多少異なります。

while…do,do…whill

他の言語とあまり変わりませんが、変数宣言がある場合はvarを使う必要があります。

演算子

+、-、*、/

はこのように注意すべきは+です。文字列と数値演算の両方を操作できます。弱い型付け言語は型が弱いと言いますが、数値が文字列の形で現れることもあれば、文字列が数値の形で現れることもありますが、それでも必要な場合にはそれがどのような型であるかを言わなければなりません。結果を確認するには、次のコードを使用します。

var a = "1";
var b = 2;
console.log(a + b);
console.log(parseInt(a) + b);

parseInt これは、文字列を int 型の変数に解析するために使用される Node.js の組み込み関数です。 上記のコードの実行結果は次のとおりです:

12
3

注: 最初の console.log の結果は 12 です。 a は文字列であるため、b も文字列の形式でシステムによって追加されます。 2つの文字 文字列をくっつけると12になります。最初の a を int 型に変換したため、2 番目の console.log の結果は 3 になります。2 つの int 型変数を加算すると、結果は当然 3 になります。

==, ===, !=, !==


ここで説明すべきことの 1 つは、この論理演算子の長さが 2 (==, !=) の場合、外部値のみを決定するということです。同じかどうかでは種類は決まりません。たとえば、

var a = 1, b = "1";
console.log(a == b);

出力結果は true です。ただし、判定の途中に等号を付けると、型と値が同じ場合のみ真となり、そうでない場合は偽となります。つまり、

var a = 1, b = "1";
console.log(a === b);
の場合、 a は int 型であり、 b は文字列であるため、返される結果は false になります。

ところで、条件文について話しましょう。実際、ここでは他の言語と何ら変わりはなく、2 つの等号と 3 つの等号が必要です。したがって、あまり詳しくは説明しません。

typeof

ここでは関数ではなく演算子として扱います。

この演算子の機能は、変数の型を決定することです。次のコードを実行すると、文字列、つまり型名が返されます。

function foo() {}
var a = 0;
var b = &#39;嘘~蛋花汤在睡觉。&#39;;
var c = 1.0;
var d = foo;
var e = { "a" : a };
var f = [ 1, 2, 3 ];
var g = null;
var h = undefined;
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);
console.log(typeof f);
console.log(typeof g);
console.log(typeof h);
ここでの実行結果は次のようになります。

number
string
number
function
object
object
object
undefined

null、未定義、NaN


JavaScript には、タイトルに示すように 3 つの特別な値があります。最初の値は C/C++ でも見られるものですが、本質は

「C++

define NULL 0
」です。JavaScript では、これら 3 つの値は異なる意味を表します。 ###ヌル ###

null 是一种特殊的 object,大致的意思就是空。比如说:

var a = null;

大家都能看懂,就不多做解释了。但是跟 C/C++ 不同的是,这个 null 跟 0 不相等。

### undefined ###

这个东西的意思就是说这个变量未声明。为了能够更好地区分 null,我们的样例代码如下写:

"javascript

var a = {
    "foo" : null
};
console.log(a["foo"]);
console.log(a["bar"]);

上面的代码中,我们让 a["foo"] 的值为空,即 null。而压根没有声明 a["bar"] 这个东西,它连空都不是。输出的结果大家都差不多应该猜到了:

null
undefined
NaN

这是一个空的数值,是一个特殊的 number。它的全称是 Not a Number。有点奇怪,大家可以理解为 不是数字形态,或者数值出错的 number 类型变量。

多在浮点型数值运算错误(如被0除)的情况下出现,甚至可以是用户自己让一个变量等于 NaN 以便返回一个错误值让大家知道这个函数运算出错了云云。

小杂碎

其它剩余的语句也跟已存在的其它语言差不多,比如说 break 啊、switch 啊、continue 啊等等等等。

变量类型

这一节主要讲的是 JavaScript 对象,其它类型差不多一带而过吧。

基础类型

Node.js 包含的基础类型差不多有如下几个:

number
string
boolean
array
其中前三种类型可以直接赋值, 而 array 的赋值只是一个引用赋值而已,在新变量中改变某个值的话旧变量的值也会改变 ,直接可以试试下面的代码:

javascript
var foo = [ 1, 2, 3 ];
var bar = foo;
bar[0] = 3;
console.log(foo);

它得出的结果是:

javascript
[ 3, 2, 3 ]

也就是说 array 要是复制出一个新的数组的话,不能用直接赋值的方法,而必须“深拷贝”。

这里有必要讲一下 array 的三种创建方法。

第一种:

javascript

var dog = new Array();
dog[0] = "嘘~";
dog[1] = "蛋花汤";
dog[2] = "在睡觉";

第二种:

javascript

var dog = new Array( "嘘~", "蛋花汤", "在睡觉" );

第四种:

javascript

var dog = [
    "嘘~",
    "蛋花汤",
    "在睡觉"
];

我个人比较喜欢第三种写法,比较简洁。

JSON对象

这里我把 JSON对象 单独拎出来而不是把它归类为 JavaScript对象,如果觉得我有点误人子弟就可以直接跳过这一节了。

本人对于 JSON对象 和 JavaScript 对象的区分放在 是否只用来存储数据,而并非是一个类的实例化。其实 JSON 的本质便是 JavaScript Object Notation。

更多有关 JSON 的信息请自行百科。

在 Node.js 中声明一个 JSON对象 非常简单:

javascript

var dog = {
  "pre" : "嘘~",
  "sub" : {
    "name" : "蛋花汤",
    "act"  : "在睡觉",
    "time" : 12
    },
  "suf" : [ "我说了", "它在睡觉", "就是在睡觉" ]
};

有两种方式能得到 JSON对象 中的某个键名的键值,第一种是用点连接,第二种是用中括号:

javascript

dog
.pre;
dog["pre"];

注意:上面在用点的时候,后面直接跟的是JSON中的key,如果把key当成是变量去当问,只能用dog[key]试试看:现在你自己动手试试看,用 for...in 的形式遍历一遍上面的 JSON对象。别忘了用上 typeof 喵~

类(对象)的基础

严格意义上来讲,Node.js 的类不能算是类,其实它只是一个函数的集合体,加一些成员变量。它的本质其实是一个函数。

不过为了通俗地讲,我们接下去以及以后都将其称为“类”,实例化的叫“对象”。

因为类有着很多 函数 的特性,或者说它的本质就是一个 函数,所以这里面我们可能一不留神就顺带着把函数基础给讲了。

类的声明和实例化

声明一个类非常简单,大家不要笑:

javascript
function foo() {
    //...
}

好了,我们已经写好了一个 foo 类了。

真的假的?!真的。

不信?不信你可以接下去打一段代码看看:

javascript
var bar = new foo();
别看它是一个函数,如果以这样的形式(new)写出来,它就是这个类的实例化。

而这个所谓的 foo() 其实就是这个 foo() 类的构造函数。

成员变量

成员变量有好两种方法。

第一种就是在类的构造函数或者任何构造函数中使用 this.e78ad71b8a45d2a3209df4d26f1fcfa6 。你可以在任何时候声明一个成员变量,在外部不影响使用,反正就算在还未声明的时候使用它,也会有一个 undefined 来撑着。所以说这就是第一种方法:

javascript
function foo() {
    this.hello = "world";
}

注意:只有在加了 this 的时候才是调用类的成员变量,否则只是函数内的一个局部变量而已。要分清楚有没有 this 的时候变量的作用范围。

第二种方法就是在构造函数或者任何成员函数外部声明,其格式是 9f92f7e78eacb2684f956ddec8c620be.prototype.e78ad71b8a45d2a3209df4d26f1fcfa6:

javascript

function foo() {
    //...
}
foo.prototype.hello = "world";

无论上面哪种方法都是对成员变量的声明,我们可以看看效果:

javascript

var bar = new foo();
console.log(bar.hello);

甚至你可以这么修改这个类:

javascript

function foo() {
    this.hello = "world";
}
foo.prototype.hello = "蛋花汤";

然后再用上面的代码输出。

想想看为什么输出的还是 world 而不是 蛋花汤。

构造函数

我们之前说过了这个 foo() 实际上是一个 构造函数。那么显然我们可以给构造函数传参数,所以就有了下面的代码:

javascript

// 代码2.1
function foo(hello) {
    if(hello === undefined) {
        this.hello = "world";
    } else {
        this.hello = hello;
    }
}

我们看到上面有一个奇葩的判断 if(hello === undefined),这个判断有什么用呢?第一种可能,就是开发者很蛋疼地特意传进去一个 undefined 进去,这个时候它是 undefined 无可厚非。

还有一种情况。我们一开始就说了 JavaScript 是一门弱类型语言,其实不仅仅是弱类型,它的传参数也非常不严谨。你可以多传或者少传(只要保证你多传或者少传的时候可以保证程序不出错,或者逻辑不出错),原则上都是可以的。多传的参数会被自动忽略,而少传的参数会以 undefined 补足。

看看下面的代码就明白了:

javascript

// 上接代码2.1
var bar1 = new foo();
var bar2 = new foo("蛋花汤");

请自行输出一下两个 bar 的 hello 变量,会发现一个是 world 一个是 蛋花汤。显而易见,我们的第一个 bar1 在声明的时候,被 Node.js 自动看成了:

javascript

var bar1 = new foo(undefined);

所以就有了它是 world 一说。

还有就是在这个构造函数中,我们看到了传进去的参数是 hello 而这个类中本来就有个成员变量就是 this.hello。不过我们之前说过了有 this 和没 this 的时候作用域不同,那个参数只是作用于构造函数中,而加了 this 的那个则是成员变量。用一个 this 就马上区分开来他们了,所以即使同名也没关系。

成员函数

成员函数声明

成员函数的声明跟成员变量的第二种声明方法差不多,即 9f92f7e78eacb2684f956ddec8c620be.prototype.265e170ec04180dc123319e5b38ce9ef = 706b50993dbe5ac54168842acd392ce8;

javascript

// 上接代码2.1
function setHello(hello) {
  this.hello = hello;
}
foo.prototype.setHello = setHello;
bar1.setHello("鸡蛋饼");

上面这段代码显而易见,我们实现了 foo 类的 setHello 函数,能通过它修改 foo.hello 的值。

但是这么写是不是有点麻烦?接下去我要讲一个 JavaScript 函数重要的特性了。

★ 匿名函数 ★

很多时候我们的某些函数只在一个地方被引用或者调用,那么我们为这个函数起一个名字就太不值了,没必要,所以我们可以临时写好这个函数,直接让引用它的人引用它,调用它的人调用它。所以函数可以省略函数名,如:

javascript

function(hello) {
    this.hello = hello;
}

至于怎么引用或者调用呢?如果是上面的那个类需要引用的话,就是写成这样的:

javascript

foo.prototype.setHello = function(hello) {
    this.hello = hello;
}

这样的写法跟 成员函数 声明 是一个效果的,而且省了很多的代码量。而且实际上,基本上的类成员函数的声明都是采用这种匿名函数的方式来声明的。

至于说怎么样让匿名函数被调用呢?这通常用于传入一个只被某个函数调用的函数时这样写。

比如我们有一个函数的原型是:

javascript

/**
 * 我们将传入a,b两个变量,
 * 在算出a+b的值后,交由func(num)
 * 去进行输出
 */
function sumab(a, b, func) {
    var c = a + b;
    func(a, b, c);
}

比如我们有两个版本的输出函数,一个是中文输出,一个是英文输出,那么如果不用匿名函数时候是这么写的:

javascript

function zh(a, b, sum) {
  console.log(a + " + " + b + " 的值是:" + sum);
}
function en(a, b, sum) {
  console.log(a + " plus " + b + " is " + sum);
}
sumab(1, 2, zh);
sumab(3, 4, en);

执行一遍这段代码,输出的结果将会是:

1 + 2 的值是:3
3 plus 4 is 7
这样的代码如果采用匿名函数的形式则将会是:

javascript

sumab(1, 2, function(a, b, sum) {
    console.log(a + " + " + b + " 的值是:" + sum);
});
sumab(3, 4, function(a, b, sum) {
    console.log(a + " plus " + b + " is " + sum);
});

这种形式通常使用于回调函数。回调机制算是 Node.js 或者说 JavaScript 的精髓。在以后的篇章会做介绍。

成员函数声明的匿名函数声明方式

虽然上一节讲过了,不过还是再讲一遍吧。

通常我们声明类的成员函数时候都是用匿名函数来声明的,因为反正那个函数也就是这个类的一个成员函数而已,不会在其它地方被单独引用或者调用,所以就有了下面的代码:

javascript

// 上接代码2.1
foo.prototype.setHello = function(hello) {
    this.hello = hello;
}

这样我们就使得 foo 类有了 setHello 这个函数了。

2.3.4. 类的随意性

这个又是我胡扯的。所谓类的随意性即 JavaScript 中你可以在任何地方修改你的类,这跟 Ruby 有着一定的相似之处。

比如说 string ,它其实也是一个类,有着诸如 length 这样的成员变量,也有 indexOf、substr 等成员函数。但是万一我们觉得这个 string 有些地方不完善,想加自己的方法,那么可以在你想要的地方给它增加一个函数,比如:

javascript

String.prototype.sb = function() {
  var newstr = "";
  for(var i = 0; i < this.length; i++) {
    if(i % 2 === 0) newstr += "s";
    else newstr += "b";
  }
  return newstr;
};

这个函数的意思就是填充一个字符串,使其变成 sb 的化身。

我们来测试一下:

var str = "嘘~蛋花汤在睡觉。";
console.log(str.sb());

你将会得到这样的结果:

sbsbsbsbs
你跟你的电脑说“嘘~蛋花汤在睡觉。”,你的电脑会骂你四次半傻逼。(赶快砸了它)

3. 附

3.1. 深拷贝

所谓深拷贝就是自己新建一个数组或者对象,把源数组或者对象中的基础类型变量值一个个手动拷过去,而不是只把源数组或者对象的引用拿过来。所以这就涉及到了一个递归的调用什么的。

下面是我实现的一个深拷贝函数,大家可以写一个自己的然后加入到自己的 Node.js 知识库中。

javascript

function cloneObject(src) {
  var dest = {};
  for(var key in src) {
    if(typeof src === "object") dest[key] = cloneObject(src[key]);
    else dest[key] = src[key];
  }
  return dest;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

如何快速使用node.js进行web开发

关于NodeJS、NPM安装配置步骤(windows版本) 以及环境变量的介绍

以上がNodeJs の基本構文と型の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。