stanford-oval/wikipedia huggingface dataset:
JavaScript语法
运算符 > 赋值复合运算符 > 解构赋值

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标准引入了“...”运算符，用于“扩展语法”(spread syntax)和“剩余参数”(rest parameters)的相关概念。
扩展语法提供了另一种解构数组的方法。 它表示指定数组中的元素应用作函数调用中的参数或数组字面量中的项。
换句话说， "..."把"[...foo]"变换为"[foo[0], foo[1], foo[2]]"，而"this.bar(...foo);"变换为"this.bar(foo[0], foo[1], foo[2]);"：
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"
当在函数声明中使用...时，它表示一个剩余参数(rest parameter)。 剩余参数必须是函数参数列表中的最右侧的命名参数。 它将被赋值一个Array，其中包含传递给函数超过其他命名参数的任何多余的参数。 换句话说，它获取传递给函数的“多余的”参数（因此得名）。
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的 arguments对象，它是一个类似数组的对象，包含当前函数调用中的所有参数（命名和未命名）。 然而，与 arguments参数不同的是，剩余参数是真正的Array对象，因此可以直接对它们使用.slice()和.sort()等方法。
...运算符只能与Array对象一起使用。然而，在未来的ECMAScript标准中，有人提议将其扩展到Object。)
运算符 > 比较运算符

| --- | --- |
==: 相等
!=: 不等
>: 大于
>=: 大于等于
<: 小于
<=: 小于等于
===: 带类型检查的相等比较
!==: 不相同
引用对象的变量只有在引用同一个对象时才相等或者相同：
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个逻辑运算符：
酉运算逻辑非 (NOT = !a)
二元运算析取 (OR = a || b)与合取 (AND = a && b)
三元条件运算符 (c ? t : f)
在逻辑运算上下文中，除下述表达式外，任何表达式的计算结果都为true:
字符串: "", '',
数: 0, -0, NaN,
特殊: null, undefined,
布尔: false.
布尔函数可用于显式转换为基础类型Boolean:
// 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
使用后增量(i++)等特性的表达式具有预期的副作用。 JavaScript提供了表达式的短路求值； 仅当左操作数不足以确定表达式的值时，右操作数才被执行。
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.
运算符 > 逻辑赋值

| --- | --- |
??=: 空值结合赋值
||=: 逻辑或赋值
&&=: 逻辑与赋值
运算符 > 按位运算符

| --- | --- |
&: AND
|: OR
^: XOR
!: NOT
<<: 左移(右端零填充)
>>: 右移 (左端为符号位复制)
>>>: 右移(左端零填充)
例如:
x=11 & 6;
console.log(x); // 2
JavaScript支持酉按位运算符:
| --- | --- |
~: NOT (按位取反)
运算符 > 位操作赋值

| --- | --- |
&=: and
|=: or
^=: xor
<<=: 左移(右端零填充)
>>=: 右移 (左端为符号位复制)
>>>=: 右移(左端零填充)
例如:
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最接近的运算符是??, 即"nullish coalescing operator"，从ECMAScript第11版引入。当左端操作数不为"nullish" (null或undefined)，取其值作为结果，否则取右端操作数作为结果。 例如：
const a = b ?? 3;
控制结构 > 复合语句

一对大括号 { } 和一个封闭的语句序列构成一个复合语句，可以在任何可以使用语句的地方使用。
控制结构 > If ... else

if (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;
 }
break; 是可选的； 但是，通常需要它，因为否则代码执行将继续到下一个案例块的主体。
作为预防措施，在最后一个案例的末尾添加一个 break 语句，以防以后添加其他案例。
可用字符串字面量作为case值。
可以使用表达式代替值。
当表达式不匹配任何其他指定的情况时，执行默认情况（可选）。
大括号是必需的。
控制结构 > 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 loop

for (var property_name in some_object) {
  // statements using some_object[property_name];
}
遍历对象的所有可枚举属性。
遍历数组的所有使用索引，包括数组对象的所有用户定义属性（如果有）。 因此，在遍历数组时，最好使用传统的for循环对索引的所有值循环。
不同的Web浏览器在 for...in 循环语句反映哪些属性方面存在差异。理论上，这是由ECMAscript标准定义的称为“DontEnum”的内部状态属性控制的，但实际上，每个浏览器在自省期间返回的属性集略有不同。使用 if (some_object.hasOwnProperty(property_name)) { ...} 测试给定属性很有用。 因此，使用 Array.prototype.newMethod = function() {...} 向数组原型添加方法可能会导致 for ... in 循环遍历方法的名称。
控制结构 > While循环

while (condition) {
  statement1;
  statement2;
  statement3;
  ...
}
控制结构 > Do ... while循环

do {
  statement1;
  statement2;
  statement3;
  ...
} while (condition);
控制结构 > With

with语句将所有给定对象的属性和方法添加到以下块的范围内，让它们被引用，就好像它们是局部变量一样。
with (document) {
  var a = getElementById('a');
  var b = getElementById('b');
  var c = getElementById('c');
};
请注意在每次getElementById()调用之前缺少document.。
因为with语句的可用性会阻碍程序性能并且被认为会降低代码的清晰度（因为任何给定的变量实际上可能是封闭with的属性），因此在“严格模式”中不允许使用此语句 .
控制结构 > Label

JavaScript在大多数实现中都支持嵌套标签。可以为break语句标记循环或块，为continue标记循环。虽然 goto 是保留字， goto在JavaScript中未实现。
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对象访问； 这提供了使用索引访问所有参数（例如 arguments[0], arguments[1], ... arguments[n]），包括那些超出命名参数数量的参数。（虽然参数列表具有 .length 属性，但它不是Array的实例；它没有诸如.slice( )、.sort()等）
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/await

JavaScript中的await运算符只能用于async标注的函数中，或者用于模块的最顶层。
如果await运算符后跟参数为Promise对象，那么函数逻辑会在该Promise对象被resolve之后继续执行，或者在它被reject以后抛出异常（可以进行异常处理）；如果await运算符后跟参数不是Promise对象，那么该值会被直接返回（不会等待）。
许多JavaScript库提供了可返回Promise对象的函数，它们都可以被await——只要符合JavaScript中的Promise规范。JQuery中函数返回的Promise在3.0版本以后才达到了Promises/A+兼容度。
下面是一个使用例：
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有几种内置对象，分别是Array、Boolean、Date、Function、Math、Number、Object、RegExp和String。 其他对象是“宿主对象”(host object)，不是由语言定义，而是由运行时环境定义。 例如，在浏览器中，典型的宿主对象属于DOM（窗口、表单、链接等）。
对象Object > 创建对象

可以使用构造函数或对象字面量创建对象。构造函数可以使用内置的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的语法进行数据交换的简单表示法。
对象Object > 方法

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.
对象Object > 构造函数

构造函数只需将值分配给新创建对象的槽。 这些值可以是数据或其他函数。
示例：操作对象：
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 术语）的效果，如下所示。（函数对象还有一个特殊的 prototype 属性，如下面的“继承”部分所述。）
对象删除很少使用，因为脚本引擎将垃圾收集不再被引用的对象。
对象Object > 继承

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 ... catch ... finally异常处理 语句来处理运行时错误。
try ... catch ... finally语句捕获由错误或 throw 语句导致的异常。 它的语法如下：
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 (表达式)

将第一个参数计算为表达式，其中可以包括赋值语句。 表达式可以引用函数的局部变量。 但是，eval代表了主要的安全风险，因为它允许不良行为者执行任意代码，因此不鼓励使用它。
var x = 7;
console.log("val " + eval("x + 2"));
进一步阅读

Danny Goodman: JavaScript Bible, Wiley, John & Sons, ISBN 0-7645-3342-8.
David Flanagan, Paula Ferguson: JavaScript: The Definitive Guide, O'Reilly & Associates, ISBN 0-596-10199-6.
Thomas A. Powell, Fritz Schneider: JavaScript: The Complete Reference, McGraw-Hill Companies, ISBN 0-07-219127-9.
Axel Rauschmayer: Speaking JavaScript: An In-Depth Guide for Programmers, 460 pages, O'Reilly Media, 25 February 2014, ISBN 978-1449365035. (free online edition （页面存档备份，存于）)
Emily Vander Veer: JavaScript For Dummies, 4th Edition, Wiley, ISBN 0-7645-7659-3.
小花忍冬

| 小花忍冬 |
| --- | --- |

科学分类 
界：: 植物界 Plantae
演化支：:  Tracheophyta
演化支：: 被子植物 Angiosperms
演化支：: 真双子叶植物 Eudicots
演化支：: 菊类植物 Asterids
目：: 川续断目 Dipsacales
科：: 忍冬科 Caprifoliaceae
属：: 忍冬屬 Lonicera
种：: 小花忍冬 L. tatarica
二名法
Lonicera tatarica Trautv.

小花忍冬（学名：）为忍冬科忍冬属下的一个变种。
扩展阅读

維基物種上的相關：小花忍冬
吴家骏

吳家駿可以指：
吴家骏 (经济学家)，中國社會科學院工業經濟研究所研究員
吳家駿 (籃球運動員)，臺灣籃球運動員
Visual C++名字修饰

Name mangling，或者Decorated Name，是指程序设计语言中具有存储性质的对象的名字被编译器改写，以适合编译器、链接器(linker)、汇编器(assembler)使用。所谓的具有存储性质的对象，即lvalue对象，是指要实际占用内存空间、有内存地址的那些实体对象，例如：变量(variables)、函数、函数指针等。C++中的纯虚函数作为特例也属于这一范畴。而数据类型(data type)就不属于具有存储性质的对象。Name mangling如何翻译成中文，尚无广泛接受的译法。可翻译作改名或名字修饰(name decorating)。
对于支持重载(overload)的程序设计语言，name mangling是必需的因而具有特别重要意义。C++允许函数重载
int foo(int i);
void foo(char c);
C++也允许变量名称在不同限定（qualifier)下同名：
std::cout;
::cout;
因此C++的编译器必须给这些函数及变量不同的名字以供程序编译链接、载入时的内部辨别使用。
C++的编译器可大略分为Windows平台上的Microsoft Visual C++与类Unix平台上的GNU CC/g++两大类，分别成了各自操作系统环境下的业界工业标准。例如，Windows平台上的Intel C++ Compiler（ICC）与Digital Mars C++，都与Visual C++保持了二进制兼容(Application Binary Interface, ABI)。而Linux平台上的Intel C++ Compiler（ICC）与HP aC++，都与GCC 3.x/4.x做到二进制兼容。GCC是开源产品，它的内部实现机制是公开的；而Visual C++不公开它内部实现细节，因此在name mangling上并无详尽的正式文档，Visual C++ name mangling的细节属于hacker行为。
一般情况下，编程者不需要知道C/C++函数的修饰名字。但是，如果在汇编源程序或者内联汇编中引用了C/C++函数，就必须使用其正确的修饰名字。
C语言的name mangling

C语言并不支持重载，因此C程序中禁止函数与函数同名，也就没有必要做name mangling。但C语言的函数调用协议(calling conventions)五花八门，用某一种调用协议编译的静态库或动态库的函数，如果用另外的调用协议去调用将会导致错误甚至系统崩溃。因此C语言编译器对函数的名字做少量的修饰，用于区别该函数支持哪种调用协议，这可以给编译、链接、特别是库函数的载入提供额外的检查信息。Microsoft C编译器在八十年代最先引入这种mangling模式，随后各家编译器如Digital Mars, Borland, GNU gcc等纷纷效仿。
目前，C语言常用的调用协议有三种：cdecl, stdcall与fastcall，其它众多调用协议如__pascal, __fortran, __syscall, __far等基本上算是过时了(obsolote)，因此无需考虑。cdecl的函数被改名为_name；stdcall的函数被改名为_name@X；fastcall的函数被改名为@name@X。其中X是函数形参所占用的字节长度(包括那些用寄存器传递的参数, 如fastcall协议). 例如：
int __cdecl foo(int i); // mangled name is _foo;
int __stdcall bar(int j); // mangled name is _bar@4  
int __fastcall qux(int i) ; // mangled name is @qux@4
注意在64位Windows平台上，由于ABI有正式标准可依，只存在一种子程序调用协议，所以该平台上的C语言的函数不在名字前加上下划线(leading underscore). 这会导致一些老的程序(legacy program), 例如使用'alias'去链接C语言的函数的Fortran程序不能正常工作。
C++语言name mangling概述

C++语言由于含有大量复杂的语言特性，如classes, templates, namespaces, operator overloading等，这使得对象的名字在不同使用上下文中具有不同的意义。所以C++的name mangling非常复杂。
这些名字被mangled的对象，实际上都是具有全局属性的存储对象(storage object)，其名字将绑定到所占用内存空间的地址，都有lvalue。存储对象具体可分为数据变量(data variable)与函数(function)。为什么不考虑函数的非静态局部变量、类的非静态数据成员呢？因为编译器把函数的非静态局部变量翻译为[sp]+固定的偏移量；把类的非静态数据成员翻译为this+固定的偏移量。
下文使用了巴科斯-瑙尔范式(BNF)来表述一些name mangling的语法定义。方括号[]表示该项出现0次或1次，除非在方括号后用上下角标给出该项出现的上下限。下文使用类，一般包含了class、struct、union等复合数据类型。
C++语言name mangling概述 > 基本结构

<C++的name mangling> ::= ?<Qualified Name> <Type Information>
 <Qualified Name> ::= <name>@ [<namespace>@]∞0 @
C++中被mangled的名字都使用问号(?)开始，因为这与用字母数字(alphanumeric)、下划线(_)或@开头的C语言程序中的被mangled的名字能完全区分开。
C++中的变量与函数，可定义于名字空间或类中。所以变量与函数受到名字空间或类的限定(qualification)。而名字空间、类又可以嵌套(nest)。
<Qualified Name>表示变量与函数的名字及所定义的名字空间（或类）的嵌套情况。并采用与C++程序中作用域嵌套相反的顺序编码。例如，namespace1::nestedClass::something编码为something@nestedClass@namespace1@@。
Name mangling时，名字的字符串用@符号作为结束标志。例如<name>@，表示<name>这个字符串以@符号作为结束标志。因为名字的长度不是事先确定的。如果一个词法单元的长度是确定的，这些词法单元就不用@作为结尾标志，例如下文中<CV Modifier>只需用单个字母表示，则无需额外的结束标志。
<Type Information>是变量与函数的类型信息的编码表示。对于数据对象，就是它的数据类型，见数据对象的name mangling；对于函数，类型信息就是它的返回值类型、参数类型列表、调用协议等情况，见函数的name mangling。
C++语言name mangling概述 > 数据对象的name mangling

这里所说的数据对象，包括全局变量(global variables)、类的静态数据成员变量(static member variables of classes)。
<数据对象的name mangling> ::= ?<name>@[<namespace>@]∞0@<data access modifier>
         <data type><CV Modifier>
<data access modifier>用于表示数据对象的类别，其编码为：
| 编码 | 含义 |
| --- | --- |
0: Private static member
1: Protected static member
2: Public static member
3: global variable
4: static local variable

<CV Modifier>是数据对象的访问属性的编码表示，一般常用的值有：A表示default对象、B表示const对象、C表示volatile对象、D表示const volatile对象。详见小节:<CV Modifier>。需要注意的是对于指针、数组、引用类型的对象，<CV Modifier>是对所指向的基类型的内存空间的访问属性。
例如：
int alpha;    // mangled as ?alpha@@3HA 其中3表示全局变量，H表示整形，A表示非const非volatile
char beta[6] = "Hello"; // mangled as ?beta@@3PADA 
                   //其中P表示为指针(或一维数组)且指针自身为非const非volatile，
                   //D表示char类型，两次出现的A都表示基类型为非const非volatile 
class myC{
	static int s_v;       // mangled as ?s_v@myC@@0HA 其中0表示私有静态数据成员
};