Skip to content

3. JavaScript 基础

:从这里开始,术语 [JavaScript] 将始终指代 ECMAScript 6 标准。

在之前的 JavaScript 项目中,创建一个名为 [bases] 的文件夹。我们将把本节中的示例放在那里:

Image

3.1. 脚本 [bases-01]

为了介绍 PHP7 的基础知识,我们使用了以下代码(参见相关段落):


<?php
 
// this is a comment
// variable used without being declared
$nom = "dupont";
// a screen display
print "nom=$nom\n";
// an array with elements of different types
$tableau = array("un", "deux", 3, 4);
// its number of elements
$n = count($tableau);
// a loop
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// initialize 2 variables with the contents of an array
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// concatenation of the 2 strings
$chaine3 = $chaine1 . $chaine2;
// result display
print "[$chaine1,$chaine2,$chaine3]\n";
// use function
affiche($chaine1);
// the type of a variable can be known
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// the type of a variable can change at runtime
$n = "a changé";
afficheType("n", $n);
// a function can return a result
$res1 = f1(4);
print "res1=$res1\n";
// a function can return a table of values
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// we could have retrieved these values in a table
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// testing
for ($i = 0; $i < count($t); $i++) {
  // displays only channels
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// == and === comparison operators
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// other tests
for ($i = 0; $i < count($t); $i++) {
  // displays only integers >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// a while loop
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//while
print "somme=$somme\n";
 
// end of program
exit;
 
//----------------------------------
function affiche($chaine) {
  // displays $chaine
  print "chaine=$chaine\n";
}
 
//poster
//----------------------------------
function afficheType($name, $variable) {
  // displays the type of $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}
 
//afficheType
//----------------------------------
function f1($param) {
  // adds 10 to $param
  return $param + 10;
}
 
//----------------------------------
function f2() {
  // returns 3 values
  return array("un", 0, 100);
}
?>

转换为 JavaScript 后,结果如下:


'use strict';
// this is a comment
// constant
const nom = "dupont";
// a screen display
console.log("nom : ", nom);
// an array with elements of different types
const tableau = ["un", "deux", 3, 4];
// its number of elements
let n = tableau.length;
// a loop
for (let i = 0; i < n; i++) {
  console.log("tableau[", i, "] = ", tableau[i]);
}
// initialize 2 variables with the contents of an array
let [chaine1, chaine2] = ["chaine1", "chaine2"];
// concatenation of the 2 strings
const chaine3 = chaine1 + chaine2;
// result display
console.log([chaine1, chaine2, chaine3]);
// use function
affiche(chaine1);
// the type of a variable can be known
afficheType("n", n);
afficheType("chaine1", chaine1);
afficheType("tableau", tableau);
// the type of a variable can change at runtime
n = "a changé";
afficheType("n", n);
// a function can return a result
let res1 = f1(4);
console.log("res1=", res1);
// a function can return a table of values
let res2, res3;
[res1, res2, res3] = f2();
console.log("(res1,res2,res3)=", [res1, res2, res3]);
// we could have retrieved these values in a table
let t = f2();
for (let i = 0; i < t.length; i++) {
  console.log("t[i]=", t[i]);
}
// testing
for (let i = 0; i < t.length; i++) {
  // displays only channels
  if (typeof (t[i]) === "string") {
    console.log("t[i]=", t[i]);
  }
}
// == and === comparison operators
if ("2" == 2) {
  console.log("avec l'opérateur ==, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2");
}
if ("2" === 2) {
  console.log("avec l'opérateur ===, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2");
}
// other tests
for (let i = 0; i < t.length; i++) {
  // displays only integers >10
  if (typeof (t[i]) === "number" && Math.floor(t[i]) === t[i] && t[i] > 10) {
    console.log("t[i]=", t[i]);
  }
}
// a while loop
t = [8, 5, 0, -2, 3, 4];
let i = 0;
let somme = 0;
while (i < t.length && t[i] > 0) {
  console.log("t[i]=", t[i]);
  somme += t[i];
  i++;
}
console.log("somme=", somme);
 
// program stopped because no executable code left
 
//poster
//----------------------------------
function affiche(chaine) {
  // chain poster
  console.log("chaine=", chaine);
}
 
//afficheType
//----------------------------------
function afficheType(name, variable) {
  // displays variable type
  console.log("type[variable ", name, "]=", typeof (variable));
}
 
//----------------------------------
function f1(param) {
  // adds 10 to param
  return param + 10;
}
 
//----------------------------------
function f2() {
  // returns 3 values
  return ["un", 0, 100];
}

让我们来讨论一下带有 [use strict] 声明(第 1 行)的 PHP 代码与 ECMAScript 6 代码之间的区别:

  • 第一个区别在于,在 ECMAScript 中,变量使用以下关键字进行声明
    • [let] 用于声明在代码执行过程中值可能会改变的变量;
    • [const] 用于声明在代码执行过程中值不会改变(即常量)的变量;
    • 您也可以使用 [var] 关键字代替 [let]。这是 ECMAScript 5 中使用的关键字。本课程中我们将不使用它;
  • 第 6 行:[console.log] 方法可以显示各种类型的数据:字符串、数字、布尔值、数组和对象。PHP 的 [print] 方法无法原生显示数组和对象。在 [console.log] 表达式中,[console] 是一个对象,而 [log] 是该对象的一个方法;
  • 第 8 行:JavaScript 数组是通过指针引用的对象。当我们编写:

const tableau = ["un", "deux", 3, 4];

变量 [array] 是一个指向字面量数组 ["one", "two", 3, 4]指针。修改数组的内容不会改变其指针。因此,数组通常使用 [const] 关键字进行声明。在 PHP 中,数组并非由指针引用。它是一个字面量值;

  • 第 12 行:循环变量 [i] 在循环内部声明(let)。关键字 [let] 具有块作用域(大括号内的代码)。因此,第 12 行中的变量 [i] 仅在循环内部可见;
  • 第 18 行:字符串连接运算符在 JavaScript 中是 + 运算符,在 PHP 中是 . 运算符。该运算符的一个显著特点是,它优先于 + 加法运算符。因此:
    • 在 PHP 中,‘1’ + 2 结果为数字 3;
    • 在 JavaScript 中,‘1’+2 返回字符串 ‘12’;
  • 第 20 行:[console.log] 可以显示数组;
  • 第 82 行:在 JavaScript 中,无法指定函数参数的类型;
  • 第 91 行:[typeof] 运算符可用于确定数据项的类型。共有四种类型:number、string、boolean 和 object。请注意,JavaScript 中没有 [integer] 类型或 [array] 类型。如前所述,数组通过指针处理,并归类为 object 类型;
  • 第 50–59 行:与 PHP 类似,JavaScript 拥有两个比较运算符 == 和 ‘===’,其含义与 PHP 中相同。ESLint 通常会将 == 运算符标记为潜在错误。我们将始终使用 ‘===’ 运算符;
  • 第 79 行:我们本可以包含 [return] 语句,但 ESLint 会发出警告,指出 [return] 仅应在函数内部使用;

现在运行这段代码:

Image

执行结果:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-01.js"
nom : dupont
tableau[ 0 ] = un
tableau[ 1 ] = deux
tableau[ 2 ] = 3
tableau[ 3 ] = 4
[ 'chaine1', 'chaine2', 'chaine1chaine2' ]
chaine= chaine1
type[variable n ]= number
type[variable chaine1 ]= string
type[variable tableau ]= object
type[variable n ]= string
res1= 14
(res1,res2,res3)= [ 'un', 0, 100 ]
t[ 0 ]= un
t[ 1 ]= 0
t[ 2 ]= 100
t[ 0 ]= un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[ 2 ]= 100
t[ 0 ]= 8
t[ 1 ]= 5
somme= 13
 
[Done] exited with code=0 in 0.316 seconds

在编写的代码中,ESLint 报告了两个错误:

Image

  • 当您将鼠标悬停在红色警告线上时,会看到错误信息 [3]。在此处,ESLint 无法识别两个常量正在进行比较。两个操作数中应有一个是变量;
  • [4] 中,如果决定不修正该错误,可通过 [快速修复] 选项忽略此警告;

Image

  • 第 [5] 行,您可以禁用当前行或整个文件的警告。这里我们选择后者。随后,文件开头会生成第 [6] 行;

3.2. 脚本 [bases-02]

[bases-02] 脚本演示了 [let][const] 关键字的使用:


'use strict';
// to initialize a variable, use let or const
// let for variables
let x = 4;
x++;
console.log(x);
// const for constants
const y = 10;
x += y;
// prohibited
y++;
  • 第 11 行会导致运行时错误 [1-2]。在执行之前,ESLint 会对此进行标记 [3]

Image

3.3. 脚本 [bases-03]

脚本 [bases-03] 用于检查 JavaScript 中的变量作用域:


'use strict';
// variable scope
let count = 1;
function doSomething() {
  // count is known here
  console.log("count=",count);
}
// call
doSomething();
  • 尽管变量 [count] 是在 [doSomething] 函数外部声明的,但在该函数内部仍可访问。这与 PHP 存在根本性的差异;

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-03.js"
count= 1
 
[Done] exited with code=0 in 0.3 seconds

3.4. 脚本 [bases-04]

局部变量会隐藏同名的全局变量:


'use strict';
// variable scope
const count = 1;
function doSomething() {
  // the local variable hides the global variable
  const count = 2;
  console.log("count inside function=",count);
}
// global variable
console.log("count outside function=",count);
// local variable
doSomething();

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-04.js"
count outside function= 1
count inside function= 2
 
[Done] exited with code=0 in 0.246 seconds

3.5. 脚本 [bases-05]

在函数内部定义的变量在函数外部不可见:


'use strict';
// variable scope
function doSomething() {
  // local variable to the
  const count = 2;
  console.log("count inside function=", count);
}
// here count is unknown
console.log("count outside function=", count);
doSomething();

ESLint 在第 9 行报告了一个错误:

Image

3.6. script [bases-06]

关键字 [let][const] 定义具有 [块] 作用域(大括号内的代码)的变量,但关键字 [var] 并非如此:


'use strict';
// the [let] keyword is used to define a block-scope variable
{
  // the [count] variable is only known in this block
  let count = 1;
  console.log("count=", count);
}
// here the variable [count] is not known
count++;
 
// the [const] keyword is used to define a block-span variable
{
  // the [count2] variable is only known in this block
  const count2 = 1;
  console.log("count=", count2);
}
// here the variable [count2] is not known
count2++;
 
// the [var] keyword cannot be used to define a block-scope variable
{
  // the variable [count3] will be known globally
  var count3 = 1;
  console.log("count=", count3);
}
// here the variable [count3] is known
count3++;

注释

  • 第 5 行:变量 [count] 仅在声明它的代码块(第 3–7 行)内有效;
  • 第 14 行:常量 [count2] 仅在声明它的代码块(第 12–16 行)内有效;
  • 第 23 行:变量 [count3] 在其声明所在的代码块(第 21–25 行)之外也是已知的;

ESLint 报告了以下错误:

Image

鉴于上述与代码块作用域相关的原因,从现在起我们将仅使用 [let][const] 关键字。

3.7. 脚本 [bases-07]

JavaScript 中的数据类型:


'use strict';
 
// data type jS
const var1 = 10;
const var2 = "abc";
const var3 = true;
const var4 = [1, 2, 3];
const var5 = {
  nom: 'axèle'
};
const var6 = function () {
  return +3;
}
// type display
console.log("typeof(var1)=", typeof (var1));
console.log("typeof(var2)=", typeof (var2));
console.log("typeof(var3)=", typeof (var3));
console.log("typeof(var4)=", typeof (var4));
console.log("typeof(var5)=", typeof (var5));
console.log("typeof(var6)=", typeof (var6));

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-07.js"
typeof(var1)= number
typeof(var2)= string
typeof(var3)= boolean
typeof(var4)= object
typeof(var5)= object
typeof(var6)= function
 
[Done] exited with code=0 in 0.26 seconds

评论

  • 第 7 行(代码):数组是一种对象。因此,[var4] 是指向该数组的指针,而非数组本身;
  • 第 8 行(代码):[var5] 是指向字面量对象的指针。我们将看到,JavaScript 的字面量对象与 PHP 的类实例非常相似。它们同样是通过指针来引用的;
  • 第 11 行(代码):变量可以是 [function] 类型(结果中的第 7 行);

3.8. 脚本 [bases-08]

此脚本演示了 JavaScript 中可能发生的类型转换。


'use strict';
 
// implicit type changes
// type -->bool
console.log("---------------[Conversion implicite vers un booléen]------------------------------");
showBool("abcd");
showBool("");
showBool([1, 2, 3]);
showBool([]);
showBool(null);
showBool(0.0);
showBool(0);
showBool(4.6);
showBool({});
showBool(undefined);
 
function showBool(data) {
  // the conversion from data to Boolean is done automatically in the following test
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", data ? true : false);
}
 
// implicit type changes to a nume ric type
console.log("---------------[Conversion implicite vers un nombre]------------------------------");
showNumber("12");
showNumber("45.67");
showNumber("abcd");
 
function showNumber(data) {
  // data + 1 doesn't work, because then jS concatenates strings rather than adding them together
  const nombre = data * 1;
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}
 
// explicit type changes to Boolean
console.log("---------------[Conversion explicite vers un booléen]------------------------------");
showBool2("abcd");
showBool2("");
showBool2([1, 2, 3]);
showBool2([]);
showBool2(null);
showBool2(0.0);
showBool2(0);
showBool2(4.6);
showBool2({});
showBool2(undefined);
 
function showBool2(data) {
  // the conversion from data to Boolean is explicitly done in the following test
  console.log("[", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", Boolean(data));
}
// changements explicites de type vers Number
console.log("---------------[Conversion explicite vers un nombre]------------------------------");
showNumber2("12.45");
showNumber2(67.8);
showNumber2(true);
showNumber2(null);
 
function showNumber2(data) {
  const nombre = Number(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}
 
// to String
console.log("---------------[Conversion explicite vers un string]------------------------------");
showString(5);
showString(6.7);
showString(false);
showString(null);
 
function showString(data) {
  const chaîne = String(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[chaîne]=", chaîne, "[type(chaîne)]=", typeof (chaîne));
}
 
// some unexpected implicit conversions
console.log("---------------[Autres cas]------------------------------");
const string1 = '1000.78';
// default string concatenation
const data1 = string1 + 1.034;
console.log("data1=", data1, "type=", typeof (data1));
const data2 = 1.034 + string1;
console.log("data2=", data2, "type=", typeof (data2));
// explicit conversion to number
const data3 = Number(string1) + 1.034;
console.log("data3=", data3, "type=", typeof (data3));
// true is converted into the number 1
const data4 = true * 1.18;
console.log("data4=", data4, "type=", typeof (data4));
// false is converted into the number 0
const data5 = false * 1.18;
console.log("data5=", data5, "type=", typeof (data5));

执行结果


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Data\st-2019\dev\es6\javascript\bases\bases-08.js"
---------------[Conversion implicite vers un booléen]------------------------------
[data= abcd ], [type(data)]= string [valeur booléenne(data)]= true
[data= ], [type(data)]= string [valeur booléenne(data)]= false
[data= [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[data= [] ], [type(data)]= object [valeur booléenne(data)]= true
[data= null ], [type(data)]= object [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[data= {} ], [type(data)]= object [valeur booléenne(data)]= true
[data= undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion implicite vers un nombre]------------------------------
[data= 12 ], [type(data)]= string [nombre]= 12 [type(nombre)]= number
[data= 45.67 ], [type(data)]= string [nombre]= 45.67 [type(nombre)]= number
[data= abcd ], [type(data)]= string [nombre]= NaN [type(nombre)]= number
---------------[Conversion explicite vers un booléen]------------------------------
[ abcd ], [type(data)]= string [valeur booléenne(data)]= true
[ ], [type(data)]= string [valeur booléenne(data)]= false
[ [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[ [] ], [type(data)]= object [valeur booléenne(data)]= true
[ null ], [type(data)]= object [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[ {} ], [type(data)]= object [valeur booléenne(data)]= true
[ undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion explicite vers un nombre]------------------------------
[data= 12.45 ], [type(data)]= string [nombre]= 12.45 [type(nombre)]= number
[data= 67.8 ], [type(data)]= number [nombre]= 67.8 [type(nombre)]= number
[data= true ], [type(data)]= boolean [nombre]= 1 [type(nombre)]= number
[data= null ], [type(data)]= object [nombre]= 0 [type(nombre)]= number
---------------[Conversion explicite vers un string]------------------------------
[data= 5 ], [type(data)]= number [chaîne]= 5 [type(chaîne)]= string
[data= 6.7 ], [type(data)]= number [chaîne]= 6.7 [type(chaîne)]= string
[data= false ], [type(data)]= boolean [chaîne]= false [type(chaîne)]= string
[data= null ], [type(data)]= object [chaîne]= null [type(chaîne)]= string
---------------[Autres cas]------------------------------
data1= 1000.781.034 type= string
data2= 1.0341000.78 type= string
data3= 1001.814 type= number
data4= 1.18 type= number
data5= 0 type= number