JAVASCRIPT 学 习 笔 记 mnstory.net 此 文 档 为 学 习 JAVASCRIPT 语 法 记 录 的 比 较, 学 习 教 材 为 阮 一 峰 开 源 的 JavaScript 标 准 参 考 教 程 一 书 语 法 部 分 http://javascript.ruanyifeng.com/ 语 句 一 条 语 句 以 换 行 或 分 号 结 束, 和 SHELL 语 法 一 样, 所 有, 分 号 可 写 可 不 写,JS 解 释 器 会 自 动 给 你 添 加, 这 里 说 的 自 动 还 是 比 较 智 能 的, 比 如 : var str = "i love" + " you " + 533 + str str console console. log (str) 它 也 能 判 断 正 确, 解 析 为 : var str="i love you " + 533 + str; str; console; console.log(str); 其 原 则 是, 没 有 分 号, 能 和 下 行 连 接 到 一 起, 且 语 法 有 意 义 才 会 连 接 这 里 注 意 一 点,return 要 返 回 的 数 据, 不 能 单 独 成 行, 因 为 按 照 JS 添 加 分 号 的 原 则 : return 3 解 析 成 了 : return; 3; function returnok() { return 3
function returnnon1() { return 3 function returnnon2() { return +3 function returnnon3() { return (3) function returnnon4() { return {3; console.log(returnok()) //3 console.log(returnnon1()) //undefined console.log(returnnon2()) //undefined console.log(returnnon3()) //undefined console.log(returnnon4()) //undefined 变 量 声 明 提 升, 函 数 定 义 提 前 var 关 键 字 声 明 的 变 量,javascript 会 将 其 声 明 ( 注 意, 是 声 明 而 非 定 义 ) 提 到 代 码 开 始 处, 这 叫 变 量 声 明 提 升 例 如 : console.log(var1) var var1 = "var1 value" 提 升 后, 其 实 为 : 输 出 : var var1 console.log(var1) var1 = "var1 value" >node hello.js undefined 虽 然 javascript 里, 声 明 变 量 可 使 用 var, 也 可 以 不 使 用 var, 但 是, 不 使 用 var 的, 是
不 会 有 变 量 声 明 提 升 功 能 的, 例 如 : console.log(var1) var1 = "var1 value" 执 行 会 报 错,var1 is not defined hello.js:1 function (exports, require, module, filename, dirname) { console.log(var1) ReferenceError: var1 is not defined at Object.<anonymous> (hello.js:1:75) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3 ^ 对 于 函 数 定 义, 使 用 了 var 同 样 有 声 明 提 升 ( 只 提 升 声 明 而 非 定 义 ), 如 果 不 使 用 var 方 式 定 义 函 数, 此 函 数 的 定 义 会 被 提 前 到 代 码 开 始 ( 定 义 本 身 提 前 ), 例 如 : console.log(funcnovar) //[Function: funcnovar] console.log(funcvar) //undefined funcnovar() //funcnovar called funcvar() //TypeError: undefined is not a function function funcnovar() { console.log("funcnovar called") var funcvar = function () { console.log("funcvar called") 相 当 于 : var funcvar function funcnovar() { console.log("funcnovar called") console.log(funcnovar) console.log(funcvar) funcnovar() funcvar() funcvar = function () {
console.log("funcvar called") 输 出 : >node hello.js [Function: funcnovar] undefined funcnovar called hello.js:4 funcvar() ^ TypeError: undefined is not a function at Object.<anonymous> (hello.js:4:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:906:3 如 果 多 次 采 用 function 命 令, 重 复 声 明 同 一 个 函 数, 则 后 面 的 声 明 会 覆 盖 前 面 的 声 明 函 数 内 部 的 变 量 提 升 与 全 局 作 用 域 一 样, 函 数 作 用 域 内 部 也 会 产 生 变 量 提 升 现 象 var 命 令 声 明 的 变 量, 不 管 在 什 么 位 置, 变 量 声 明 都 会 被 提 升 到 函 数 体 的 头 部 function foo(x,y) { if (x > 100) { var z = x - 100; console.log("x,y,z="+x+","+y+","+z) 这 样 定 义 的 函 数, 等 同 于 var z 提 前 声 明 到 foo 函 数 的 开 始 处 foo() foo(50) foo(400) foo(400,44) foo(400,44,66) foo(undefined,44,66) foo(null,44) //x,y,z=undefined,undefined,undefined //x,y,z=50,undefined,undefined //x,y,z=400,undefined,300 //x,y,z=400,44,300 //x,y,z=400,44,300 //x,y,z=undefined,44,undefined //x,y,z=null,44,undefined
变 量 名 变 量 命 名, 相 对 c 语 言 来 说, 多 了 允 许 $ 开 头, 也 可 以 用 中 文, 当 然 本 语 言 的 关 键 字 是 不 能 用 的, 例 如 : var $i = 44 var 名 字 = " 你 的 名 字?" console.log($i) console.log( 名 字 ) 输 出 : >node hello.js 44 你 的 名 字? Question: undefined 是 关 键 字 吗? var undefined = "change undefined identify" 输 出 : console.log(undefined) >node hello.js change undefined identify 表 明 undefined 并 非 关 键 字 作 用 域 被 大 括 号 刮 起 来 的 一 段 代 码 与 大 多 数 编 程 语 言 不 一 样,JavaScript 的 区 块 不 构 成 单 独 的 作 用 域 (scope) 也 就 是 说, 区 块 中 的 变 量 与 区 块 外 的 变 量, 属 于 同 一 个 作 用 域 Javascript 只 有 两 种 作 用 域 : 一 种 是 全 局 作 用 域, 变 量 在 整 个 程 序 中 一 直 存 在 ; 另 一 种 是 函 数 作 用 域, 变 量 只 在 函 数 内 部 存 在 类 型 typeof var declarevar console.log(typeof declarevar) console.log(typeof notdeclarevar) console.log(typeof undefined) //undefined //undefined //undefined
var func = function(){ console.log(typeof func) console.log(typeof function(){) //function //function console.log(typeof []) console.log(typeof {) console.log(typeof new func) console.log(typeof null) //object //object //object //object console.log(typeof NaN) console.log(typeof 0) //number //number console.log(typeof "") console.log(typeof '') console.log(typeof typeof 1) //string //string //string console.log(typeof true) console.log(typeof false) //boolean //boolean boolean 在 布 尔 表 达 式 中, 这 些 值 undefined,null,false,0( 包 括 +0/-0),NaN,"",'' 默 认 转 换 为 false, 其 他 的 都 为 true if ([]) console.log("[] true") if ({) console.log("{ true") if (!"") console.log("\"\" false") if (!'') console.log("'' false") if (!NaN) console.log("nan false") //if (notdeclarevar) console.log("notdeclarevar ERROR") Number JavaScript 内 部, 所 有 数 字 都 是 以 64 位 浮 点 数 形 式 储 存, 即 使 整 数 也 是 如 此 所 以,1 与 1.0 是 相 等 的, 而 且 1 加 上 1.0 得 到 的 还 是 一 个 整 数, 不 会 像 有 些 语 言 那 样 变 成 小 数 1 === 1.0 // true 1 + 1.0 // 2 由 于 浮 点 数 不 是 精 确 的 值, 所 以 涉 及 小 数 的 比 较 和 运 算 要 特 别 小 心 0.1 + 0.2 === 0.3 // false 0.3 / 0.1 // 2.9999999999999996 (0.3-0.2) === (0.2-0.1) // false 大 于 2 的 53 次 方 以 后, 整 数 运 算 的 结 果 开 始 出 现 错 误 所 以, 大 于 等 于 2 的 53 次 方 的 数
值, 都 无 法 保 持 精 度 console.log(number.max_value) // 1.7976931348623157e+308 console.log(number.min_value) // 5e-324-0 === +0 // true 但 是 (1/+0) === (1/-0) // false 因 为 除 以 正 零 得 到 +Infinity, 除 以 负 零 得 到 -Infinity NaN 不 等 于 任 何 值, 包 括 它 本 身 NaN === NaN // false isnan 方 法 可 以 用 来 判 断 一 个 值 是 否 为 NaN isnan(nan) // true isnan(123) // false isnan("hello") // true 相 当 于 isnan(number("hello")) // true 转 换 为 Number, 容 易 混 淆 的 : 1.undefined 转 换 为 NaN 而 null 转 换 为 0 2."0123" 按 十 进 制 转 换 为 123 而 0123 按 八 进 制 转 换 为 291 3. 对 数 字 而 言,.123 自 动 补 全 为 0.123;123. 自 动 补 全 为 123.0 4. 对 字 符 串 而 言,Number 转 换 也 遵 从 此 规 律,parseInt 不 补 全 前 点 号 的 情 况, 例 如 Number(".123") = 123 而 parseint(".123") = NaN 5. 如 果 传 入 的 参 数 为 object 类 型, 会 调 用 其 valueof 方 法, 如 果 valueof 的 结 果 为 数 字, 字 符 串, 布 尔 值, 直 接 调 用 Number 如 果 valueof 的 结 果 是 复 合 类 型, 调 用 复 合 类 型 的 tostring, 再 调 用 Number ------------------------------- 输 入 参 数 Number 结 果 parseint 结 果 描 述 ------------------------------- 0 0 0 "0" 0 0 0. 0 0 "0." 0 0.0 0 0 ------------------------------- ".0" 0 NaN parseint 不 认 为 点 开 始 的 为 数 字 -------------------------------
0 NaN 空, "", '', null, false Number 将 其 认 为 是 0 "" 0 NaN parseint 将 其 认 为 是 NaN '' 0 NaN null 0 NaN false 0 NaN ------------------------------- undefined NaN NaN undefined 在 哪 儿 都 是 NaN 而 null 在 Number 看 来 是 0 "undefined" NaN NaN "." NaN NaN "true" NaN NaN "false" NaN NaN "abc" NaN NaN "abc123" NaN NaN ------------------------------- "123abc" NaN 123 数 字 开 头 的,number 认 为 是 NaN parseint 会 尽 可 能 解 析 为 数 字 "0123" 123 123 ------------------------------- 0123 83 83 对 字 符 串 而 言, 没 有 八 进 制 而 数 字 本 身 会 自 动 转 换 "123." 123 123 123. 123 123 "0x123" 291 291 0x123 291 291 ------------------------------- " \t12.3\n" 12.3 12 都 可 以 trim 掉 字 符 串 前 后 的 空 格, 区 别 是 : 一 个 是 转 换 成 Number, 结 果 可 以 是 float.123 0.123 0 一 个 是 parseint, 结 果 只 能 是 int ".123" 0.123 NaN -------------------------------
true 1 NaN true 在 Number 里 是 1, 在 parseint 里 是 NaN String 1. 数 字 转 为 相 应 的 字 符 串 2. true, false, undefined, null 转 换 为 对 应 字 符 串 3. 如 果 传 入 的 参 数 为 object 类 型, 会 调 用 其 tostring 方 法, 如 果 tostring 的 结 果 为 数 字, 字 符 串, 布 尔 值, 直 接 连 接 如 果 tostring 的 结 果 是 复 合 类 型, 调 用 复 合 类 型 的 valeof, 再 连 接 Error 自 动 抛 出 的 error 有 三 个 成 员 : name: 错 误 名 称 message: 错 误 提 示 信 息 stack: 错 误 的 堆 栈 ( 非 标 准 属 性, 但 是 大 多 数 平 台 支 持 ) Error 有 6 个 子 类 型 : 1. SyntaxError 是 解 析 代 码 时 发 生 的 语 法 错 误 2. ReferenceError 是 引 用 一 个 不 存 在 的 变 量 时 发 生 的 错 误 3. RangeError 是 当 一 个 值 超 出 有 效 范 围 时 发 生 的 错 误 4. TypeError 是 变 量 或 参 数 不 是 预 期 类 型 时 发 生 的 错 误 5. URIError 是 URI 相 关 函 数 的 参 数 不 正 确 时 抛 出 的 错 误 6. EvalError 是 eval 函 数 没 有 被 正 确 执 行 时 抛 出 的 错 误 还 可 以 继 承 自 Error 自 定 义 错 误 : function UserError(message) { this.message = message " 默 认 信 息 "; this.name = "UserError"; UserError.prototype = new Error(); UserError.prototype.constructor = UserError; 上 面 代 码 自 定 义 一 个 错 误 对 象 UserError, 让 它 继 承 Error 对 象 然 后, 就 可 以 生 成 这 种 自 定 义 的 错 误 了 new UserError(" 这 是 自 定 义 的 错 误!"); throw 可 以 throw 任 何 类 型 的 东 西, 但 是 最 好 throw new Error(' 出 错 了!');
传 值 和 传 引 用 原 始 类 型 是 值 传 递 var foo = 1; var fooback = foo; function cantmodifyvar(v) { v = 2 cantmodifyvar(foo); console.log("foo("+fooback+"->"+foo+")"); //foo(1->1) 复 合 类 型, 类 似 C 语 言 传 指 针 差 不 多 var arr = [1,2,3]; var arrback = arr; // 这 里 也 是 赋 值 的 变 量 地 址 function cantmodifyarr(v) { v = ["a", "b", "c"] cantmodifyarr(arr); console.log("arr("+arrback+"->"+arr+")"); //arr(1,2,3->1,2,3) function modifyarrcontent(v) { v[1] = "changed"; modifyarrcontent(arr); console.log("arr("+arrback+"->"+arr+")"); //arr(1,changed,3->1,changed,3) arguments function argtest(x) { //callee 代 表 argments 所 在 的 函 数 console.log("arguments.callee.name = " + arguments.callee.name) //arguments.callee.name = argtest console.log("arguments.length = "+arguments.length); //arguments.length = 2 console.log("arguments[0] = "+arguments[0]); //arguments[0] = 1 console.log("arguments[1] = "+arguments[1]); //arguments[1] = 2 console.log("arguments[2] = "+arguments[2]); //arguments[2] = undefined
argtest(1, 2) arguments 并 不 是 一 个 数 组, 而 是 一 个 对 象, 有 是 需 要 将 其 转 换 为 数 组 :var args = Array.prototype.slice.call(arguments); 闭 包 闭 包 的 特 点 在 于, 在 函 数 外 部 可 以 读 取 函 数 的 内 部 变 量 function f() { var v = 1; var c = function (){ ; return v; return c; var o = f(); o();// 1 上 面 代 码 表 示, 原 先 在 函 数 f 外 部, 我 们 是 没 有 办 法 读 取 内 部 变 量 v 的 但 是, 借 助 闭 包 c, 可 以 读 到 这 个 变 量 立 即 调 用 函 数 (function(){ /* code */ ()); 或 者 (function(){ /* code */ )(); 但 不 是 function(){ /* code */ (); // SyntaxError: Unexpected token ( 它 的 目 的 有 两 个 : 一 是 不 必 为 函 数 命 名, 避 免 了 污 染 全 局 变 量 ; 二 是 IIFE 内 部 形 成 了 一 个 单 独 的 作 用 域, 可 以 封 装 一 些 外 部 无 法 读 取 的 私 有 变 量 对 象 所 谓 对 象, 就 是 一 种 无 序 的 数 据 集 合, 由 若 干 个 键 值 对 (key-value) 构 成 var name = "nameval"; var me = { 180 : "cm", // 键 会 自 动 转 换 为 字 符 串 name : "coder", // 不 会 把 name 当 成 变 量, 直 接 转 换 成 "name" "name" : "coder 2", // 都 是 后 一 个 冲 掉 前 一 个 foo : "bar", age: 1024,
; action: function(x) { console.log("you call me? "+x); // 为 了 兼 容 老 浏 览 器, 最 后 一 个 属 性 后 面 的 逗 号 不 能 加 (e.g IE8) me.color = "red" // 这 样 写 也 可 以 //delete 命 令 只 能 删 除 对 象 本 身 的 属 性, 不 能 删 除 继 承 的 属 性 //delete 命 令 也 不 能 删 除 var 命 令 声 明 的 变 量, 只 能 用 来 删 除 属 性 delete me.foo delete me.notexist console.log(object.keys(me)); //[ '180', 'name', 'age', 'action', 'color' ] for (i in me){ //in 运 算 符 用 于 检 查 对 象 是 否 包 含 某 个 属 性, 例 如 name in me 返 回 ture, 与 for 结 合, 可 遍 历 console.log(i + "\t= " + me[i]); 输 出 结 果 : 180 = cm name = coder 2 age = 1024 action = function (x) { console.log("you call me? "+x); color = red 运 算 符 数 值 运 算 符 (+) 同 样 使 用 加 号, 但 是 加 法 运 算 符 是 二 元 运 算 符 ( 需 要 两 个 操 作 数 ), 它 是 一 元 运 算 符 ( 只 需 要 一 个 操 作 数 ) 它 的 重 要 作 用 在 于 可 以 将 任 何 值 转 为 数 值 ( 与 Number 函 数 的 作 用 相 同 ) +true // 1 +[] // 0 +{ // NaN 两 个 运 算 子 之 中 有 一 个 是 字 符 串, 另 一 个 运 算 子 就 会 被 自 动 转 为 字 符 串 加 法 运 算 符 以 外 的 其 他 算 术 运 算 符, 都 不 会 发 生 重 载 它 们 的 规 则 是 : 所 有 运 算 子 一 律 转 为 数 值, 再 进 行 相 应 的 数 学 运 算 于 是 : 1 - "1" // 0 +"3" // 3 -true // -1
var now = new Date(); typeof (now + 1) // "string" typeof (now - 1) // "number" 加 法 运 算 时,now 转 为 字 符 串, 加 一 个 数 字, 得 到 还 是 字 符 串 ; 减 法 运 算 时,now 转 为 数 值, 减 一 个 数 字, 得 到 的 是 数 字 余 数 运 算 结 果 的 正 负 号 由 第 一 个 运 算 子 的 正 负 号 决 定 -1 % 2 // -1 1 % -2 // 1 Javascript 有 两 组 相 等 运 算 符, 一 组 是 == 和!=, 另 一 组 是 === 和!== 前 者 只 比 较 值 的 相 等, 后 者 除 了 值 以 外, 还 比 较 类 型 是 否 相 同 请 尽 量 不 要 使 用 前 一 组, 永 远 只 使 用 === 和!== 因 为 == 默 认 会 进 行 类 型 转 换, 规 则 十 分 难 记 如 果 你 不 相 信 的 话, 请 回 答 下 面 五 个 判 断 式 的 值 是 true 还 是 false: false == 'false' false == undefined false == null null == undefined 0 == '' 前 三 个 是 false, 后 两 个 是 true if(1!== "1") { console.log('1!== "1"'); 这 里 做 自 动 类 型 转 换 if(1 == "1") { console.log('1 == "1"'); 相 等 运 算 符 == 的 自 动 转 换 规 则 : 如 果 类 型 不 一 样, 原 始 类 型 的 数 据 会 转 换 成 数 值 类 型 再 进 行 比 较 对 象 ( 这 里 指 广 义 的 对 象, 包 括 数 值 和 函 数 ) 与 原 始 类 型 的 值 比 较 时, 对 象 转 化 成 原 始 类 型 的 值, 再 进 行 比 较 [1] == 1 // true [1] == "1" // true [1] == true // true 上 面 代 码 将 只 含 有 数 值 1 的 数 组 与 原 始 类 型 的 值 进 行 比 较, 数 组 [1] 会 被 自 动 转 换 成 数 值 1, 因 此 结 果 都 是 true 位 运 算 符 Javascript 完 全 套 用 了 Java 的 位 运 算 符, 包 括 按 位 与 & 按 位 或 按 位 异 或 ^ 按 位 非 ~ 左 移 << 带 符 号 的 右 移 >> 和 用 0 补 足 的 右 移 >>> 这 套 运 算 符 针 对 的 是 整 数, 所 以 对 Javascript 完 全 无 用, 因 为 Javascript 内 部, 所 有 数 字 都 保 存 为 双 精 度 浮 点 数
如 果 使 用 它 们 的 话,Javascript 不 得 不 将 运 算 数 先 转 为 整 数, 然 后 再 进 行 运 算, 这 样 就 降 低 了 速 度 而 且 " 按 位 与 运 算 符 "& 同 " 逻 辑 与 运 算 符 "&&, 很 容 易 混 淆 9. function 语 句 在 Javascript 中 定 义 一 个 函 数, 有 两 种 写 法 : 和 function foo() { var foo = function () { 两 种 写 法 完 全 等 价 但 是 在 解 析 的 时 候, 前 一 种 写 法 会 被 解 析 器 自 动 提 升 到 代 码 的 头 部, 因 此 违 背 了 函 数 应 该 先 定 义 后 使 用 的 要 求, 所 以 建 议 定 义 函 数 时, 全 部 采 用 后 一 种 写 法 undefined 和 null null 表 示 " 没 有 对 象 ", 即 该 处 不 应 该 有 值 (1) 作 为 函 数 的 参 数, 表 示 该 函 数 的 参 数 不 是 对 象 (2) 作 为 对 象 原 型 链 的 终 点 Object.getPrototypeOf(Object.prototype) // null undefined 表 示 " 缺 少 值 ", 就 是 此 处 应 该 有 一 个 值, 但 是 还 没 有 定 义 (1) 变 量 被 声 明 了, 但 没 有 赋 值 时, 就 等 于 undefined (2) 调 用 函 数 时, 应 该 提 供 的 参 数 没 有 提 供, 该 参 数 等 于 undefined (3) 对 象 没 有 赋 值 的 属 性, 该 属 性 的 值 为 undefined (4) 函 数 没 有 返 回 值 时, 默 认 返 回 undefined var i; i // undefined function f(x){console.log(x) f() // undefined var o = new Object(); o.p // undefined var x = f(); x // undefined undefined 和 null 与 其 他 类 型 的 值 比 较 时, 结 果 都 为 false, 它 们 互 相 比 较 时 结 果 为 true false == null // false 0 == null // false undefined == null // true '' == '0' // false, 因 为 两 边 都 是 字 符 串, 不 需 要 转 换 0 == '' // true, 因 为 '' 转 换 为 整 数 是 0 0 == '0' // true false == 'false' // false
false == '0' // true false == undefined // false false == null // false null == undefined ' \t\r\n ' == 0 // true // true 两 个 复 合 类 型 ( 对 象 数 组 函 数 ) 的 数 据 比 较 时, 不 是 比 较 它 们 的 值 是 否 相 等, 而 是 比 较 它 们 是 否 指 向 同 一 个 对 象 ({) === { // false [] === [] // false (function (){) === function (){ // false void 在 大 多 数 语 言 中,void 都 是 一 种 类 型, 表 示 没 有 值 但 是 在 Javascript 中,void 是 一 个 运 算 符, 接 受 一 个 运 算 数, 并 返 回 undefined void 0; // undefined 这 个 命 令 没 什 么 用, 而 且 很 令 人 困 惑, 建 议 避 免 使 用 下 面 是 void 运 算 符 的 一 个 例 子 var x = 3; void (x = 5) //undefined x // 5 这 个 运 算 符 主 要 是 用 于 书 签 工 具 (bookmarklet) 或 者 用 于 在 超 级 链 接 中 插 入 代 码, 目 的 是 返 回 undefined 可 以 防 止 网 页 跳 转 javascript:void window.open("http://example.com/") 比 如, 下 面 是 常 用 于 网 页 链 接 的 触 发 鼠 标 点 击 事 件 的 写 法 <a href="#" onclick="f();"> 文 字 </a> 上 面 代 码 有 一 个 问 题, 函 数 f 必 须 返 回 false, 或 者 onclick 事 件 必 须 返 回 false, 否 则 会 引 起 浏 览 器 跳 转 到 另 一 个 页 面 function f(){ // some code 或 者 写 成 return false; <a href="#" onclick="f();return false;"> 文 字 </a> void 运 算 符 可 以 取 代 上 面 两 种 写 法 <a href="javascript:void(0)" onclick="f();"> 文 字 </a> 2014/11/17