🌸I could be bounded in a nutshell and count myself a king of infinite space.
特别鸣谢:木芯工作室 、Ivan from Russia
你能用的数据类型
在计算机科学中,数据就是一切,它对于计算机意义重大。 JavaScript 提供八种不同的数据类型,它们是 undefined(未定义)、null(空)、boolean(布尔型)、string(字符串)、symbol、number(数字)、bigint(可以表示任意大的整数)和 object(对象)。
例如,计算机区分数字,例如 12,和由字符组成的字符串 strings,例如 “12”、“dog” 或 “123 cats”。 计算机可以对数字执行数学运算,但不能对字符串执行数学运算。
变量允许计算机以一种动态的形式来存储和操作数据, 即通过操作指向数据的指针而不是数据本身来实现。 以上八种数据类型中的任何一种都可以存储到一个变量中。
变量非常类似于你在数学中使用的 x、y 变量,都是以一个简单命名的名称来代替我们赋值给它的数据。 计算机中的变量与数学中的变量不同的是,计算机可以在不同的时间存储不同类型的变量。
通过在变量前面使用关键字 var,声明一个变量,例如:
var ourName;
上面代码的意思是创建一个名为 ourName 的变量。 在 JavaScript 中我们以分号结束语句。 变量名称可以由数字、字母、美元符号 $ 或者下划线 _ 组成,但是不能包含空格或者以数字为开头。
把一个变量的值给另一个变量
在使用赋值运算符赋予变量某个值后,你可以使用赋值运算符将该变量的值赋给另一个变量。
var myVar; myVar = 5; var myNum; myNum = myVar;
以上代码声明了一个没有初始值的变量 myVar,然后给它赋值为 5。 紧接着,又声明了一个没有初始值的变量 myNum。 然后,变量 myVar 的内容(也就是 5)被赋给了变量 myNum。 现在,变量 myNum 的值也为 5。
字符串
之前,你使用以下代码声明变量:
var myName;
但是你也可以像这样声明一个字符串变量:
var myName = "your name";
“your name” 被称为 string literal。 字符串文字或字符串是用单引号或双引号括起来的一系列零个或多个字符。
没初始化的变量
当 JavaScript 中的变量被声明的时候,程序内部会给它一个初始值
undefined。 当你对一个值为 undefined
的变量进行运算操作的时候,算出来的结果将会是 NaN,它的意思是 "Not a Number"
。 如果你用 undefined 变量连接一个字符串,你将得到一个 undefined 的 字符串。
探索 var 和 let 关键字之间的差异
使用 var 关键字声明变量的最大问题之一是你可以轻松覆盖变量声明:
var camper = "James"; var camper = "David"; console.log(camper);
在上面的代码中,camper 变量最初声明为 James,然后被覆盖为 David。 然后控制台显示字符串 David。
在小型应用程序中,你可能不会遇到此类问题。 但是随着你的代码库变大,你可能会意外地覆盖一个你不打算覆盖的变量。 由于此行为不会引发错误,因此搜索和修复错误变得更加困难。
ES6 中引入了一个名为 let
的关键字,这是对 JavaScript 的一次重大更新,以解决与 var 关键字有关的潜在问题。 你将在后面的挑战中了解其他 ES6 特性。
如果将上面代码中的 var 替换为 let ,则会导致错误:
let camper = "James"; let camper = "David";
该错误可以在你的浏览器控制台中看到。
所以不像 var,当你使用 let 时,同名的变量只能声明一次。
使用 const 关键字声明只读变量
关键字 let 并不是声明变量的唯一新方法。 在 ES6 中,你还可以使用 const 关键字声明变量
。
const 具有 let 的所有出色功能,另外还有一个额外的好处
,即使用 const 声明的变量是只读的
。 它们是一个常量值,这意味着一旦一个变量被赋值为 const,它就不能被重新赋值:
const FAV_PET = "Cats"; FAV_PET = "Dogs";
由于重新分配 FAV_PET 的值,控制台将显示错误。
你应该始终使用 const 关键字命名不想重新分配的变量。 这有助于避免给一个常量进行额外的再次赋值。
注意: 通常,开发者会用大写字母作为常量标识符
,用小写字母或者驼峰命名作为变量(对象或数组)标识符。 你将在后面的挑战中了解有关对象、数组以及不可变和可变值的更多信息。 同样在后面的挑战中,你将看到大写、小写或驼峰式变量标识符的示例。
更改代码,以便使用 let 或 const 声明所有变量。 当你想要改变变量时使用 let,当你想要变量保持不变时使用 const。 此外,重命名使用 const 声明的变量以符合惯例。 请勿更改分配给变量的字符串。
转义字符串中的引号
定义一个字符串必须要用单引号或双引号来包裹它。 那么当你的字符串里面包含引号 " 或者 ’ 时该怎么办呢?
在 JavaScript 中,可以通过在引号前面使用反斜杠(\)来转义引号。
const sampleStr = "Alan said, \"Peter is learning JavaScript\".";
有了转义符号,JavaScript 就知道这个单引号或双引号并不是字符串的结尾,而是字符串内的字符。 所以,上面的字符串打印到控制台的结果为:
Alan said, "Peter is learning JavaScript".
用单引号、双引号引用字符串
JavaScript 中的字符串可以使用开始和结束都是同类型的单引号或双引号表示
。 与其他一些编程语言不同的是,单引号和双引号的功能在 JavaScript 中是相同的。
const doubleQuoteStr = "This is a string"; const singleQuoteStr = 'This is also a string';
当你需要在一个字符串中使用多个引号的时候,你可以使用单引号包裹双引号或者相反
。 常见的场景比如在字符串中包含对话的句子需要用引号包裹。 另外比如在一个包含有 <a>
标签的字符串中,标签的属性值需要用引号包裹。
const conversation = 'Finn exclaims to Jake, "Algebraic!"';
然而,如果你需要在其中使用外面的引号,这就成为一个问题。 记住,一个字符串在开头和结尾处有相同的引号
。 要知道,字符串在开头和结尾都有相同的引号,如果在中间使用了相同的引号,字符串会提前中止并抛出错误。
const goodStr = 'Jake asks Finn, "Hey, let\'s go on an adventure?"'; const badStr = 'Finn responds, "Let's go!"';
在这里 badStr 会产生一个错误。
在上面的 goodStr 中,通过使用反斜杠 \ 转义字符可以安全地使用两种引号。
提示: 不要混淆反斜杠 \ 和斜杠 /。 它们不是一回事
。
把字符串更改为开头和结尾使用单引号的字符串,并且不包含转义字符。
这样字符串中的 <a>
标签里面任何地方都可以使用双引号。 你需要将最外层引号更改为单引号,以便删除转义字符。
const myStr = '<a href=\"http://www.example.com\" target=\"_blank\">Link</a>';
用加号运算符连接字符串
在 JavaScript 中,当 + 操作符被用于一个 String 类型的值的时候,它被称作拼接操作符
。 你可以通过拼接其他字符串来创建一个新的字符串。
例如:
'My name is Alan,' + ' I concatenate.'
提示: 注意空格。 拼接操作不会在两个字符串之间添加空格
。所以,如果想加上空格的话,你需要自己在字符串里面添加。
例如:
const ourStr = "I come first. " + "I come second.";
字符串 I come first. I come second. 将显示在控制台中。
用字符串 This is the start. 和 This is the end. 通过 + 运算符创建 myStr。 确保在两个字符串之间包含一个空格。
用 += 运算符连接字符串
我们还可以使用 += 运算符来拼接字符串到现有字符串变量的结尾。 对于那些被分割成几段的长的字符串来说,这一操作是非常有用的。
提示: 注意空格。 拼接操作不会在两个字符串之间添加空格,所以,如果想要加上空格的话,你需要自己在字符串里面添加。
例如:
let ourStr = "I come first. "; ourStr += "I come second.";
ourStr 的值为字符串 I come first. I come second.
用变量构造字符串
有时候你需要构建一个字符串。 通过使用连接运算符(+),你可以插入一个或多个变量来组成一个字符串。
例如:
const ourName = "freeCodeCamp"; const ourStr = "Hello, our name is " + ourName + ", how are you?";
ourStr 值为 Hello, our name is freeCodeCamp, how are you?
把你的名字赋值给变量 myName,然后把变量 myName 插入到字符串 My name is 和 and I am well! 之间,并把连接后的结果赋值给变量 myStr。
将变量追加到字符串
就像我们可以用多行字符串字面量构建单个字符串一样,我们还可以使用加且赋值(+=)运算符将字符串追加到字符串的末尾。
示例:
const anAdjective = "awesome!"; let ourStr = "freeCodeCamp is "; ourStr += anAdjective;
ourStr 值为 freeCodeCamp is awesome!。
字符串的不变性
在 JavaScript 中,字符串(String)的值是不可变的(immutable)
,这意味着一旦字符串被创建就不能被改变。
例如,以下代码将产生错误,因为字符串 Bob 中的字母 B 不能更改为字母 J:
let myStr = "Bob"; myStr[0] = "J";
请注意,这不意味着无法重新分配 myStr。 更改 myStr 的唯一方法是为其分配一个新值,如下所示:
let myStr = "Bob"; myStr = "Job";
使用 push 方法操作数组
一个将数据添加到数组末尾的简单方法是 push() 函数。
.push()
接受一个或多个参数(parameters),并把它压入到数组的末尾。
示例:
const arr1 = [1, 2, 3]; arr1.push(4); const arr2 = ["Stimpson", "J", "cat"]; arr2.push(["happy", "joy"]);
arr1 现在值为 [1, 2, 3, 4],arr2 值为 [“Stimpson”, “J”, “cat”, [“happy”, “joy”]]。
使用 pop 方法操作数组
改变数组中数据的另一种方法是用 .pop() 函数。
.pop() 函数用来弹出一个数组末尾的值。 我们可以把这个弹出的值赋给一个变量存储起来。 换句话说就是 .pop() 函数移除数组末尾的元素并返回这个元素。
数组中任何类型的元素(数值,字符串,甚至是数组)都可以被弹出来 。
const threeArr = [1, 4, 6]; const oneDown = threeArr.pop(); console.log(oneDown); console.log(threeArr);
第一个 console.log 将显示值 6,第二个将显示值 [1, 4]。
使用 shift 方法操作数组-移出第一个
pop() 函数用来移出数组中最后一个元素。 如果想要移出第一个元素要怎么办呢?
这时候我们就需要 .shift() 了。 它的工作原理就像 .pop(),但它移除的是第一个元素,而不是最后一个。
示例:
const ourArray = ["Stimpson", "J", ["cat"]]; const removedFromOurArray = ourArray.shift();
removedFromOurArray 值为 Stimpson,ourArray 值为 [“J”, [“cat”]]
使用 unshift 方法操作数组
不仅可以 shift(移出)数组中的第一个元素,也可以 unshift(移入)一个元素到数组的头部。
.unshift() 函数用起来就像 .push() 函数一样,但不是在数组的末尾添加元素,unshift() 在数组的头部添加元素。
示例:
const ourArray = ["Stimpson", "J", "cat"]; ourArray.shift(); ourArray.unshift("Happy");
在 shift、ourArray 后值为 [“J”, “cat”]。 在 unshift、ourArray 后值为 [“Happy”, “J”, “cat”]。
全局作用域和函数
在 JavaScript 中,作用域涉及到变量的作用范围。 在函数外定义的变量具有 全局 作用域。 这意味着,具有全局作用域的变量可以在代码的任何地方被调用。
未使用 let 或 const 关键字声明的变量会在 global 范围内自动创建
。 当在代码其他地方无意间定义了一个变量,刚好变量名与全局变量相同,这时会产生意想不到的后果。 你应该总是用 let 或 const 声明你的变量。
使用 let 或 const,在任何函数之外声明一个名为 myGlobal 的全局变量。 并给它一个初始值 10。
在函数 fun1中,赋值 5 给 oopsGlobal,不使用 var、let 或 const 关键字。
// 在这行下面声明 myGlobal 变量 let myGlobal=10; function fun1() { // 给 oopsGlobal 赋值 5 oopsGlobal=5; } // 只修改这一行上面的代码 function fun2() { let output = ""; if (typeof myGlobal != "undefined") { output += "myGlobal: " + myGlobal; } if (typeof oopsGlobal != "undefined") { output += " oopsGlobal: " + oopsGlobal; } console.log(output); }
局部作用域和函数
在一个函数内声明的变量,以及该函数的参数都具有局部(local)作用域。 这意味着它们只在该函数内可见。
这是在函数 myTest 内声明局部变量 loc 的例子:
function myTest() { const loc = "foo"; console.log(loc); } myTest(); console.log(loc);
myTest() 函数调用将在控制台中显示字符串 foo。 console.log(loc) 行(在 myTest 函数之外)将抛出错误,因为 loc 未在函数之外定义。
函数中的全局作用域和局部作用域
一个程序中有可能具有相同名称的局部变量 和全局变量。 在这种情况下,局部变量将会优先于全局变量。
下面为例:
const someVar = "Hat"; function myFun() { const someVar = "Head"; return someVar; }
函数 myFun 将会返回字符串 Head,因为局部变量的优先级更高。
给 myOutfit 添加一个局部变量来将 outerWear 的值重载为 sweater。
// 设置 const outerWear = "T-Shirt"; function myOutfit() { // 只修改这一行下面的代码 const outerWear="sweater"; // 只修改这一行上面的代码 return outerWear; } myOutfit();
队列
排队
在计算机科学中队列(queue)是一个抽象的数据结构(Data Structure),队列中的条目都是有秩序的。 新的条目会被加到队列的末尾,旧的条目会从队列的头部被移出。
写一个函数 nextInLine,用一个数组(arr)和一个数字(item)作为参数。
把数字添加到数组的结尾,然后移出数组的第一个元素。
最后 nextInLine 函数应该返回被删除的元素。
==的特色,自动类型转换
在 JavaScript 中,为了让两个不同的数据类型(例如 numbers 和 strings)的值可以作比较,它必须把一种类型转换为另一种类型。 这叫作 “类型强制转换”。 转换之后,可以像下面这样来比较:
1 == 1 // true 1 == 2 // false 1 == '1' // true "3" == 3 // true
严格相等运算符
严格相等运算符(===)是相对相等操作符(==)的另
一种比较操作符。 与相等操作符转换数据两类型不同,严格相等运算符不会做类型转换。
如果比较的值类型不同,那么在严格相等运算符比较下它们是不相等的,会返回 false 。
示例
3 === 3 // true 3 === '3' // false
在第二个例子中,3 是一个 Number 类型,而 ‘3’ 是一个 String 类型。
比较不同值
在上两个挑战中,我们学习了相等运算符 () 和严格相等运算符 (=)。 现在让我们快速回顾并实践一下。
如果要比较的值不是同一类型,相等运算符会先执行数据类型转换,然后比较值。 而严格相等运算符只比较值,不会进行数据类型转换。
示例
3 == '3' 返回 true ,因为 JavaScript 执行了从字符串到数字类型的转换。 3 === '3' 返
回 false,因为类型不同,没有进行类型转换。
提示 在 JavaScript 中,你可以使用 typeof 运算符确定变量或值的类型,如下所示:
typeof 3 typeof '3'
typeof 3 返回字符串 number,typeof ‘3’ 返回字符串 string。
严格不等运算符
严格不相等运算符(!==)与全等运算符是相反的。 这意味着严格不相等并返回 false 的地方,用严格相等运算符会返回 true,反之亦然。 严格不相等运算符不会转换值的数据类型。
示例
3 !== 3 // false 3 !== '3' // true 4 !== 3 // true
大于运算符-转换
使用大于运算符(>)来比较两个数字。 如果大于运算符左边的数字大于右边的数字,将会返回 true。 否则,它返回 false。
与相等运算符一样,大于运算符在比较的时候,会转换值的数据类型。
例如:
5 > 3 // true 7 > '3' // true 2 > 3 // false '1' > 9 // false