Javascript 语言精粹 代码片段合集

标签:Douglas-Crockford Javascript 最佳实践


原文链接

更好的阅读体验

使用一个method 方法定义新方法
Function.prototype.method = function (name, func) {
if (!this.prototype[name]) {
this.prototype[name] = func;
}
return this;
}

根据数字的正负来判断是使用Math.ceiling 还是Math.floor
Number.method("integer", function () {
return Math[this < 0 ? 'ceil' : 'floor'](this);
});

移除字符串首尾的空白
String.method("trim", function () {
return this.replace(/^\s+|\s+$/g, '');
})

闭包演示
var myObject = (function () {
var value = 0; return {
increment: function (inc) {
value += typeof inc === "number" ? inc : 1;
},
getValue: function () {
return value;
}
};
}());

缓存中间计算结果 - 斐波纳挈数组
// 定义
var memoizer = function (memo, formula) {
var recur = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = formula(recur, n);
memo[n] = result;
}
return result;
};
return recur;
}; // 使用
var fibonacci = memoizer([0, 1], function (recur, n) {
return recur(n-1) + recur(n - 2);
});
for (var i = 0; i <= 10; i++) {
console.log("%d : %d", i, fibonacci(i));
} // 扩展用法 阶乘
var factorial = memoizer([1, 1], function (recur, n) {
return n * recur (n - 1)
});
for (var i = 1; i <= 10; i++) {
console.log("%d : %d", i, factorial(i));
}

如何实现继承 - 函数化
  1. 创建一个对象
  2. 有选择地定义私有实例变量和方法。这些就是函数中通过var语句定义的普通变量
  3. 给这个新对象扩充方法。这些方法拥有特权去访问参数,以及上一步中定义的变量。
  4. 返回这个新对象
// 这里是一个函数化构造器的伪代码模板(加粗的文本表示强调):
var **constructor** = function (spec, my) {
// 代码快内部不知道怎么加粗,哪位大神指点一下
var that, **其他私有变量**;
my = my || {}; // **把共享的变量和函数添加到my中** that = {
name: "**一个新对象**"
}; // **给that添加特权方法** return that;
}
// spec 对象包含构造器需要构造一个新实例的所哟信息。spec 的内容可能会被复制到私有变量中,或者被其他函数改变,或者方法可以在需要的时候访问spec的信息。(一个简化的方式是替换spec为一个单一的值。当构造对象过程中并不需要整个spec对象的时候,这是有用的。)
// my 对象是一个为继承链中的构造器提供秘密共享的容器。my对象可以选择性地使用。如果没有传入一个my对象,那么会创建一个my对象 // demo var mammal = function (spec) {
var that = {}; that.get_name = function () {
return spec.name;
}; that.says = function () {
return spec.saying || "";
} return that;
}; var cat = function (spec) {
spec.saying = spec.saying || 'meow';
var that = mammal(spec);
that.purr = function (n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += "-";
}
s += "r";
}
return s;
};
that.get_name = function () {
return that.says() + " " + spec.name + " " + that.says();
};
return that;
}; var myCat = cat({name: "Henrietta"});
函数化模式还提供了一个处理父类方法的方法。我们会构造一个superior方法,它取得一个方法名并返回调用那个方法的函数。该函数会调用原来的方法,尽管属性已经变化了。
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});

让我们在coolcat上试验一下,coolcat就像cat一样,除了它有一个更酷的调用父类方法的get_name方法。它只需要一点点的准备工作。我们会声明一个super_get_name变量,并且把调用superior方法所返回的结果赋值给它。

var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
}; var myCoolCat = coolcat({name: 'Bix'});
var name = myCoolCat.get_name();
console.log(name); // "like meow Bix meow baby"

部件

我们可以从一套部件中把对象组装出来。例如,我们可以构造一个给任何对象添加简单事件处理特性的函数。他会给对象添加一个on方法、一个fire方法和一个私有的事件注册表对象:

var eventuality = function (that) {
var registry = {};
that.fire = function (event) {
// 在一个对象上触发一个事件。该事件可以是一个包含事件名称的字符串
// 或者是一个拥有包含事件名称的 type 属性的对象。
// 通过'on'方法注册的事件处理程序中匹配事件名称的函数将被调用。
var array,
func,
handler,
i,
type = typeof event === 'string' ? event : event.type;
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i += 1) {
handler = array[i];
// 每个处理程序包含一个方法和一组可选的参数。
// 如果该方法是一个字符串形式的名字,那么寻找到该函数。
func = handler.method;
if (typeof func === 'string') {
func = this[func];
}
// 调用一个处理程序。如果该条目包含参数,那么传递它们过去。否则,传递该事件对象。
func.apply(this, handler.parameters || [event]);
}
}
return this;
}; that.on = function (type, method, parameters) {
// 注册一个事件。构造一条处理程序条目。将它插入到处理程序数组中,
// 如果这种类型的事件还不存在,就构造一个。
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return this;
}; return that;
};

我们可以在任何单独的对象上调用eventuality, 授予它事件处理方法。我们也可以赶在that被返回之前在一个构造器函数中调用它 eventuality(that);

eventuality(myCoolCat);
myCoolCat.health = 100;
myCoolCat.on('dead', function (event) {
var date = event.date;
var killer = event.killer;
console.log("%s killed me at %s", killer, date);
});
myCoolCat.on('hurt', function () {
this.health -= 50;
if (this.health <= 0) {
var event = {
type: 'dead',
killer: 'stone from sky',
date: new Date()
};
this.fire(event);
} else {
console.log('nothing, who is the strong guy.');
}
}); myCoolCat.fire("hurt"); //nothing, who is the strong guy.
myCoolCat.fire("hurt"); //stone from sky killed me at Sat Mar 14 2015 15:47:29 GMT+0800 (CST)

数组与对象

javascript 编程中,一个常见的错误是在必须使用数组时使用了对象,或者在必须使用对象时使用了数组。其实规则很简单:当属性名是小而连续的整数时,你应该使用数组。否则,使用对象。

javascript 本身没有一个好的机制来区分数组和对象。我们可以通过定义自己的is_array函数来弥补这个缺陷:

var is_array = function (value) {
return value
&& typeof value === 'object'
&& value.constructor === Array;
};
// 不过该方法在识别从不同的窗口(window)或者frame里构造的数组时会失败。下面是一个更好的方式
// 上面这句话这里本人尚未理解,请高手指点
var is_array = function (value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};
为数组扩充reduce函数
Array.method('reduce', function (f, value) {
var i;
for (i = 0; i < this.length; i += 1) {
value = f(this[i], value);
}
return value;
});
// DEMO
var data = [4, 8, 15, 16, 23, 42];
var add = function (a, b) {
return a + b;
};
var mult = function (a, b) {
return a * b;
};
var sum = data.reduce(add, 0);
console.log(sum);// 108
var product = data.reduce(mult, 1);
console.log(product); // 7418880 // 因为数组其实就是对象,所以我们可以直接给一个单独的数组添加方法
data.total = function () {
return this.reduce(add, 0);
};
var total = data.total();
console.log(total); // 108
为数组指定初始值
Array.dim = function (dimension, initial) {
var a = [], i;
for (i = 0; i < dimension; i += 1) {
a[i] = initial;
}
return a;
};
var myArray = Array.dim(10, 0); //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 注意这里不能使用我们之前说的method方法,应为那个方法是给某个类型的每一个具体的对象增加方法的,而这里我们是给Array这个 类型 增加方法,类似于某些静态语言中的静态方法或者类方法
数组排序

sort 方法会array中的内容进行排序。但是它不能正确第给一组数字排序:

var myNumbers = [4, 8, 15, 16, 23, 42];
myNumbers.sort(); // [15, 16, 23, 4, 42, 8]

javascript 的默认比较函数把要被排序的元素都视为字符串。它尚未足够智能到在比较这些元素之前先检测他们的类型,所以当它比较这些数字的时候,会把它们转化为字符串,于是得到一个错的离谱的结果。

辛运的是,你可以使用自己的比较函数来替换默认的比较函数。

你的比较函数应该接受两个参数,并且如果这两个参数相等则返回0,如果第1个参数应该排列在前面,则返回一个负数,如果第2个参数应该排在前面,则返回一个正数。

myNumbers.sort(function (a, b) {
return a - b;
}); // [4, 8, 15, 16, 23, 42]

上面这个函数可以使数字正确排序,但它不能使字符串排序。如果我们想要给任何包含简单值的数组排序,必须要做更多的工作:

var myStrings = ['aa', 'bb', 'a', 4, 8, 15, 16, 23, 42];
myStrings.sort(function (a, b) {
if (a === b) {
return 0;
}
if (typeof a === typeof b) {
return a < b ? -1 : 1;
}
return typeof a < typeof b ? -1 : 1;
}); //[4, 8, 15, 16, 23, 42, "a", "aa", "bb"]
对象数组排序
// by 函数接受一个成员名字字符串做为参数,
// 并返回一个可以用来对包含该成员的对象数组的进行排序的比较函数
var by = function (name) {
return function (o, p) {
var a, b;
if (typeof o === 'object' && typeof p === 'object' && o && p) {
a = o[name];
b = p[name];
if (a === b) {
return 0;
}
if (typeof a === typeof b) {
return a < b ? -1 : 1;
}
return typeof a < typeof b ? -1 : 1;
} else {
throw {
name: 'Error',
message: 'Expected an object when sorting by ' + name
};
} };
}
var myPeople = [
{first: 'Joe', last: 'Beasser'},
{first: 'Moe', last: 'Howard'},
{first: 'Joe', last: 'DeRita'},
{first: 'Shemp', last: 'Howard'},
{first: 'Larry', last: 'Fine'},
{first: 'Curly', last: 'Howard'}
];
myPeople.sort(by('first'));
/*
[
{first: "Curly", last: "Howard"},
{first: "Joe", last: "Beasser"},
{first: "Joe", last: "DeRita"},
{first: "Larry", last: "Fine"},
{first: "Moe", last: "Howard"},
{tfirst: "Shemp", last: "Howard"}
]
*/

sort 方法是不稳定的

排序的稳定性是指排序后数组中的相等值的相对位置没有发生改变,而不稳定性排序则会改变相等值的相对位置。详细内容参见排序算法。JavaScript的sort方法的稳定性根据不同浏览器的实现而不一致。可参见Array.prototype.sort中的介绍。

下面的调用:

myPeople.sort(by('last')).sort(by('first'));
/*
[
{"first": "Curly", "last": "Howard"},
{"first": "Joe", "last": "Beasser"},
{"first": "Joe", "last": "DeRita"},
{"first": "Larry", "last": "Fine"},
{"first": "Moe", "last": "Howard"},
{"first": "Shemp", "last": "Howard"}]
*/

不能保证产生正确的序列。如果你想基于多个键值进行排序,你需要再次做更多的工作。我们可以修改by函数,让其可以接受第2个参数,当主要的键值产生一个匹配的时候,另一个compare方法将被调用以决出高下。

// by 函数接受一个成员名字字符串和一个可选的次要比较函数做为参数,
// 并返回一个可以用来对包含该成员的对象数组进行排序的比较函数。
// 当 o[name] 和 p[name] 相等时,次要比较函数被用来决出高下。
var by = function (name, minor) {
return function (o, p) {
var a, b;
if (o && p && typeof o === 'object' && typeof p === 'object') {
a = o[name];
b = p[name];
if (a === b) {
return typeof minor === 'function' ? minor(o, p) : 0;
}
if (typeof a === typeof b) {
return a < b ? -1 : 1;
}
return typeof a < typeof b ? -1 : 1;
} else {
throw {
name: 'Error',
message: 'Expected an object when sorting by ' + name
};
}
};
}
myPeople.sort(by('last', by('first')));
[
{"first": "Joe", "last": "Beasser"},
{"first": "Joe", "last": "DeRita"},
{"first": "Larry", "last": "Fine"},
{"first": "Curly", "last": "Howard"},
{"first": "Moe", "last": "Howard"},
{"first": "Shemp", "last": "Howard"}
]

正则表达式 - 解析URL
var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
var url = "http://www.ora.com:80/goodparts?q#fragment";
var result = parse_url.exec(url);
var names = ['url', 'scheme', 'slash', 'host', 'port', 'path', 'query', 'hash'];
var blanks = ' ';
var i;
for (i = 0; i < names.length; i += 1) {
console.log("%s:%s%s", names[i], blanks.substring(names[i].length), result[i]);
}
/*
url: http://www.ora.com:80/goodparts?q#fragment
scheme:http
slash: //
host: www.ora.com
port: 80
path: goodparts
query: q
hash: fragment
*/
正则表达式 - 验证数字
var parse_number = /^-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i;
var isNumber = function (value) {
var result = parse_number.test(value);
console.log("%s %s a number", value, result ? "is" : "is not");
}
isNumber('1')
// 1 is a number
isNumber('number')
// number is not a number
isNumber('98.6')
// 98.6 is a number
isNumber('132.21.86.100')
// 132.21.86.100 is not a number
isNumber('123.45E-67')
// 123.45E-67 is a number
isNumber('123.45D-67')
//123.45D-67 is not a number // 数字可能由一个整数部分加上一个可选的负号、一个可选的小数部分和一个可选的指数部分构成
正则表达式中32个ASCII特殊字符集合:
/*
!"#$%
&'()*
+,-./
:;<=>
?@[\]
^_`{\
}~
*/
var ascii32 = /(?:!|"|#|\$|%|&|'|\(|\)|\*|\+|,|-|\/|:|;|<|=|>|\?|@|\[|\\|]|\^|_|`|\{|\||\}|~)/;
// 这是其中一种简写方式,不过依旧难以阅读
var ascii32_short1 = /[!-\/:-@\[-`{-~]/;
// 正则表达式的一个方便之处就是累的求反。如果 [ 后的第一个字符是 ^ ,那么这个类会排除这些特殊字符。
var not_ascii = /[^!-\/:-@\[-`{-~]/;

糟粕

javascript 有两组相等运算符:=== 和 !, 以及它们邪恶的孪生兄弟 == 和 !=。= 和 !== 这一组运算符会按照你期望的方式工作。如果来两个运算数类型一致并且拥有相同的值,那么 === 返回 true,!== 返回 false。而它们邪恶的孪生兄弟只有在两个运算数类型一致时才会做出正确的判断,如果两个运算数是不同的类型,它们试图去强制转换值的类型。转换的规则复杂且难以记忆。这里有一些有趣的例子:

'' == '0'           // false
0 == '' // true
0 == '0' // true false == 'false' // false
false == '0' // true false == undefined // false
false == null // false
null == undefined // true ' \t\r\n' == 0 // true

== 运算符对传递性的缺乏值得我们警惕。我的建议是永远不要使用那对邪恶的孪生兄弟。相反,请始终使用 === 和 !==。如果以上所有比较使用 === 运算符,结果都是false

传递性是一种编程约定。可以这么理解:对于任意的引用值x、y和z,如果 x == yy == ztrue,那么x == ztrue。而javascript中的 == 运算符在某些特例上违背了传递性。


最后 以一个自定义的JSON解析器 结尾吧
// 这是一个用JavaScript编写JSON解析器的实现方案:
var json_parse = function () {
// 这是一个能把JSON文本解析成JavaScript数据结构的函数。
// 它是一个简单的递归降序解析器。
// 我们在另一个函数中定义此函数,以避免创建全局变量。 var at, // 当前字符索引
ch, // 当前字符
escapee = {
'"' : '"',
'\\' : '\\',
'/' : '/',
b : 'b',
f : '\f',
n : '\n',
r : '\r',
t : '\t'
},
text,
error = function (m) {
// 当某处出错时,调用error。
throw {
name : 'SyntaxError',
messsage: m,
at : at,
text : text
};
},
next = function (c) {
// 如果提供了参数 c, 那么检查它是否匹配当前字符。
if (c && c !== ch) {
error("Expected '" + c + "' insttead of '" + ch + "'");
} // 获取下一个字符。当没有下一个字符时,返回一个空字符串。
ch = text.charAt(at);
at += 1;
return ch;
},
number = function () {
// 解析一个数字值。
var number,
string = '';
if (ch === '-') {
string = '-';
next('-');
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
if (ch === '.') {
string += ".";
while (next() && ch >= '0' && ch <= '9') {
string += ch;
} }
if (ch == 'e' || ch == 'E') {
string += ch;
next();
if (ch === '-' || ch === '+') {
string += ch;
next();
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
}
number = +string;
if (isNaN(number)) {
error("Bad number");
} else {
return number;
}
},
string = function () {
// 解析一个字符串值。
var hex,
i,
string = '',
uffff;
// 当解析字符串值时,我们必须找到 " 和 \ 字符。
if (ch === '"') {
while (next()) {
if (ch === '"') {
next();
return string;
} else if (ch === '\\') {
next();
if (ch === 'u') {
uffff = 0;
for (i = 0; i < 4; i += 1) {
hex = parseInt(next(), 16);
if (!isFinite(hex)) {
break;
}
uffff = uffff * 16 + hex;
}
string += String.fromCharCode(uffff);
} else if (typeof escapee[ch] === 'string') {
string += escapee[ch];
} else {
break;
}
} else {
string += ch;
}
}
}
error("Bad string");
},
white = function () {
// 跳过空白
while (ch && ch <= ' ') {
next();
}
},
word = function () {
// true, false 或者 null
switch (ch) {
case 't':
next('t');
next('r');
next('u');
next('e');
return true;
case 'f':
next('f');
next('a');
next('l');
next('s');
next('e');
return false;
case 'n':
next('n');
next('u');
next('l');
next('l');
return null;
}
error("Unexpected '" + ch + "'");
},
value, // 值函数的占位符。
array = function () {
// 解析一个数组值。
var array = [];
if (ch === '[') {
white();
if (ch === ']') {
next(']');
return array; // 空数组
}
while (ch) {
array.push(value());
white();
if (ch === "]") {
next(']');
return array;
}
next(',');
white();
}
}
error("Bad array");
},
object = function () {
// 解析一个对象值
var key,
object = {};
if(ch === '{') {
next('{');
white();
if (ch === "}") {
next('}');
return object; // 空对象
}
while (ch) {
key = string();
white();
next(":");
object[key] = value();
white();
if(ch === '}') {
next('}');
return object;
}
next(",");
white();
}
}
error("Bad object");
};
value = function () {
// 解析一个JSON值。它可以是对象、数组、字符串、数字或一个词。
white();
switch (ch) {
case '{':
return object();
case '[':
return array();
case '"':
return string();
case "-":
return number();
default:
return ch >= '0' && ch <= '9' ? number() : word() ;
}
};
// 返回json_parse 函数。它能访问上述所有的函数和变量。
return function(source, reviver) {
var result;
text = source;
at = 0;
ch = ' ';
result = value();
white();
if (ch) {
error("Syntax error");
} // 如果存在reviver 函数,我们就递归地对这个新结构调用walk函数,
// 开始时先创建一个临时的启动对象,并以一个空字符串作为键名保存结果,
// 然后传递每个键值对给reviver函数去处理可能存在的转换。
// 如果没有reviver函数,我们就简单地返回这个结果。
return typeof reviver === 'function' ?
function walk(holder, key) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}({'': result}, '')
: result;
}
}();

This is the end.

正文部分到此结束。

第一次写读书笔记,一是加深自己的印象,二来方便以后查阅,毕竟纸张没有搜索功能。

如果你也喜欢这篇文章欢迎转载,但本文代码版权属于《JavaScript 语言精粹》,小部分代码扩充是为了演示代码效果。

Javascript 语言精粹 代码片段合集的更多相关文章

  1. 常用torch代码片段合集

    PyTorch常用代码段整理合集 本文代码基于 PyTorch 1.0 版本,需要用到以下包 import collections import os import shutil import tqd ...

  2. opencv代码片段合集

    个人笔记 长期更新 #### 创建一个图片 import cv2 # Not actually necessary if you just want to create an image. impor ...

  3. numpy代码片段合集

    生成shape为(num_examples, num_inputs),符合0-1分布的数据. np.random.normal(0, 1, (num_examples, num_inputs))

  4. 大量Javascript/JQuery学习教程电子书合集

    [推荐分享]大量Javascript/JQuery学习教程电子书合集,送给有需要的人   不收藏是你的错^_^. 经证实,均可免费下载. 资源名称 资源大小   15天学会jQuery(完整版).pd ...

  5. 《JavaScript语言精粹》小记

    一.前言 以下内容均摘自<JavaScript语言精粹>一书,本人在读这本书时,发现作者诠释JavaScript很犀利,特别是数组部分,固记录下来,想和大家分享下. 随笔主要包含两大部分: ...

  6. [推荐分享]大量Javascript/JQuery学习教程电子书合集,送给有需要的人

    不收藏是你的错^_^. 经证实,均可免费下载. 资源名称 资源大小   15天学会jQuery(完整版).pdf 274.79 KB   21天学通JavaScript(第2版)-顾宁燕扫描版.pdf ...

  7. JavaScript 语言精粹笔记3

    方法 毒瘤 糟粕 记录一下阅读蝴蝶书的笔记,本篇为书中最后一部分:方法.代码风格.优美的特性.毒瘤.糟粕等. 方法 这一章主要介绍了一些方法集.这里写几个我不太熟悉的方法和要点吧. array.joi ...

  8. javascript语言精粹

    内容选自:<javascript语言精粹> 1.6种值会为假(==false),分别是false,null,undefined,' ',0,NaN 2.typeof有6种值,分别是'num ...

  9. JavaScript语言精粹笔记

    JavaScript语言精粹笔记 掌握语言的每个特性可以让你出风头,但是并不推荐,因为一部分的特性带来的麻烦可能远超本身的价值.正如书中所言,坏的材料并不能雕刻出好的作品,要成为一名更好的程序员,要取 ...

随机推荐

  1. CSS三列布局

    × 目录 两侧定宽中间自适应 两列定宽一侧自适应 中间定宽两侧自适应一侧定宽两列自适应三列自适应总结 前面的话 前面已经介绍过单列定宽单列自适应和两列自适应的两列布局.本文介绍三列布局,分为两侧定宽中 ...

  2. Cocos2d-x 3.2 学习笔记(十一)Game 2048

    一.规则 游戏2048的规则很简单 2+2=4  4+4=8 8+8=16 16+16=32 ……1024+1024=2048 这游戏挺火的……不过做起来也不难,就用cocos2dx做一下,首先我也没 ...

  3. C/C++定义全局变量/常量几种方法的区别

    在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块):    在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...

  4. Linux驱动开发——__stringify

    在Linux内核中有一个宏__stringify,在include/linux/stringify.h定义如下: #ifndef __LINUX_STRINGIFY_H #define __LINUX ...

  5. Spark入门实战系列--2.Spark编译与部署(上)--基础环境搭建

    [注] 1.该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取: 2.Spark编译与部署将以CentOS 64位操作系统为基础,主要是考虑到实际应用 ...

  6. Azure ARM (4) 开始创建ARM Resource Group并创建存储账户

    <Windows Azure Platform 系列文章目录> 好了,接下来我们开始创建Azure Resource Group. 1.我们先登录Azure New Portal,地址是: ...

  7. $("#id").val()取值textarea是""

    今天取值的时候,判断是null可以通过,证明不是null,明明是空的. 判断是''通过,证明取出来的是''空字符串.

  8. Ajax PHP项目实战

    这两天在实验楼学习ajax,后台是用php写的,下面我将三个实战项目分享出来,也方便我以后随时查看. 第一个项目我写的注释比较详细,第二个和第三个注释就写的比较少了,因为用的方法都差不多:这三个项目都 ...

  9. JavaScript基础插曲-练习

    Javascript基础学习 eg:利用正则表达式来去掉空格. 1:msg=' Hello ': <script type="text/javascript">     ...

  10. 基于MDK-ARM创建STM32L-DISCOVERY Project

    本文只针对使用MDK-ARM建立软件开发环境,并基于STM32L1xx_StdPeriph_Lib_V1.1.1库及其Examples,其余情况可参考UM1451 User manual Gettin ...