Idle Works, Idle Thoughts

JavaScript 学习笔记

if 语句中,逻辑与/或用 &&||,没有 and 和 or 这样的关键字。有关键字:true/false。

页面加载后即运行的 JavaScript 代码,即定义一个匿名函数,并运行它:

(function(){})();

简单调试技术

1. 通过 console.log() 在控制台输出调试信息:

console.log("hello world");

2. 通过 alert() 在浏览器弹出一个框,输出提示信息。

3. 通过 document.write() 输出到当前的HTML页面中。

document.write("hello world!");

4. 通过下面这段代码,把日志发送到 Server:

var sender = new XMLHttpRequest();
sender.open("GET", "client-log.php?log=" + msg);
sender.send();

JavaScript语法基础

switch/case 语句:

switch(expression) {
    case n:
        /* codes */
        break;
    case m:
        /*  codes */
        break;
    default:
        /*  codes*/
}    

try…catch 语句:

try {
    throw new Error("Unkonw Error.");
} catch(e) {
    console.log(e.message);
}

字符串

JavaScript 字符串是不可变的(immutable),String 类所定义的方法都不能修改字符串的内容。如果涉及修改,都是返回全新的字符串。

replace() 字符串替换。注意没有在原字符串上替换,而是返回了替换后的值:

s = "hello berlin";
s = s.replace("berlin", "james");

replace() 执行替换。但注意,s.replace("a", "b"); 只会替换第一次出现的 a,要所有的 a 都替换为 b,应该用 s.replace(/a/g, "b"); 这样的写法。

indexOf()进行字符串搜索,如果没有找到子串则返回-1.

String.prototype.include = function(s) {
    return this.indexOf(s) != -1;
};

var s = "Welcome to my world!";
if(s.include("world")) {
    console.log("it works!");
}

search()进行正则表达式搜索,如果没有找到子串则返回-1.

if(s.search("world")) {
    console.log("find it");
}
if(s.search("/Welcome/")) {
    console.log("find it");
}
if(s.search("/welcome.*world/i")) {
    console.log("find it");
}

JavaScript 中没有 startsWith()endsWith() 这样的实用函数,可以自己添加:

if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (prefix){
        return this.slice(0, prefix.length) === prefix;
    };
} 

if (typeof String.prototype.endsWith != 'function') {
    String.prototype.endsWith = function(suffix) {
        return this.indexOf(suffix, this.length - suffix.length) !== -1;
    };
}

注意 startsWith() 的实现没有使用 indexOf(),因为 indexOf() 会扫描整个字符串。

trim() 删除字符串前后空格。

split() 将字符串转为数组,可以用正则表达式,如:

var s = "  623205  EA911785091CN  AU  Alice Hertson  ";
console.log(s.trim().split(/\s+/));

正则表达式

JavaScript 的正则表达式有 3 种语法:

/pattern/flags

new RegExp(pattern [, flags])

RegExp(pattern [, flags])

flags 包括:

创建一个正则表达式对象:

/ab+c/i;

new RegExp('ab+c', 'i');

new RegExp(/ab+c/, 'i');

在 ES6 之前,以上 new RegExp(/ab+c/, 'i') 会抛出一个 TypeError 异常(can’t supply flags when constructing one RegExp from another),表示不能用一个 RegExp 构建另一个 RegExp。

如果 RegExp 不会变化,用 /ab+c/i 这样的形式就可以了;如果 RegExp 是动态生成的,例如由其他变量或用户输入构建,则需要 new RegExp 的形式。

注意生成 new RegExp 时,应使用转移符,如:

/\d+/;

new RegExp('\\d+');

RegExp 对象的方法:

RegExp 示例:

'idle works'.replace(/(\w+)\s(\w+)/, '$2.$1');      
// works.idle

'Some text\nMore\r\nAnd yet\rEnd'.split(/\r\n|\r|\n/)
// [ 'Some text', 'More', 'And yet', 'End' ]

'Please yes\nmake my day.'.match(/yes.*day/)
// null    

'Please yes\nmake my day.'.match(/yes[^]*day/)
// [ 'yes\nmake my day',
// index: 7,
// input: 'Please yes\nmake my day.' ]

Stick regex matches

首先用 g 指定全局匹配,每次匹配后,lastIndex 被置为下一次匹配的开始处:

var msg = 'Today, the man and the dog went to the park.';

var re = /the \w+/g;

console.log(re.exec(msg));  // the man
console.log(re.lastIndex);  // 14

console.log(re.exec(msg));  // the dog
console.log(re.lastIndex);  // 26

console.log(re.exec(msg));  // the park
console.log(re.lastIndex);  // 43

如果没有 g 标识,exec() 不会修改 lastIndex 的值,且每次都是从字符串起始位置(0)开始匹配,匹配到第一个子串时结束。

数组

简单构造数组。

var notebooks = ["book", "movie", "story"];

遍历数组:

for(var i = 0; i < notebooks.length; i++) {
  console.log(notebooks[i]);
}

使用 push() 往数组附加数据:

notebooks.push("song");
console.log(notebooks);     // ["book", "movie", "story", "song"]。

使用 shift() 弹出第一个元素,使用 pop() 弹出最后一个元素:

var head = notebooks.shift();
var tail = notebooks.pop();
console.log(head, tail, notebooks);     // book song ["movie", "story"]

使用 unshift() 往数组开头出添加数据:

var arr = [1, 2];

arr.unshift(0);         // [0, 1, 2]
arr.unshift(-2, -1);    // [-2, -1, 0, 1, 2]
arr.unshift([-4, -3]);  // [[-4, -3], -2, -1, 0, 1, 2]

判断一个元素是否存在于数组中:

arr.indexOf(2);         // 找不到则返回-1

对象

一些对象的构造示例:

var obj = {};
var point = { x:0, y:0 };
var circle = { 
    x : point.x, 
    y : point.y, 
    radius:2 
};
var user = {
    "name" : "berlinix",
    "age" : 26
};

在创建对象后,可以随时增删对象属性。添加属性:

user.mail = "unkown@berlinix.com";
user["city"] = "beijing";

添加(访问)属性有2种方法,一种为obj.member,另一种为obj["member"]。前一种是半动态的,属性名是标识符,可以在代码中为对象任意添加属性,但必须硬编码;后一种是完全动态的,属性名是字符串,可以在运行时为对象添加属性。像obj["member"]这样的对象,我们也称作关联数组,类似Perl的哈希。

JavaScript中函数也是对象,因此可为函数添加属性,如:

id_factory.id = 0;
function id_factory() {
    return id_factory.id++;
}

以上代码实现了每次调用id_factory()返回新的数值功能(更好的实现是用闭包)。

对象属性是动态生成的,可以用for in来遍历对象所有属性:

function to_str(user) {
    var s = "";
    for(var name in user) {
        s += name + "\n";
    }
    return s;
}

要测试对象是否有某个属性,可以用in表达式或直接与undefined对比:

if("website" in user) { }
if(user.website !== undefined) { }

删除对象属性用delete运算符。delete后,for/in不会枚举该属性,in也不会检测到该属性。

Window对象

常见Window对象方法列表:

常见用法:

alert("hello, world!");

var ret = confirm("submit your order?");
if(ret == true) { alert("submit!"); }
else { alert("don't submit!"); }

prompt(msg, default_value);
var username = prompt("Input your name", "myname");
alert("hello, " + username);    

获取当前浏览页面的文件名:

var page = window.location.pathname.split("/").pop();        

document对象

获取一个div的内容

document.getElementById("country").innerHTML;

setTimeout()函数

setTimeout()是一个异步函数。

console.log(1);
setTimeout(function() { console.log(2); }, 500);
console.log(3);

这段代码的输出是:1、3、2. 注意setTimeout()并没有阻塞主线程。

CORS跨域请求

在Server端的响应报文中需要添加:

Access-Control-Allow-Origin:*

node.js中可以这样做:

res.setHeader('Access-Control-Allow-Origin','*');