语法与数据类型

语法

var\let\const

var

声明一个变量,可选初始化一个值。

let

声明一个块作用域的局部变量,可选初始化一个值。

const

声明一个块作用域的只读常量。

用 var 或 let 语句声明的变量,如果没有赋初始值,则其值为 undefined。如果访问一个未声明的变量会导致抛出 ReferenceError

  • undefined 值在布尔类型环境中会被当作 false
  • 数值类型环境中 undefined 值会被转换为 NaN
  • 当你对一个 null 变量求值时,空值 null 在数值类型环境中会被当作 0 来对待
变量提升

一个函数中所有的var语句应尽可能地放在接近函数顶部的地方

  • JavaScript 变量的另一个不同寻常的地方是,你可以先使用变量稍后再声明变量而不会引发异常。这一概念称为变量提升;JavaScript 变量感觉上是被“提升”或移到了函数或语句的最前面。但是,提升后的变量将返回 undefined 值。因此在使用或引用某个变量之后进行声明和初始化操作,这个被提升的变量仍将返回 undefined 值。
  • 在 ECMAScript 6 中,let 和 const 同样会被提升变量到代码块的顶部但是不会被赋予初始值。在变量声明之前引用这个变量,将抛出引用错误(ReferenceError)。这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。
  • 对于函数来说,只有函数声明会被提升到顶部,而函数表达式不会被提升




/** * 例子 2 */ // will return a value of undefined var myvar = "my value"; (function () { console.log(myvar); // undefined var myvar = "local value"; })(); ------------------------------------------------------- console.log(x); // ReferenceError let x = 3; ---------------------------------------------------------- /* 函数声明 */ foo(); // "bar" function foo() { console.log("bar"); } /* 函数表达式 */ baz(); // 类型错误:baz 不是一个函数 var baz = function () { console.log("bar2"); };


常量  

对象属性被赋值为常量是不受保护的,所以下面的语句执行时不会产生错误。

const MY_OBJECT = { key: "value" };
MY_OBJECT.key = "otherValue";

同样的,数组的被定义为常量也是不受保护的,所以下面的语句执行时也不会产生错误。

const MY_ARRAY = ["HTML", "CSS"];
MY_ARRAY.push("JAVASCRIPT");
console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];

全局变量

实际上,全局变量是全局对象的属性。在网页中,(译注:缺省的)全局对象是 window ,所以你可以用形如 window.variable

数据类型

  • 七种基本数据类型:
  • 布尔值(Boolean),有 2 个值分别是:true 和 false
  • null,一个表明 null 值的特殊关键字。JavaScript 是大小写敏感的,因此 null 与 NullNULL或变体完全不同。
  • undefined,和 null 一样是一个特殊的关键字undefined 表示变量未赋值时的属性。
  • 数字(Number),整数或浮点数,例如: 42 或者 3.14159
  • 任意精度的整数(BigInt),可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
  • 字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy"
  • 代表(Symbol,在 ECMAScript 6 中新添加的类型)。一种实例是唯一且不可改变的数据类型。
  • 以及对象(Object)

     对象属性名字可以是任意字符串,包括空串。如果对象属性名字不是合法的 javascript 标识符,它必须用引号包裹



const unusualPropertyNames = { '': '空字符串', '!': '砰!' } console.log(unusualPropertyNames.''); // SyntaxError: Unexpected string console.log(unusualPropertyNames.!); // SyntaxError: Unexpected token ! ----------------------------------------------------------------------- console.log(unusualPropertyNames[""]); // 空字符串 console.log(unusualPropertyNames["!"]); // 砰!



!!!核心基础:1.访问对象属性foo['var']最稳妥  2.字符串插值"${var}"



//访问对象属性 var foo = { a: "alpha", 2: "two" }; console.log(foo.a); // alpha console.log(foo[2]); // two //console.log(foo.2); // SyntaxError: missing ) after argument list //console.log(foo[a]); // ReferenceError: a is not defined console.log(foo["a"]); // alpha console.log(foo["2"]); // two ---------------------------------------------------------------------------- //字符串插值"${var}" var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?`;


数字-》字符串:“+”



x = "The answer is " + 42; // "The answer is 42" y = 42 + " is the answer"; // "42 is the answer"



字符串-》数字:parseInt()、parseFloat()

parseInt 方法只能返回整数,所以使用它会丢失小数部分。另外,调用 parseInt 时最好总是带上进制(radix)参数,这个参数用于指定使用哪一种进制。



x = "The answer is " + 42; // "The answer is 42" y = 42 + " is the answer"; // "42 is the answer"


进制


整数可以用十进制(基数为 10)、十六进制(基数为 16)、八进制(基数为 8)以及二进制(基数为 2)表示。

  • 十进制整数字面量由一串数字序列组成,且没有前缀 0。
  • 八进制的整数以 0(或 0O、0o)开头,只能包括数字 0-7。
  • 十六进制整数以 0x(或 0X)开头,可以包含数字(0-9)和字母 a~f 或 A~F。
  • 二进制整数以 0b(或 0B)开头,只能包含数字 0 和 1。

控制语句与错误处理

throw语句

throw "Error2"; // String type
throw 42; // Number type
throw true; // Boolean type
throw {
  toString: function () {
    return "I'm an object!";
  },
};
------------------------------------------
//可以在抛出异常时声明一个对象。那你就可以在 catch 块中查询到对象的属性。

// Create an object type UserException
function UserException(message) {
  this.message = message;
  this.name = "UserException";
}

// Make the exception convert to a pretty string when used as
// a string (e.g. by the error console)
UserException.prototype.toString = function () {
  return this.name + ': "' + this.message + '"';
};

// Create an instance of the object type and throw it
throw new UserException("Value too high");

try....catch...finally 

换句话说,如果你在 try 代码块中的代码如果没有执行成功,那么你希望将执行流程转入 catch 代码块。如果 try 代码块没有抛出异常,catch 代码块就会被跳过。

finally块无论是否抛出异常都会执行。如果抛出了一个异常,就算没有异常处理,finally块里的语句也会执行。

执行顺序 

function f() {
  try {
    console.log(0);
    throw "bogus";
  } catch (e) {
    console.log(1);
    return true; // this return statement is suspended
    // until finally block has completed
    console.log(2); // not reachable
  } finally {
    console.log(3);
    return false; // overwrites the previous "return"
    console.log(4); // not reachable
  }
  // "return false" is executed now
  console.log(5); // not reachable
}
f(); // console 0, 1, 3; returns false
----------------------------------------------------------------------
function f() {
  try {
    throw "bogus";
  } catch (e) {
    console.log('caught inner "bogus"');
    throw e; // this throw statement is suspended until
    // finally block has completed
  } finally {
    return false; // overwrites the previous "throw"
  }
  // "return false" is executed now
}

try {
  f();
} catch (e) {
  // this is never reached because the throw inside
  // the catch is overwritten
  // by the return in finally
  console.log('caught outer "bogus"');
}

// OUTPUT
// caught inner "bogus"

 Error对象

DOMException、ECMAScript exceptions

function doSomethingErrorProne () {
  if (ourCodeMakesAMistake()) {
    throw (new Error('The message'));
  } else {
    doSomethingToGetAJavascriptError();
  }
}
....
try {
  doSomethingErrorProne();
}
catch (e) {
  console.log(e.name); // logs 'Error'
  console.log(e.message); // logs 'The message' or a JavaScript error message)
}

循环与迭代

基本循环语句

//for语句
for (var i = 0; i < selectObject.options.length; i++) {
      if (selectObject.options[i].selected) {
        numberSelected++;
      }
    }
---------------------------------------------------------
//do...while语句
var i = 0;
do {
  i += 1;
  console.log(i);
} while (i < 5);
----------------------------------------------------------
//while语句
var n = 0;
var x = 0;
while (n < 3) {
  n++;
  x += n;
}
------------------------------------------------------------
break与continue

label语句

一个 label 提供了一个让你在程序中其他位置引用它的标识符。例如,你可以用 label 标识一个循环,然后使用 break 或者 continue 来指出程序是否该停止循环还是继续循环。



var num = 0; outPoint: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j == 5) { break outPoint; // 在 i = 5,j = 5 时,跳出所有循环, // 返回到整个 outPoint 下方,继续执行 } num++; } } alert(num); // 输出 55




var num = 0; outPoint: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j == 5) { continue outPoint; } num++; } } alert(num); // 95




for...in语句

for...in 语句循环一个指定的变量来循环一个对象所有可枚举的属性。JavaScript 会为每一个不同的属性执行指定的语句。


虽然使用 for...in 来迭代数组 Array 元素听起来很诱人,但是它返回的东西除了数字索引外,还有可能是你自定义的属性名字。因此还是用带有数字索引的传统的 for 循环来迭代一个数组比较好,因为,如果你想改变数组对象,比如添加属性或者方法,for...in 语句迭代的是自定义的属性,而不是数组的元素。



function dump_props(obj, obj_name) { var result = ""; for (var i in obj) { result += obj_name + "." + i + " = " + obj[i] + "<br>"; } result += "<hr>"; return result; }




for...of语句

for...of 语句在可迭代对象(包括ArrayMapSetarguments


迭代协议: 迭代协议具体分为两个协议:可迭代协议迭代器协议https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols




let arr = [3, 5, 7]; arr.foo = "hello"; for (let i in arr) { console.log(i); // 输出 "0", "1", "2", "foo" } for (let i of arr) { console.log(i); // 输出 "3", "5", "7" } // 注意 for...of 的输出没有出现 "hello"