JavaScript语法JavaScript语法是编写该语言程序的一套规则。 JavaScript标准库缺少官方標準串流函數(除了 起源布兰登·艾克在JavaScript 1.1 规范的第一段中[1][2]总结如下:
基础大小写敏感JavaScript是大小写敏感的。经常以一个大写字母开始构造函数的名称 ,一个小写字母开始函数或变量的名字。 例子: var a = 5;
console.log(a); // 5
console.log(A); // throws a ReferenceError: A is not defined
空白和分号不像在C语言中,JavaScript源代码中的空白可以直接影响形式语义学。JavaScript里的语句用分号结束。因为自动分号插入(ASI),也就是说,一些符合语法规则的的语句在分析到换行符时会被认为是完整的,如同在换行符前面插入了一个分号。一些当局建议显式地写结束语句的分号,因为它也许会减少自动分号插入未曾预料的效果。[3] 有两个问题:有五个符记既能开始一条语句,也能扩展一条完整的语句;以及五个受限的语句(production),其中换行在一些位置不被允许,潜在可能会产生不正确的解析。[4]
五个有问题的符记是左圆括号“ a = b + c
(d + e).foo()
// Treated as:
// a = b + c(d + e).foo();
有建议前面的语句以分号结束。
有些人建议在以“ a = b + c
(d + e).foo()
// Treated as:
// a = b + c(d + e).foo();
最初的分号有时也在JavaScript库中使用,在它们被追加到另一个省略尾部分号的库的情况下,因为这可能会导致初始语句的模糊不清。
五个受限的语句是 return
a + b;
// Returns undefined. Treated as:
// return;
// a + b;
// Should be written as:
// return a + b;
注释// a short, one-line comment
/* this is a long, multi-line comment
about my script. May it one day
be great. */
/* Comments /* may not be nested */ Syntax error */
变量标准JavaScript中的变量没有附加类型,因此任何值(每个值都有一个类型)可以存储在任何变量中。从ES6(该语言的第6版)开始,变量可以用 从JavaScript1.5 开始,可以在标识符中使用ISO 8859-1或Unicode字符(或 作用域和提升用 对于 函数声明,它声明一个变量并为其分配一个函数,类似于变量语句,但除了可以提升声明之外,它们还提升了赋值——就好像整个语句出现在包含的函数的顶部一样——因此前向引用(forward reference)也是允许的:函数语句在包含它的函数中的位置是不相关的。这不同于在 因而,如: var func = function() { .. } // 仅提升声明
function func() { .. } // 声明和赋值被提升
块作用域可以通过将整个块包装在一个函数中然后执行它来产生——这被称为立即调用函数表达式模式——或者通过使用 声明和赋值在作用域外声明的变量是全局变量。如果一个变量在更高的作用域中声明,它可以被子作用域(child scope)访问。 当JavaScript尝试解析标识符时,它会在本地作用域内查找。如果没有找到这个标识符,它会在下一个外部作用域中查找,依此类推,直到抵达全局变量所在的全局作用域。如果仍未找到,JavaScript将引发 给标识符赋值时,JavaScript会通过完全相同的过程来获取此标识符;但如果在全局范围内找不到它,将在创建的作用域内创建“变量”。[11]因此,如果给未声明的变量赋值,会被创建为一个全局变量。在全局范围内(即在任何函数体之外或在 请注意,JavaScript的严格模式(strict mode)禁止给未声明的变量赋值,从而避免了全局命名空间污染。 例子变量声明和作用域的一些例子: var x1 = 0; // 一个全局变量,因为未在任何函数内
let x2 = 0; // 也是全局变量,因为未在任何块内
function f() {
var z = 'foxes', r = 'birds'; // 2个局部变量
m = 'fish'; //全局变量,因为给未声明的变量赋值
function child() {
var r = 'monkeys'; //为局部变量,不影响父函数中变量r的值"birds"
z = 'penguins'; //闭包:子函数也能访问父函数中的变量
}
twenty = 20; //该变量在下一行声明,但在该函数内任何位置都可用,这里是在声明之前使用
var twenty;
child();
return x1 + x2; //这里使用的x1和x2是全局变量
}
f();
console.log(z); // 这将抛出ReferenceError异常,因为z不可用了
for (let i = 0; i < 10; i++) console.log(i);
console.log(i); // 抛出 ReferenceError: i is not defined
for (const i = 0; i < 10; i++) console.log(i); // 抛出TypeError: Assignment to constant variable
const pi; // 抛出SyntaxError: Missing initializer in const declaration
基本数据类型JavaScript语言提供6种基本数据类型:
一些基本数据类型还提供一组命名值来表示类型边界的范围。这些命名值在下面的相应子节中描述。 Undefined“undefined”值被赋值给所有未初始化变量,在查看不存在的对象属性时也返回这个值。在布尔上下文中,未定义值被认为是假值。 注意: undefined 被认为是真正的基本数据类型。 除非显式转换,否则与在逻辑上下文中评估为false的其他类型相比,未定义的值可能会出现不可预料的行为。 var test; // 变量被声明但未定义,其值被赋为undefined值
var testObj = {};
console.log(test); // test的值存在,显示为undefined
console.log(testObj.myProp); // testObj存在,但属性不存在,显示为undefined
console.log(undefined == null); // 未强制类型检查,显示为true
console.log(undefined === null); // 强制类型检查,显示为false
注意:没有内建的语言字面量用于undefined。因此 下属函数不会如期望那样工作: function isUndefined(x) { var u; return x === u; } // 如这个...
function isUndefined(x) { return x === void 0; } // ... 或第二个
function isUndefined(x) { return (typeof x) === "undefined"; } // ... 或第三个
调用 NumberNumber数据类型表示IEEE-754浮点双精度。不能精确表示一些实数或分数。如: console.log(0.2 + 0.1 === 0.3); // displays false
console.log(0.94 - 0.01); // displays 0.9299999999999999
因此,无论何时格式化输出,都应使用诸如toFixed()方法之类的例程对数字进行舍入。[12] 数字可以用这些符号中的任何一种来指定: 345; // 一个整数
34.5; // 一个浮点数
3.45e2; // 另一个浮点数
0b1011; // 二进制整数
0o377; // 八进制整数
0xFF; // 十六进制整数,A-F可大写可小写
ES2021引入了数字分隔符_ (the underscore): 1_000_000_000; // 用于大数
1_000_000.5; // 支持十进制
1_000e1_000; // 支持科学计数法
//支持二进制、八进制、十六进制
0b0000_0000_0101_1011;
0o0001_3520_0237_1327;
0xFFFF_FFFF_FFFF_FFFE;
// 但是您能在数的非数字部分旁边,或开头或结尾处使用分隔符
_12; // 变量未定义(下划线使其成为变量标识符)
12_; // 语法错误(不能在数字的末尾)
12_.0; // 语法错误(在小数点旁边放置分隔符没有意义)
12._0; // 语法错误
12e_6; // 语法错误(“e”旁边,非数字。在开头放置分隔符没有意义)
1000____0000; // 语法错误(“_”旁边,非数字。一次只允许 1 个分隔符
Number类型的范围+∞, −∞和NaN(Not a Number)可以通过两个程序表达式获得: Infinity; // 正无穷大(用-Infinity 获得负无穷大)
NaN; // Not-A-Number值,字符串到数字转换时也作为失败返回值
Infinity 和 NaN 是数字: typeof Infinity; // 返回"number"
typeof NaN; // 返回"number"
这三个特殊值对应并按照IEEE-754描述的方式运行。 Number构造函数(用作函数),或一元+或-可用于执行显式数值转换: var myString = "123.456";
var myNumber1 = Number(myString);
var myNumber2 = +myString;
当用作构造函数时,会创建一个数值包装对象(尽管它用处不大): myNumericWrapper = new Number(123.456);
但是,NaN 不等于自身: const nan = NaN;
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(NaN !== NaN); // true
console.log(nan !== nan); // true
//可用isNaN方法检查NaN
console.log(isNaN("converted to NaN")); // true
console.log(isNaN(NaN)); // true
console.log(Number.isNaN("not converted")); // false
console.log(Number.isNaN(NaN)); // true
BigIntBigInts 可用于任意大的整数。特别是大于253 - 1的整数,这是JavaScript可以用 Number 原语可靠表示的最大数字,并由Number.MAX_SAFE_INTEGER常量表示。 let t = 100n;
let t1 = BigInt('100');
let t2 = BigInt('0x64');
let t3 = BigInt(100);
//这几种方法,都可以定义BigInt
Math的方法不支持BigInt。 JSON.stringify不支持BigInt,需要 toString方法支持BigInt,radix有效值是[2,36],默认是10。 BigInt除法,结果会被截断为整数,不是浮点数。如: StringJavaScript中的字符串是一个字符序列。在JavaScript中,可以通过将一系列字符放在双引号(") 或单引号(')之间直接创建字符串(作为字面量)。此种字符串必须写在单行上,但可包含转义的换行符(如\n). JavaScript标准允许反引号字符(`,即重音符或反撇号)引用多行字符串字面量,但这仅在2016年开始的某些浏览器上支持:Firefox和Chrome,但Internet Explorer 11不支持。[13] var greeting = "Hello, World!";
var anotherGreeting = 'Greetings, people of Earth.';
可以使用charAt方法(由String.prototype提供)访问字符串中的单个字符。这是访问字符串中的单个字符时的首选方式,因为它也适用于非现代浏览器: var h = greeting.charAt(0);
在现代浏览器中,可以通过与数组相同的表示法访问字符串中的单个字符: var h = greeting[0];
但是,JavaScript字符串是不可变的: greeting[0] = "H"; // Fails.
如果字符串具有相同的内容,则将相等运算符 ("==") 应用于两个字符串将返回 true,这意味着:具有相同的长度并包含相同的字符序列(大小写对字母很重要)。因此: var x = "World";
var compare1 = ("Hello, " +x == "Hello, World"); // Here compare1 contains true.
var compare2 = ("Hello, " +x == "hello, World"); // Here compare2 contains false since the first characters of the second operands are not of the same case.
除非转义,否则不能嵌套相同类型的引号: var x = '"Hello, World!" he said.'; // Just fine.
var x = ""Hello, World!" he said."; // Not good.
var x = "\"Hello, World!\" he said."; // Works by escaping " with \"
String构造函数创建一个字符串对象(一个包装字符串的对象): var greeting = new String("Hello, World!");
这些对象有一个valueOf方法,返回包装在其中的原始字符串: var s = new String("Hello !");
typeof s; // Is 'object'.
typeof s.valueOf(); // Is 'string'.
两个String对象之间的相等与字符串原语不同: var s1 = new String("Hello !");
var s2 = new String("Hello !");
s1 == s2; // Is false, because they are two distinct objects.
s1.valueOf() == s2.valueOf(); // Is true.
BooleanJavaScript提供了一个带有真假字面量的布尔数据类型。typeof运算符为这些基本类型返回字符串“"boolean"”。 在逻辑上下文中使用时,由于自动类型转换,0、-0、null、NaN、undefined和空字符串("")求值为false。 所有其他值(前一个列表的补集)求值为true,包括字符串"0"、"false"和任何对象。 类型转换使用类型检查的比较运算符( 当需要类型转换时,JavaScript会按如下方式转换Boolean、Number、String或Object操作数:[14]
道格拉斯·克羅克福特提倡用“truthy”和“falsy”来描述各种类型的值在逻辑上下文中的行为方式,特别是在边缘情况下。[15]在JavaScript的早期版本中,二元逻辑运算符返回一个布尔值,但现在它们返回一个操作数。在合取( // Automatic type coercion
console.log(true == 2 ); // false... true → 1 !== 2 ← 2
console.log(false == 2 ); // false... false → 0 !== 2 ← 2
console.log(true == 1 ); // true.... true → 1 === 1 ← 1
console.log(false == 0 ); // true.... false → 0 === 0 ← 0
console.log(true == "2"); // false... true → 1 !== 2 ← "2"
console.log(false == "2"); // false... false → 0 !== 2 ← "2"
console.log(true == "1"); // true.... true → 1 === 1 ← "1"
console.log(false == "0"); // true.... false → 0 === 0 ← "0"
console.log(false == "" ); // true.... false → 0 === 0 ← ""
console.log(false == NaN); // false... false → 0 !== NaN
console.log(NaN == NaN); // false...... NaN is not equivalent to anything, including NaN.
// Type checked comparison (no conversion of types and values)
console.log(true === 1); // false...... data types do not match
// Explicit type coercion
console.log(true === !!2); // true.... data types and values match
console.log(true === !!0); // false... data types match, but values differ
console.log( 1 ? true : false); // true.... only ±0 and NaN are "falsy" numbers
console.log("0" ? true : false); // true.... only the empty string is "falsy"
console.log(Boolean({})); // true.... all objects are "truthy"
new运算符可用于为布尔基本类型创建对象包装器。但是,typeof运算符不返回对象包装器的boolean,它返回object。因为所有对象都求值为true,所以必须使用诸如.valueOf()或.toString()之类的方法来检索包装的值。对于Boolean类型的显式强制,Mozilla建议优先使用Boolean()函数(没有new)而不是 Boolean 对象。 var b = new Boolean(false); // Object false {}
var t = Boolean(b); // Boolean true
var f = Boolean(b.valueOf()); // Boolean false
var n = new Boolean(b); // Not recommended
n = new Boolean(b.valueOf()); // Preferred
if (0 || -0 || "" || null || undefined || b.valueOf() || !new Boolean() || !t) {
console.log("Never this");
} else if ([] && {} && b && typeof b === "object" && b.toString() === "false") {
console.log("Always this");
}
SymbolECMAScript6引入的新类型。一个Symbol是独一无二且不可变的标识符。 例如: var x = Symbol(1);
var y = Symbol(1);
console.log(x === y); // => false
var symbolObject = {};
var normalObject = {};
// since x and y are unique,
// they can be used as unique keys in an object
symbolObject[x] = 1;
symbolObject[y] = 2;
console.log(symbolObject[x]); // => 1
console.log(symbolObject[y]); // => 2
// as compared to normal numeric keys
normalObject[1] = 1;
normalObject[1] = 2; // overrides the value of 1
console.log(normalObject[1]); // => 2
// changing the value of x does not change the key stored in the object
x = Symbol(3);
console.log(symbolObject[x]); // => undefined
// changing x back just creates another unique Symbol
x = Symbol(1);
console.log(symbolObject[x]); // => undefined
存在well known symbols。其中一个是 let x = [1, 2, 3, 4]; // x is an Array
x[Symbol.iterator] === Array.prototype[Symbol.iterator]; // and Arrays are iterable
const xIterator = x[Symbol.iterator](); // The [Symbol.iterator] function should provide an iterator for x
xIterator.next(); // { value: 1, done: false }
xIterator.next(); // { value: 2, done: false }
xIterator.next(); // { value: 3, done: false }
xIterator.next(); // { value: 4, done: false }
xIterator.next(); // { value: undefined, done: true }
xIterator.next(); // { value: undefined, done: true }
// for..of loops automatically iterate values
for (const value of x) {
console.log(value); // 1 2 3 4
}
// Sets are also iterable:
[Symbol.iterator] in Set.prototype; // true
for (const value of new Set(['apple', 'orange'])) {
console.log(value); // "apple" "orange"
}
原生对象JavaScript语言提供了一些原生对象(native object)。JavaScript原生对象被认为是JavaScript规范的一部分。 尽管有JavaScript环境,但这组对象应该始终可用。 Array数组(array)是从 与C语言家族的编程语言一样,数组使用从零开始的索引方案:通过 var myArray = []; // Point the variable myArray to a newly ...
// ... created, empty Array
myArray.push("hello World"); // Fill the next empty index, in this case 0
console.log(myArray[0]); // Equivalent to console.log("hello World");
数组有一个 可以使用普通对象属性访问表示法访问 myArray[1]; // the 2nd item in myArray
myArray["1"];
以上两个是等价的。 不能使用“点”表示法或带有替代数字表示的字符串: myArray.1; // syntax error
myArray["01"]; // not the same as myArray[1]
声明一个数组可用 let myArray;
// Array literals
myArray = [1, 2]; // length of 2
myArray = [1, 2,]; // same array - You can also have an extra comma at the end
// It's also possible to not fill in parts of the array
myArray = [0, 1, /* hole */, /* hole */, 4, 5]; // length of 6
myArray = [0, 1, /* hole */, /* hole */, 4, 5,]; // same array
myArray = [0, 1, /* hole */, /* hole */, 4, 5, /* hole */,]; // length of 7
// With the constructor
myArray = new Array(0, 1, 2, 3, 4, 5); // length of 6
myArray = new Array(365); // an empty array with length 365
数组实现为“稀疏数组”,只有定义的元素占用了内存。设置 可以使用对象声明字面量来创建其行为类似于其他语言中的关联数组对象: dog = {color: "brown", size: "large"};
dog["color"]; // results in "brown"
dog.color; // also results in "brown"
可以使用对象和数组声明字面量来快速创建关联数组、多维数组或两者兼有的数组。从技术上讲,JavaScript不支持多维数组,但可以使用数组数组来模仿它们: cats = [{color: "brown", size: "large"},
{color: "black", size: "small"}];
cats[0]["size"]; // results in "large"
dogs = {rover: {color: "brown", size: "large"},
spot: {color: "black", size: "small"}};
dogs["spot"]["size"]; // results in "small"
dogs.rover.color; // results in "brown"
Date
new Date(); // create a new Date instance representing the current time/date.
new Date(2010, 2, 1); // create a new Date instance representing 2010-Mar-01 00:00:00
new Date(2010, 2, 1, 14, 25, 30); // create a new Date instance representing 2010-Mar-01 14:25:30
new Date("2010-3-1 14:25:30"); // create a new Date instance from a String.
提供了抽取字段的方法,以及有用的 var d = new Date(2010, 2, 1, 14, 25, 30); // 2010-Mar-01 14:25:30;
// Displays '2010-3-1 14:25:30':
console.log(d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + ' '
+ d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
// Built-in toString returns something like 'Mon Mar 01 2010 14:25:30 GMT-0500 (EST)':
console.log(d);
Error用 throw new Error("Something went wrong.");
这可被try...catch...finally块捕获。将在异常处理节中详述。 MathThe Math object contains various math-related constants (for example, ) and functions (for example, cosine). (Note that the object has no constructor, unlike or . All its methods are "static", that is "class" methods.) All the trigonometric functions use angles expressed in radians, not degrees or grads. Math对象包含各种与数学相关的常数(例如,π)和函数(例如,余弦)。 请注意,与Array或Date不同,Math对象没有构造函数。它的所有方法都是“静态的”,即“类”方法。所有三角函数都使用以弧度表示角度,而不是度数或百分度。
正则表达式/expression/.test(string); // returns Boolean
"string".search(/expression/); // returns position Number
"string".replace(/expression/, replacement);
// Here are some examples
if (/Tom/.test("My name is Tom")) console.log("Hello Tom!");
console.log("My name is Tom".search(/Tom/)); // == 11 (letters before Tom)
console.log("My name is Tom".replace(/Tom/, "John")); // == "My name is John"
字符类// \d - digit
// \D - non digit
// \s - space
// \S - non space
// \w - word char
// \W - non word
// [ ] - one of
// [^] - one not of
// - - range
if (/\d/.test('0')) console.log('Digit');
if (/[0-9]/.test('6')) console.log('Digit');
if (/[13579]/.test('1')) console.log('Odd number');
if (/\S\S\s\S\S\S\S/.test('My name')) console.log('Format OK');
if (/\w\w\w/.test('Tom')) console.log('Hello Tom');
if (/[a-zA-Z]/.test('B')) console.log('Letter');
字符匹配// A...Z a...z 0...9 - alphanumeric
// \u0000...\uFFFF - Unicode hexadecimal
// \x00...\xFF - ASCII hexadecimal
// \t - tab
// \n - new line
// \r - CR
// . - any character
// | - OR
if (/T.m/.test('Tom')) console.log ('Hi Tom, Tam or Tim');
if (/A|B/.test("A")) console.log ('A or B');
重复// ? - 0 or 1 match
// * - 0 or more
// + - 1 or more
// {n} - exactly n
// {n,} - n or more
// {0,n} - n or less
// {n,m} - range n to m
if (/ab?c/.test("ac")) console.log("OK"); // match: "ac", "abc"
if (/ab*c/.test("ac")) console.log("OK"); // match: "ac", "abc", "abbc", "abbbc" etc.
if (/ab+c/.test("abc")) console.log("OK"); // match: "abc", "abbc", "abbbc" etc.
if (/ab{3}c/.test("abbbc")) console.log("OK"); // match: "abbbc"
if (/ab{3,}c/.test("abbbc")) console.log("OK"); // match: "abbbc", "abbbbc", "abbbbbc" etc.
if (/ab{1,3}c/.test("abc")) console.log("OK"); // match: "abc", "abbc", "abbbc"
Anchors// ^ - string starts with
// $ - string ends with
if (/^My/.test("My name is Tom")) console.log ("Hi!");
if (/Tom$/.test("My name is Tom")) console.log ("Hi Tom!");
子表达式// ( ) - groups characters
if (/water(mark)?/.test("watermark")) console.log("Here is water!"); // match: "water", "watermark",
if (/(Tom)|(John)/.test("John")) console.log("Hi Tom or John!");
Flag// /g - global
// /i - ignore upper/lower case
// /m - allow matches to span multiple lines
console.log("hi tom!".replace(/Tom/i, "John")); // == "hi John!"
console.log("ratatam".replace(/ta/, "tu")); // == "ratutam"
console.log("ratatam".replace(/ta/g, "tu")); // == "ratutum"
高级方法my_array = my_string.split(my_delimiter);
// example
my_array = "dog,cat,cow".split(","); // my_array==["dog","cat","cow"];
my_array = my_string.match(my_expression);
// example
my_array = "We start at 11:30, 12:15 and 16:45".match(/\d\d:\d\d/g); // my_array==["11:30","12:15","16:45"];
Capturing groupvar myRe = /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})/;
var results = myRe.exec("The date and time are 2009-09-08 09:37:08.");
if (results) {
console.log("Matched: " + results[0]); // Entire match
var my_date = results[1]; // First group == "2009-09-08"
var my_time = results[2]; // Second group == "09:37:08"
console.log("It is " + my_time + " on " + my_date);
} else console.log("Did not find a valid date!");
函数JavaScript的每个函数是 // x, y is the argument. 'return x + y' is the function body, which is the last in the argument list.
var add = new Function('x', 'y', 'return x + y');
add(1, 2); // => 3
上述加法函数也可定义为函数表达式: var add = function(x, y) {
return x + y;
};
add(1, 2); // => 3
ES6中,增加了箭头函数语法(arrow function syntax)。与 var add = (x, y) => {return x + y;};
// values can also be implicitly returned (i.e. no return statement is needed)
var addImplicit = (x, y) => x + y;
add(1, 2); // => 3
addImplicit(1, 2) // => 3
对于需要提升的函数,专门的表达式: function add(x, y) {
return x + y;
}
add(1, 2); // => 3
提升允许你在声明之前使用它: add(1, 2); // => 3, not a ReferenceError
function add(x, y) {
return x + y;
}
函数实例可具有属性和方法: function subtract(x, y) {
return x - y;
}
console.log(subtract.length); // => 2, arity of the function (number of arguments)
console.log(subtract.toString());
/*
"function subtract(x, y) {
return x - y;
}"
*/
运算符'+'运算符重载:它用于字符串连接和算术加法。 当无意中混合字符串和数字时,这可能会导致问题。 作为一元运算符,它可以将数字字符串转换为数字。 // Concatenate 2 strings
console.log('He' + 'llo'); // displays Hello
// Add two numbers
console.log(2 + 6); // displays 8
// Adding a number and a string results in concatenation (from left to right)
console.log(2 + '2'); // displays 22
console.log('$' + 3 + 4); // displays $34, but $7 may have been expected
console.log('$' + (3 + 4)); // displays $7
console.log(3 + 4 + '7'); // displays 77, numbers stay numbers until a string is added
// Convert a string to a number using the unary plus
console.log(+'2' === 2); // displays true
console.log(+'Hello'); // displays NaN
类似地, '*'运算符也是重载的:可以把字符串转为数。 console.log(2 + '6'*1); // displays 8
console.log(3*'7'); // 21
console.log('3'*'7'); // 21
console.log('hello'*'world'); // displays NaN
算术运算符JavaScript支持下述二元算术运算符:
JavaScript支持下述酉算术运算符:
例如: var x = 1;
console.log(++x); // x becomes 2; displays 2
console.log(x++); // displays 2; x becomes 3
console.log(x); // x is 3; displays 3
console.log(x--); // displays 3; x becomes 2
console.log(x); // displays 2; x is 2
console.log(--x); // x becomes 1; displays 1
模运算符显示除以模数后的余数。 如果涉及负数,则返回值取决于操作数。 var x = 17;
console.log(x%5); // displays 2
console.log(x%6); // displays 5
console.log(-x%5); // displays -2
console.log(-x%-5); // displays -2
console.log(x%-5); // displays 2
要始终返回非负数,请重新添加模数并再次应用模运算符: var x = 17;
console.log((-x%5+5)%5); // displays 3
赋值复合运算符
基本类型的赋值: var x = 9;
x += 1;
console.log(x); // displays: 10
x *= 30;
console.log(x); // displays: 300
x /= 6;
console.log(x); // displays: 50
x -= 3;
console.log(x); // displays: 47
x %= 7;
console.log(x); // displays: 5
对象类型的赋值: /**
* To learn JavaScript objects...
*/
var object_1 = {a: 1}; // assign reference of newly created object to object_1
var object_2 = {a: 0};
var object_3 = object_2; // object_3 references the same object as object_2 does
object_3.a = 2;
message(); // displays 1 2 2
object_2 = object_1; // object_2 now references the same object as object_1
// object_3 still references what object_2 referenced before
message(); // displays 1 1 2
object_2.a = 7; // modifies object_1
message(); // displays 7 7 2
object_3.a = 5; // object_3 doesn't change object_2
message(); // displays 7 7 5
object_3 = object_2;
object_3.a=4; // object_3 changes object_1 and object_2
message(); // displays 4 4 4
/**
* Prints the console.log message
*/
function message() {
console.log(object_1.a + " " + object_2.a + " " + object_3.a);
}
解构赋值at its leaves that are to receive the substructures of the assigned value. 在Mozilla的JavaScript中,从1.7版开始,解构赋值(destructuring assignment)允许一次将部分数据结构赋值给多个变量。 赋值的左侧是一个类似于任意嵌套对象/数组字面量的模式,在其叶子处包含左值将接收赋值的子结构。 var a, b, c, d, e;
[a, b, c] = [3, 4, 5];
console.log(a + ',' + b + ',' + c); // displays: 3,4,5
e = {foo: 5, bar: 6, baz: ['Baz', 'Content']};
var arr = [];
({baz: [arr[0], arr[3]], foo: a, bar: b}) = e;
console.log(a + ',' + b + ',' + arr); // displays: 5,6,Baz,,,Content
[a, b] = [b, a]; // swap contents of a and b
console.log(a + ',' + b); // displays: 6,5
[a, b, c] = [3, 4, 5]; // permutations
[a, b, c] = [b, c, a];
console.log(a + ',' + b + ',' + c); // displays: 4,5,3
扩展/休息运算符ECMAScript 2015标准引入了“ 扩展语法提供了另一种解构数组的方法。 它表示指定数组中的元素应用作函数调用中的参数或数组字面量中的项。 换句话说, " var a = [1, 2, 3, 4];
// It can be used multiple times in the same expression
var b = [...a, ...a]; // b = [1, 2, 3, 4, 1, 2, 3, 4];
// It can be combined with non-spread items.
var c = [5, 6, ...a, 7, 9]; // c = [5, 6, 1, 2, 3, 4, 7, 9];
// For comparison, doing this without the spread operator
// creates a nested array.
var d = [a, a]; // d = [[1, 2, 3, 4], [1, 2, 3, 4]]
// It works the same with function calls
function foo(arg1, arg2, arg3) {
console.log(arg1 + ':' + arg2 + ':' + arg3);
}
// You can use it even if it passes more parameters than the function will use
foo(...a); // "1:2:3" → foo(a[0], a[1], a[2], a[3]);
// You can mix it with non-spread parameters
foo(5, ...a, 6); // "5:1:2" → foo(5, a[0], a[1], a[2], a[3], 6);
// For comparison, doing this without the spread operator
// assigns the array to arg1, and nothing to the other parameters.
foo(a); // "1,2,3,4:undefined:undefined"
当在函数声明中使用 function foo(a, b, ...c) {
console.log(c.length);
}
foo(1, 2, 3, 4, 5); // "3" → c = [3, 4, 5]
foo('a', 'b'); // "0" → c = []
剩余参数类似于Javascript的
比较运算符
引用对象的变量只有在引用同一个对象时才相等或者相同: var obj1 = {a: 1};
var obj2 = {a: 1};
var obj3 = obj1;
console.log(obj1 == obj2); //false
console.log(obj3 == obj1); //true
console.log(obj3 === obj1); //true
参见String. 逻辑运算符JavaScript提供4个逻辑运算符: 在逻辑运算上下文中,除下述表达式外,任何表达式的计算结果都为true:
布尔函数可用于显式转换为基础类型 // Only empty strings return false
console.log(Boolean("") === false);
console.log(Boolean("false") === true);
console.log(Boolean("0") === true);
// Only zero and NaN return false
console.log(Boolean(NaN) === false);
console.log(Boolean(0) === false);
console.log(Boolean(-0) === false); // equivalent to -1*0
console.log(Boolean(-2) === true);
// All objects return true
console.log(Boolean(this) === true);
console.log(Boolean({}) === true);
console.log(Boolean([]) === true);
// These types return false
console.log(Boolean(null) === false);
console.log(Boolean(undefined) === false); // equivalent to Boolean()
The NOT operator evaluates its operand as a Boolean and returns the negation. Using the operator twice in a row, as a double negative, explicitly converts an expression to a primitive of type Boolean: console.log( !0 === Boolean(!0));
console.log(Boolean(!0) === !!1);
console.log(!!1 === Boolean(1));
console.log(!!0 === Boolean(0));
console.log(Boolean(0) === !1);
console.log(!1 === Boolean(!1));
console.log(!"" === Boolean(!""));
console.log(Boolean(!"") === !!"s");
console.log(!!"s" === Boolean("s"));
console.log(!!"" === Boolean(""));
console.log(Boolean("") === !"s");
console.log(!"s" === Boolean(!"s"));
三元运算符可用于显式转换: console.log([] == false); console.log([] ? true : false); // “truthy”, but the comparison uses [].toString()
console.log([0] == false); console.log([0]? true : false); // [0].toString() == "0"
console.log("0" == false); console.log("0"? true : false); // "0" → 0 ... (0 == 0) ... 0 ← false
console.log([1] == true); console.log([1]? true : false); // [1].toString() == "1"
console.log("1" == true); console.log("1"? true : false); // "1" → 1 ... (1 == 1) ... 1 ← true
console.log([2] != true); console.log([2]? true : false); // [2].toString() == "2"
console.log("2" != true); console.log("2"? true : false); // "2" → 2 ... (2 != 1) ... 1 ← true
使用后增量( console.log(a || b); // When a is true, there is no reason to evaluate b.
console.log(a && b); // When a is false, there is no reason to evaluate b.
console.log(c ? t : f); // When c is true, there is no reason to evaluate f.
In early versions of JavaScript and JScript, the binary logical operators returned a Boolean value (like most C-derived programming languages). However, all contemporary implementations return one of their operands instead: 在JavaScript和JScript的早期版本中,二元逻辑运算符返回一个布尔值(就像大多数从C派生的编程语言一样)。但是,所有Javascript的当代实现都返回其操作数之一: console.log(a || b); // if a is true, return a, otherwise return b
console.log(a && b); // if a is false, return a, otherwise return b
更熟悉C中的行为的程序员可能会发现这个特性令人惊讶,但它允许更简洁地表达模式,如空值结合运算符: var s = t || "(default)"; // assigns t, or the default value, if t is null, empty, etc.
逻辑赋值
按位运算符
例如: x=11 & 6;
console.log(x); // 2
JavaScript支持酉按位运算符:
位操作赋值
例如: x=7;
console.log(x); // 7
x<<=3;
console.log(x); // 7->14->28->56
字符串
例如: str = "ab" + "cd"; // "abcd"
str += "e"; // "abcde"
str2 = "2" + 2; // "22", not "4" or 4.
??JavaScript最接近的运算符是 const a = b ?? 3;
|| )对任何布尔假值:null , undefined , "" , 0 , NaN , false ,都会取右端操作数的值。控制结构复合语句一对大括号 If ... elseif (expr) {
//statements;
} else if (expr2) {
//statements;
} else {
//statements;
}
三元调解运算符条件运算符创建一个表达式,该表达式根据条件计算为两个表达式之一。 这类似于根据条件选择两个语句之一执行的“if”语句。 即,条件运算符之于表达式就像 if 之于语句。 result = condition ? expression : alternative;
等价于: if (condition) {
result = expression;
} else {
result = alternative;
}
与 if 语句不同,条件运算符不能省略其“else-branch”。 Switch语句JavaScript的switch语句如下: switch (expr) {
case SOMEVALUE:
// statements;
break;
case ANOTHERVALUE:
// statements;
break;
default:
// statements;
break;
}
For循环 for (initial; condition; loop statement) {
/*
statements will be executed every time
the for{} loop cycles, while the
condition is satisfied
*/
}
或: for (initial; condition; loop statement(iteration)) // one statement
For ... in loopfor (var property_name in some_object) {
// statements using some_object[property_name];
}
While循环while (condition) {
statement1;
statement2;
statement3;
...
}
Do ... while循环do {
statement1;
statement2;
statement3;
...
} while (condition);
Withwith语句将所有给定对象的属性和方法添加到以下块的范围内,让它们被引用,就好像它们是局部变量一样。 with (document) {
var a = getElementById('a');
var b = getElementById('b');
var c = getElementById('c');
};
因为with语句的可用性会阻碍程序性能并且被认为会降低代码的清晰度(因为任何给定的变量实际上可能是封闭with的属性),因此在“严格模式”中不允许使用此语句 . LabelJavaScript在大多数实现中都支持嵌套标签。可以为break语句标记循环或块,为 loop1: for (var a = 0; a < 10; a++) {
if (a == 4) {
break loop1; // Stops after the 4th attempt
}
console.log('a = ' + a);
loop2: for (var b = 0; b < 10; ++b) {
if (b == 3) {
continue loop2; // Number 3 is skipped
}
if (b == 6) {
continue loop1; // Continues the first loop, 'finished' is not shown
}
console.log('b = ' + b);
}
console.log('finished');
}
block1: {
console.log('Hello'); // Displays 'Hello'
break block1;
console.log('World'); // Will never get here
}
goto block1; // Parse error.
函数函数没有返回语句的情况下,则返回值undefined。 function gcd(segmentA, segmentB) {
var diff = segmentA - segmentB;
if (diff == 0)
return segmentA;
return diff > 0 ? gcd(segmentB, diff) : gcd(segmentA, -diff);
}
console.log(gcd(60, 40)); // 20
var mygcd = gcd; // mygcd is a reference to the same function as gcd. Note no argument ()s.
console.log(mygcd(60, 40)); // 20
函数时头等对象,可以赋值给其他变量。 调用函数时给出的参数数量不一定与函数定义中的参数数量相对应;在调用时没有匹配实参的命名形参具有值undefined(可以隐式转换为 false)。在函数中,参数也可以通过arguments对象访问; 这提供了使用索引访问所有参数(例如 function add7(x, y) {
if (!y) {
y = 7;
}
console.log(x + y + arguments.length);
};
add7(3); // 11
add7(3, 4); // 9
原始值(数字、布尔值、字符串)按值传递。 对于对象,它是对传递的对象的引用。 var obj1 = {a : 1};
var obj2 = {b : 2};
function foo(p) {
p = obj2; // Ignores actual parameter
p.b = arguments[1];
}
foo(obj1, 3); // Does not affect obj1 at all. 3 is additional parameter
console.log(obj1.a + " " + obj2.b); // writes 1 3
函数可以在其他函数内部声明,并访问外部函数的局部变量。 此外,即使在外部函数退出后,它们也会通过记住外部函数的局部变量来实现完整的闭包。 var v = "Top";
var bar, baz;
function foo() {
var v = "fud";
bar = function() { console.log(v) };
baz = function(x) { v = x; };
}
foo();
baz("Fugly");
bar(); // Fugly (not fud) even though foo() has exited.
console.log(v); // Top
Async/awaitJavaScript中的 如果 许多JavaScript库提供了可返回Promise对象的函数,它们都可以被 下面是一个使用例[23]: async function createNewDoc() {
let response = await db.post({}); // post a new doc
return db.get(response.id); // find by id
}
async function main() {
try {
let doc = await createNewDoc();
console.log(doc);
} catch (err) {
console.log(err);
}
}
main();
对象Object为方便起见,类型通常被细分为“基本”(primitives)和“对象”。 对象是具有标识符的实体(它们仅与自身相同)并将属性名称映射到值(基于原型编程 术语中的“槽”slot)。 对象可以被认为是 关联数组或散列(hash),并且通常使用这些数据结构来实现。但是,对象具有其他功能,例如原型链(prototype chain),这是普通关联数组所没有的。 JavaScript有几种内置对象,分别是 创建对象可以使用构造函数或对象字面量创建对象。构造函数可以使用内置的Object函数或自定义函数。按照惯例,构造函数的名称以大写字母开头: // Constructor
var anObject = new Object();
// Object literal
var objectA = {};
var objectA2 = {}; // A != A2, {}s create new objects as copies.
var objectB = {index1: 'value 1', index2: 'value 2'};
// Custom constructor (see below)
对象字面量和数组字面量允许人们轻松创建灵活的数据结构: var myStructure = {
name: {
first: "Mel",
last: "Smith"
},
age: 33,
hobbies: ["chess", "jogging"]
};
这是 JSON 的基础,它是一种使用类似JavaScript的语法进行数据交换的简单表示法。 方法method是一个已分配给对象的属性名称的函数。与许多面向对象的语言不同,在与对象相关的JavaScript中,函数定义和方法定义没有区别。相反,区别发生在函数调用期间。函数可以作为方法调用。 当作为方法调用时,标准局部变量 this 会自动设置为 "." 左侧的对象实例。(还有 call 和 apply 方法可以显式设置 this - 一些包,例如 jQuery 用 this 做不寻常的事情。) 在下面的示例中,Foo被用作构造函数。构造函数没有什么特别之处——它只是一个初始化对象的普通函数。当与 new 关键字一起使用时,通常情况下,this 设置为新创建的空白对象。 请注意,在下面的示例中,Foo只是为槽分配值,其中一些值是函数。因此它可以为不同的实例分配不同的功能。此示例中没有原型设计。 function px() { return this.prefix + "X"; }
function Foo(yz) {
this.prefix = "a-";
if (yz > 0) {
this.pyz = function() { return this.prefix + "Y"; };
} else {
this.pyz = function() { return this.prefix + "Z"; };
}
this.m1 = px;
return this;
}
var foo1 = new Foo(1);
var foo2 = new Foo(0);
foo2.prefix = "b-";
console.log("foo1/2 " + foo1.pyz() + foo2.pyz());
// foo1/2 a-Y b-Z
foo1.m3 = px; // Assigns the function itself, not its evaluated result, i.e. not px()
var baz = {"prefix": "c-"};
baz.m4 = px; // No need for a constructor to make an object.
console.log("m1/m3/m4 " + foo1.m1() + foo1.m3() + baz.m4());
// m1/m3/m4 a-X a-X c-X
foo1.m2(); // Throws an exception, because foo1.m2 doesn't exist.
构造函数构造函数只需将值分配给新创建对象的槽。 这些值可以是数据或其他函数。 示例:操作对象: function MyObject(attributeA, attributeB) {
this.attributeA = attributeA;
this.attributeB = attributeB;
}
MyObject.staticC = "blue"; // On MyObject Function, not object
console.log(MyObject.staticC); // blue
object = new MyObject('red', 1000);
console.log(object.attributeA); // red
console.log(object["attributeB"]); // 1000
console.log(object.staticC); // undefined
object.attributeC = new Date(); // add a new property
delete object.attributeB; // remove a property of object
console.log(object.attributeB); // undefined
delete object; // remove the whole Object (rarely used)
console.log(object.attributeA); // throws an exception
构造函数本身在对象原型的“构造函数”槽中被引用。 所以, function Foo() {}
// Use of 'new' sets prototype slots (for example,
// x = new Foo() would set x's prototype to Foo.prototype,
// and Foo.prototype has a constructor slot pointing back to Foo).
x = new Foo();
// The above is almost equivalent to
y = {};
y.constructor = Foo;
y.constructor();
// Except
x.constructor == y.constructor // true
x instanceof Foo // true
y instanceof Foo // false
// y's prototype is Object.prototype, not
// Foo.prototype, since it was initialised with
// {} instead of new Foo.
// Even though Foo is set to y's constructor slot,
// this is ignored by instanceof - only y's prototype's
// constructor slot is considered.
函数本身就是对象,可以用来产生类似于“静态属性”(使用 C++/Java 术语)的效果,如下所示。(函数对象还有一个特殊的 对象删除很少使用,因为脚本引擎将垃圾收集不再被引用的对象。 继承JavaScript以Self的方式通过原型设计(prototyping)支持继承层次结构。 在以下示例中,Derived类继承自 Base类。当d创建为Derived时,对Base基础实例的引用被复制到 d.base。 Derive不包含aBaseFunction的值,因此在访问aBaseFunction时从aBaseFunction检索它。 这可以通过改变base.aBaseFunction的值来明确,这反映在d.aBaseFunction的值中。 一些实现允许使用__proto__槽显式访问或设置原型,如下所示。 function Base() {
this.anOverride = function() { console.log("Base::anOverride()"); };
this.aBaseFunction = function() { console.log("Base::aBaseFunction()"); };
}
function Derived() {
this.anOverride = function() { console.log("Derived::anOverride()"); };
}
base = new Base();
Derived.prototype = base; // Must be before new Derived()
Derived.prototype.constructor = Derived; // Required to make `instanceof` work
d = new Derived(); // Copies Derived.prototype to d instance's hidden prototype slot.
d instanceof Derived; // true
d instanceof Base; // true
base.aBaseFunction = function() { console.log("Base::aNEWBaseFunction()"); }
d.anOverride(); // Derived::anOverride()
d.aBaseFunction(); // Base::aNEWBaseFunction()
console.log(d.aBaseFunction == Derived.prototype.aBaseFunction); // true
console.log(d.__proto__ == base); // true in Mozilla-based implementations and false in many others.
下面清楚地显示了在实例创建时对原型的引用是如何“复制”的,但是对原型的更改会影响引用它的所有实例。 function m1() { return "One"; }
function m2() { return "Two"; }
function m3() { return "Three"; }
function Base() {}
Base.prototype.m = m2;
bar = new Base();
console.log("bar.m " + bar.m()); // bar.m Two
function Top() { this.m = m3; }
t = new Top();
foo = new Base();
Base.prototype = t;
// No effect on foo, the *reference* to t is copied.
console.log("foo.m " + foo.m()); // foo.m Two
baz = new Base();
console.log("baz.m " + baz.m()); // baz.m Three
t.m = m1; // Does affect baz, and any other derived classes.
console.log("baz.m1 " + baz.m()); // baz.m1 One
在实践中,使用了这些主题的许多变体,它可能既强大又令人困惑。 异常处理JavaScript 包含一个
try {
// Statements in which exceptions might be thrown
} catch(errorValue) {
// Statements that execute in the event of an exception
} finally {
// Statements that execute afterward either way
}
最初,try块中的语句执行。如果抛出异常,脚本的控制流会立即转移到catch块中的语句,异常可用作错误参数。否则将跳过catch块。 如果catch块不想处理特定错误,它可以 throw(errorValue)。 在任何情况下,finally块中的语句都会被执行。这可用于释放资源,尽管内存会自动进行垃圾回收。 可以省略catch或finally子句。 catch参数是必需的。 Mozilla实现允许多个catch语句,作为对ECMAScript标准的扩展。它们遵循类似于Java中使用的语法: try { statement; }
catch (e if e == "InvalidNameException") { statement; }
catch (e if e == "InvalidIdException") { statement; }
catch (e if e == "InvalidEmailException") { statement; }
catch (e) { statement; }
在浏览器中,onerror比捕获异常更常用。 onerror = function (errorValue, url, lineNr) {...; return true;};
本地函数与方法与网页浏览器不相关。 eval (表达式)将第一个参数计算为表达式,其中可以包括赋值语句。 表达式可以引用函数的局部变量。 但是, var x = 7;
console.log("val " + eval("x + 2"));
参考文献
进一步阅读
外部链接維基教科書中的相關電子教程:JavaScript
|