讓JavaScript擁有類(lèi)似Lambda表達(dá)式編程能力的方法
更新時(shí)間:2010年09月12日 19:08:08 作者:
在前幾天的博文中我發(fā)布了一個(gè)可以自定義頁(yè)碼呈現(xiàn)方式的組件,有C#和JavaScript兩個(gè)版本。
但是我后來(lái)也跟人說(shuō),因?yàn)榻邮艿膮?shù)太多,所以如果不把智能提示寫(xiě)得很清楚的話,連我自己都常常搞不清楚該怎么用。
不過(guò),接受參數(shù)多,除了容易弄錯(cuò)用法以外,還會(huì)產(chǎn)生另一個(gè)問(wèn)題,這也是我編寫(xiě)出今天發(fā)布的這個(gè)東西的原因。
來(lái)看一下JS版的頁(yè)碼呈現(xiàn)組件的完全版函數(shù)簽名:
function pnView(
currentPage, actionCurrent,
beginPage, endPage,
actionBegin, actionEnd,
currentSiblings, actionCurrentSibling,
preventFolding, actionFolding,
endOfBegin, beginOfEnd,
actionBeginSibling, actionEndSibling
)
可以看到,這個(gè)可以最大幅度進(jìn)行自定義的完全版函數(shù)簽名,接受14個(gè)參數(shù),而其中有一半——也就是7個(gè)參數(shù),是要接受回調(diào)函數(shù)的。
由此產(chǎn)生的問(wèn)題就是需要手工寫(xiě)入多次的“function(){}”等字符組合,就像這樣:
function ww(s) { document.write(s); }
function ws(n) { ww(' <A href="#">(' + n + ')</A> '); }
pnView(14, function (n) { ww(' [' + n + '] ') },
1, 27,
function (n) { ww('<A href="#">|< ' + n + '</A> '); }, function (n) { ww(' <A href="#">' + n + ' >|</A>'); },
2, ws,
1, function () { ww(' ... '); },
2, 2,
ws, ws
);
當(dāng)我在網(wǎng)頁(yè)中測(cè)試這個(gè)組件的時(shí)候我就覺(jué)得自己非常想念C#中的Lambda表達(dá)式——雖然有些人、有些JS框架會(huì)把匿名函數(shù)稱(chēng)作“Lambda表達(dá)式”,但其實(shí)那只相當(dāng)于C#中的“匿名委托/函數(shù)”,而Lambda的(表面)特征是使用簡(jiǎn)短的語(yǔ)法模式來(lái)反映一個(gè)(回調(diào))函數(shù)/過(guò)程(或者說(shuō)動(dòng)作)的邏輯,而不被“delegate”或者別的什么關(guān)鍵字分散精力。
出于這樣的原因,我編寫(xiě)了這個(gè)可以轉(zhuǎn)譯JS代碼、把一種特定的模式(pattern)翻譯成函數(shù)定義的模塊。
在使用這個(gè)模塊以后,前面的那個(gè)調(diào)用可以變成這個(gè)樣子:
eval(function () {
var ww = (s, document.write(s));
var ws = (n, ww(' <A href="#">(' + n + ')</A> '));
pnView(14, (n, ww(' [' + n + '] ')),
1, 27,
(n, ww('<A href="#">|< ' + n + '</A> ')), (n, ww(' <A href="#">' + n + ' >|</A>')),
2, ws,
1, (0, ww(' ... ')),
2, 2,
ws, ws
);
}.lamda())();
模塊的完整代碼如下:
/*!
L-amda "a-Lambda", a module provides Alternate "Lambda" style programming ability for JavaScript.
Created By NanaLich. 2010-09-08
This module is published under WTFPL v2, so you just DO WHAT THE Fxxx YOU WANT TO with it.
*/
!function () {
function attachEntry(o, a, m) {
var i, j, n;
o = [].concat(o);
//if (!(o instanceof Array)) o = [o];
while (i = o.shift()) {
for (j in a) {
if (!i[n = a[j]]) i[n] = m;
}
}
}
var rx0 = /^\s*(0|NaN|null)\s*,$/;
var rx1 = /([\W]\s*)\((\s*0\s*,|(?:\s*[a-z_$][\w$]*\s*,)+)|"(\\[\s\S]|[^\x22])*"|'(\\[\s\S]|[^\x27])*'/gi;
var rx2 = /\)/g;
function rxGetFlags(rx) { // 取出正則表達(dá)式的創(chuàng)建選項(xiàng)
return (rx.global ? 'g' : '') + (rx.ignoreCase ? 'i' : '') + (rx.multiline ? 'm' : '');
//return /\/([gim]*)$/.exec('' + rx)[1];
}
attachEntry(RegExp, ['getFlags'], rxGetFlags);
attachEntry(RegExp.prototype, ['getFlags'], function () {
return rxGetFlags(this);
});
function translateLambda(s) {
if (typeof (s) != 'string') s = '' + s;
var x = new RegExp(rx1.source, rx1.getFlags());
var y = new RegExp(rx2.source, rx2.getFlags()); // 由于firefox、safari等瀏覽器對(duì)全局匹配正則表達(dá)式有過(guò)度的優(yōu)化,所以這里采用一種迂回的辦法創(chuàng)建不重復(fù)的正則表達(dá)式實(shí)例
var m, l = 0, r = '';
while (m = x.exec(s)) {
var c = m[0], h, p, q, t;
switch (c.charAt(0)) { // 判斷期待的語(yǔ)法成分
case '$':
case ')':
case ']':
case '"':
case "'":
continue; // 函數(shù)傳參,跳過(guò)
}
h = m[2];
if (rx0.test(h))
h = '';
else
h = h.substr(0, h.length - 1); // 去掉末尾的逗號(hào)
r += s.substring(l, p = m.index); // 在結(jié)果字符串上附加之前余留的內(nèi)容
y.lastIndex = l = p + c.length; // 從逗號(hào)之后開(kāi)始尋找右括號(hào)
while (q = y.exec(s)) {
q = q.index;
try {
t = 'return ' + s.substring(l, q) + ';';
new Function(t); // 語(yǔ)法測(cè)試
//r += c + 'function(' + h + '){ ' + translateLambda(t) + ' }'; // 翻譯里面的內(nèi)容
r += m[1] + 'function(' + h + '){ ' + translateLambda(t) + ' }'; // 翻譯里面的內(nèi)容
x.lastIndex = l = q + 1; // 下一次查找從括號(hào)之后開(kāi)始
break;
} catch (ex) { }
}
if (!q) l = p; // 說(shuō)明找不到右括號(hào)或者有效的代碼,直接附加所有匹配的內(nèi)容
}
try {
r += s.substr(l);
if (/[\w$]*|"(\\[\s\S]|[^\x22])*"|'(\\[\s\S]|[^\x27])*'/.exec(r)[0] == 'function') // 粗略判斷產(chǎn)生的是不是函數(shù)(可以應(yīng)付絕大部分情況)
r = '0,' + r; // 使用這種“怪”形式可以在所有瀏覽器(包括IE)中得到預(yù)期的效果
new Function(r); // 語(yǔ)法測(cè)試
return r;
} catch (ex) { // 失敗,返回原文
return s;
}
};
var lamdaAliases = ["translateLambda", "lambda", "lamda"];
attachEntry([Function, String], lamdaAliases, translateLambda);
attachEntry([Function.prototype, String.prototype], lamdaAliases, function () {
return translateLambda(this);
});
} ();
如果和C#中的Lambda表達(dá)式相比的話,我的這個(gè)模塊還是有很多不足的,不過(guò)現(xiàn)在這個(gè)樣子已經(jīng)讓我很滿(mǎn)意了,至少我不用再寫(xiě)太多的“function”了。
簡(jiǎn)單來(lái)說(shuō),這個(gè)模塊的規(guī)格特性是這樣的——
優(yōu)點(diǎn):
減少編寫(xiě)代碼時(shí)“function”的出現(xiàn)次數(shù);
使用可以在一般的JavaScript編輯器中正常編輯的語(yǔ)法模式(pattern),直接寫(xiě)在函數(shù)體中不會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤。
局限性:
在任何時(shí)候使用這個(gè)模塊都必須調(diào)用轉(zhuǎn)譯方法(“translateLambda”、“l(fā)ambda”或者“l(fā)amda”)和eval函數(shù),無(wú)法省略;
如果存在一個(gè)函數(shù)A,不可能通過(guò)對(duì)A進(jìn)行處理來(lái)達(dá)到轉(zhuǎn)譯傳遞至A的參數(shù)的目的(也就是說(shuō)a.lambda()或者類(lèi)似的操作并不會(huì)讓a((x, x * 2))等同于a(function(x){ return x * 2; }));
不能包含表達(dá)式之外的任何語(yǔ)句、不能包含使用“;”來(lái)分隔的多條語(yǔ)句。
缺點(diǎn):
連續(xù)出現(xiàn)的括號(hào)可能會(huì)讓代碼變得難以理解;
任何編輯器都無(wú)法為L(zhǎng)ambda表達(dá)式提供語(yǔ)法高亮;
存在錯(cuò)誤地轉(zhuǎn)譯現(xiàn)有代碼的可能性——這個(gè)模塊選擇進(jìn)行匹配的模式是在正常的代碼中沒(méi)有實(shí)用價(jià)值、也通常不會(huì)出現(xiàn)的模式,如:(x, x * 2)等價(jià)于單純的x * 2、(0, a.method())等價(jià)于單純的a.method(),所以這個(gè)缺點(diǎn)影響到實(shí)際代碼的可能性無(wú)限趨近于0。
以下是幾種不當(dāng)?shù)挠梅ǎ?
1、使用這個(gè)模塊并不會(huì)節(jié)省很多代碼量的時(shí)候:本末倒置。
eval(function(){ // 不僅沒(méi)減少代碼量,反而還增加了
window.onload = (0, alert('載入完成!'));
}.lambda());
2、對(duì)接受參數(shù)的函數(shù)進(jìn)行轉(zhuǎn)譯處理:之前已經(jīng)提到過(guò)這種情況。
eval(somefunction.lambda())((x, x.toString(16))); // somefunction可能會(huì)產(chǎn)生預(yù)料外的結(jié)果,而且收到的參數(shù)會(huì)是x.toString(16)的結(jié)果(如果x在此處并沒(méi)有被定義過(guò),還會(huì)產(chǎn)生一個(gè)“變量不存在”的異常),而非一個(gè)回調(diào)函數(shù)。
3、為了使用此模塊而規(guī)避語(yǔ)法檢查:
因?yàn)槭褂玫氖窃贘avaScript中有效但無(wú)實(shí)用價(jià)值的語(yǔ)法,所以規(guī)避語(yǔ)法檢查是完全沒(méi)有必要的。
eval("somefunction((x, x.toString(16)))".lamda()); // 失去了語(yǔ)法檢查,可能在運(yùn)行的時(shí)候產(chǎn)生意外
4、在(偽)Lambda中使用過(guò)多的操作,甚至多條語(yǔ)句:
在設(shè)計(jì)這個(gè)模塊的時(shí)候我并沒(méi)有找出可以使用多條語(yǔ)句且可以通過(guò)語(yǔ)法檢查的模式(pattern),原因是在Lambda表達(dá)式中使用多條語(yǔ)句時(shí),“function”、“return”等幾個(gè)字符所增加的代碼量通常是可以忽略的,這樣去使用Lambda表達(dá)式本身就屬于一種偏離了初衷的做法。
eval(function(){ somefunction((x, y.something(x); return x.toString(16))); }.lamda())(); // 語(yǔ)法錯(cuò)誤
eval(function(){ somefunction((x, y.something(x), x.toString(16))); }.lamda())(); // 容易產(chǎn)生理解上的歧義
eval(function(){ somefunction((x, ++x)); }.lamda())(); // 簡(jiǎn)單的表達(dá)式可以被接受
最佳使用場(chǎng)合:
現(xiàn)在很多人寫(xiě)JavaScript的時(shí)候喜歡把自己的代碼都寫(xiě)在一個(gè)閉包里面,這樣可以避免全局作用域污染問(wèn)題,就像這樣:
(function(){
// 所有的代碼都放在這里
})();
——而這種“大”閉包正好是使用本模塊的最佳場(chǎng)合:
eval(function(){ // 括號(hào)前增加eval
// 所有的代碼都放在這里
}.lamda())(); // 括號(hào)里增加.lamda()
昨天codeplex抽瘋,代碼和release上傳總出錯(cuò)。再考慮到這個(gè)模塊的使用場(chǎng)合比較有限,不適合缺乏JavaScript經(jīng)驗(yàn)的人使用,所以不另外提供源代碼打包下載——有需要的話請(qǐng)直接從文中復(fù)制。
不過(guò),接受參數(shù)多,除了容易弄錯(cuò)用法以外,還會(huì)產(chǎn)生另一個(gè)問(wèn)題,這也是我編寫(xiě)出今天發(fā)布的這個(gè)東西的原因。
來(lái)看一下JS版的頁(yè)碼呈現(xiàn)組件的完全版函數(shù)簽名:
復(fù)制代碼 代碼如下:
function pnView(
currentPage, actionCurrent,
beginPage, endPage,
actionBegin, actionEnd,
currentSiblings, actionCurrentSibling,
preventFolding, actionFolding,
endOfBegin, beginOfEnd,
actionBeginSibling, actionEndSibling
)
可以看到,這個(gè)可以最大幅度進(jìn)行自定義的完全版函數(shù)簽名,接受14個(gè)參數(shù),而其中有一半——也就是7個(gè)參數(shù),是要接受回調(diào)函數(shù)的。
由此產(chǎn)生的問(wèn)題就是需要手工寫(xiě)入多次的“function(){}”等字符組合,就像這樣:
復(fù)制代碼 代碼如下:
function ww(s) { document.write(s); }
function ws(n) { ww(' <A href="#">(' + n + ')</A> '); }
pnView(14, function (n) { ww(' [' + n + '] ') },
1, 27,
function (n) { ww('<A href="#">|< ' + n + '</A> '); }, function (n) { ww(' <A href="#">' + n + ' >|</A>'); },
2, ws,
1, function () { ww(' ... '); },
2, 2,
ws, ws
);
當(dāng)我在網(wǎng)頁(yè)中測(cè)試這個(gè)組件的時(shí)候我就覺(jué)得自己非常想念C#中的Lambda表達(dá)式——雖然有些人、有些JS框架會(huì)把匿名函數(shù)稱(chēng)作“Lambda表達(dá)式”,但其實(shí)那只相當(dāng)于C#中的“匿名委托/函數(shù)”,而Lambda的(表面)特征是使用簡(jiǎn)短的語(yǔ)法模式來(lái)反映一個(gè)(回調(diào))函數(shù)/過(guò)程(或者說(shuō)動(dòng)作)的邏輯,而不被“delegate”或者別的什么關(guān)鍵字分散精力。
出于這樣的原因,我編寫(xiě)了這個(gè)可以轉(zhuǎn)譯JS代碼、把一種特定的模式(pattern)翻譯成函數(shù)定義的模塊。
在使用這個(gè)模塊以后,前面的那個(gè)調(diào)用可以變成這個(gè)樣子:
復(fù)制代碼 代碼如下:
eval(function () {
var ww = (s, document.write(s));
var ws = (n, ww(' <A href="#">(' + n + ')</A> '));
pnView(14, (n, ww(' [' + n + '] ')),
1, 27,
(n, ww('<A href="#">|< ' + n + '</A> ')), (n, ww(' <A href="#">' + n + ' >|</A>')),
2, ws,
1, (0, ww(' ... ')),
2, 2,
ws, ws
);
}.lamda())();
模塊的完整代碼如下:
復(fù)制代碼 代碼如下:
/*!
L-amda "a-Lambda", a module provides Alternate "Lambda" style programming ability for JavaScript.
Created By NanaLich. 2010-09-08
This module is published under WTFPL v2, so you just DO WHAT THE Fxxx YOU WANT TO with it.
*/
!function () {
function attachEntry(o, a, m) {
var i, j, n;
o = [].concat(o);
//if (!(o instanceof Array)) o = [o];
while (i = o.shift()) {
for (j in a) {
if (!i[n = a[j]]) i[n] = m;
}
}
}
var rx0 = /^\s*(0|NaN|null)\s*,$/;
var rx1 = /([\W]\s*)\((\s*0\s*,|(?:\s*[a-z_$][\w$]*\s*,)+)|"(\\[\s\S]|[^\x22])*"|'(\\[\s\S]|[^\x27])*'/gi;
var rx2 = /\)/g;
function rxGetFlags(rx) { // 取出正則表達(dá)式的創(chuàng)建選項(xiàng)
return (rx.global ? 'g' : '') + (rx.ignoreCase ? 'i' : '') + (rx.multiline ? 'm' : '');
//return /\/([gim]*)$/.exec('' + rx)[1];
}
attachEntry(RegExp, ['getFlags'], rxGetFlags);
attachEntry(RegExp.prototype, ['getFlags'], function () {
return rxGetFlags(this);
});
function translateLambda(s) {
if (typeof (s) != 'string') s = '' + s;
var x = new RegExp(rx1.source, rx1.getFlags());
var y = new RegExp(rx2.source, rx2.getFlags()); // 由于firefox、safari等瀏覽器對(duì)全局匹配正則表達(dá)式有過(guò)度的優(yōu)化,所以這里采用一種迂回的辦法創(chuàng)建不重復(fù)的正則表達(dá)式實(shí)例
var m, l = 0, r = '';
while (m = x.exec(s)) {
var c = m[0], h, p, q, t;
switch (c.charAt(0)) { // 判斷期待的語(yǔ)法成分
case '$':
case ')':
case ']':
case '"':
case "'":
continue; // 函數(shù)傳參,跳過(guò)
}
h = m[2];
if (rx0.test(h))
h = '';
else
h = h.substr(0, h.length - 1); // 去掉末尾的逗號(hào)
r += s.substring(l, p = m.index); // 在結(jié)果字符串上附加之前余留的內(nèi)容
y.lastIndex = l = p + c.length; // 從逗號(hào)之后開(kāi)始尋找右括號(hào)
while (q = y.exec(s)) {
q = q.index;
try {
t = 'return ' + s.substring(l, q) + ';';
new Function(t); // 語(yǔ)法測(cè)試
//r += c + 'function(' + h + '){ ' + translateLambda(t) + ' }'; // 翻譯里面的內(nèi)容
r += m[1] + 'function(' + h + '){ ' + translateLambda(t) + ' }'; // 翻譯里面的內(nèi)容
x.lastIndex = l = q + 1; // 下一次查找從括號(hào)之后開(kāi)始
break;
} catch (ex) { }
}
if (!q) l = p; // 說(shuō)明找不到右括號(hào)或者有效的代碼,直接附加所有匹配的內(nèi)容
}
try {
r += s.substr(l);
if (/[\w$]*|"(\\[\s\S]|[^\x22])*"|'(\\[\s\S]|[^\x27])*'/.exec(r)[0] == 'function') // 粗略判斷產(chǎn)生的是不是函數(shù)(可以應(yīng)付絕大部分情況)
r = '0,' + r; // 使用這種“怪”形式可以在所有瀏覽器(包括IE)中得到預(yù)期的效果
new Function(r); // 語(yǔ)法測(cè)試
return r;
} catch (ex) { // 失敗,返回原文
return s;
}
};
var lamdaAliases = ["translateLambda", "lambda", "lamda"];
attachEntry([Function, String], lamdaAliases, translateLambda);
attachEntry([Function.prototype, String.prototype], lamdaAliases, function () {
return translateLambda(this);
});
} ();
如果和C#中的Lambda表達(dá)式相比的話,我的這個(gè)模塊還是有很多不足的,不過(guò)現(xiàn)在這個(gè)樣子已經(jīng)讓我很滿(mǎn)意了,至少我不用再寫(xiě)太多的“function”了。
簡(jiǎn)單來(lái)說(shuō),這個(gè)模塊的規(guī)格特性是這樣的——
優(yōu)點(diǎn):
減少編寫(xiě)代碼時(shí)“function”的出現(xiàn)次數(shù);
使用可以在一般的JavaScript編輯器中正常編輯的語(yǔ)法模式(pattern),直接寫(xiě)在函數(shù)體中不會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤。
局限性:
在任何時(shí)候使用這個(gè)模塊都必須調(diào)用轉(zhuǎn)譯方法(“translateLambda”、“l(fā)ambda”或者“l(fā)amda”)和eval函數(shù),無(wú)法省略;
如果存在一個(gè)函數(shù)A,不可能通過(guò)對(duì)A進(jìn)行處理來(lái)達(dá)到轉(zhuǎn)譯傳遞至A的參數(shù)的目的(也就是說(shuō)a.lambda()或者類(lèi)似的操作并不會(huì)讓a((x, x * 2))等同于a(function(x){ return x * 2; }));
不能包含表達(dá)式之外的任何語(yǔ)句、不能包含使用“;”來(lái)分隔的多條語(yǔ)句。
缺點(diǎn):
連續(xù)出現(xiàn)的括號(hào)可能會(huì)讓代碼變得難以理解;
任何編輯器都無(wú)法為L(zhǎng)ambda表達(dá)式提供語(yǔ)法高亮;
存在錯(cuò)誤地轉(zhuǎn)譯現(xiàn)有代碼的可能性——這個(gè)模塊選擇進(jìn)行匹配的模式是在正常的代碼中沒(méi)有實(shí)用價(jià)值、也通常不會(huì)出現(xiàn)的模式,如:(x, x * 2)等價(jià)于單純的x * 2、(0, a.method())等價(jià)于單純的a.method(),所以這個(gè)缺點(diǎn)影響到實(shí)際代碼的可能性無(wú)限趨近于0。
以下是幾種不當(dāng)?shù)挠梅ǎ?
1、使用這個(gè)模塊并不會(huì)節(jié)省很多代碼量的時(shí)候:本末倒置。
復(fù)制代碼 代碼如下:
eval(function(){ // 不僅沒(méi)減少代碼量,反而還增加了
window.onload = (0, alert('載入完成!'));
}.lambda());
2、對(duì)接受參數(shù)的函數(shù)進(jìn)行轉(zhuǎn)譯處理:之前已經(jīng)提到過(guò)這種情況。
復(fù)制代碼 代碼如下:
eval(somefunction.lambda())((x, x.toString(16))); // somefunction可能會(huì)產(chǎn)生預(yù)料外的結(jié)果,而且收到的參數(shù)會(huì)是x.toString(16)的結(jié)果(如果x在此處并沒(méi)有被定義過(guò),還會(huì)產(chǎn)生一個(gè)“變量不存在”的異常),而非一個(gè)回調(diào)函數(shù)。
3、為了使用此模塊而規(guī)避語(yǔ)法檢查:
因?yàn)槭褂玫氖窃贘avaScript中有效但無(wú)實(shí)用價(jià)值的語(yǔ)法,所以規(guī)避語(yǔ)法檢查是完全沒(méi)有必要的。
復(fù)制代碼 代碼如下:
eval("somefunction((x, x.toString(16)))".lamda()); // 失去了語(yǔ)法檢查,可能在運(yùn)行的時(shí)候產(chǎn)生意外
4、在(偽)Lambda中使用過(guò)多的操作,甚至多條語(yǔ)句:
在設(shè)計(jì)這個(gè)模塊的時(shí)候我并沒(méi)有找出可以使用多條語(yǔ)句且可以通過(guò)語(yǔ)法檢查的模式(pattern),原因是在Lambda表達(dá)式中使用多條語(yǔ)句時(shí),“function”、“return”等幾個(gè)字符所增加的代碼量通常是可以忽略的,這樣去使用Lambda表達(dá)式本身就屬于一種偏離了初衷的做法。
復(fù)制代碼 代碼如下:
eval(function(){ somefunction((x, y.something(x); return x.toString(16))); }.lamda())(); // 語(yǔ)法錯(cuò)誤
eval(function(){ somefunction((x, y.something(x), x.toString(16))); }.lamda())(); // 容易產(chǎn)生理解上的歧義
eval(function(){ somefunction((x, ++x)); }.lamda())(); // 簡(jiǎn)單的表達(dá)式可以被接受
最佳使用場(chǎng)合:
現(xiàn)在很多人寫(xiě)JavaScript的時(shí)候喜歡把自己的代碼都寫(xiě)在一個(gè)閉包里面,這樣可以避免全局作用域污染問(wèn)題,就像這樣:
復(fù)制代碼 代碼如下:
(function(){
// 所有的代碼都放在這里
})();
——而這種“大”閉包正好是使用本模塊的最佳場(chǎng)合:
復(fù)制代碼 代碼如下:
eval(function(){ // 括號(hào)前增加eval
// 所有的代碼都放在這里
}.lamda())(); // 括號(hào)里增加.lamda()
昨天codeplex抽瘋,代碼和release上傳總出錯(cuò)。再考慮到這個(gè)模塊的使用場(chǎng)合比較有限,不適合缺乏JavaScript經(jīng)驗(yàn)的人使用,所以不另外提供源代碼打包下載——有需要的話請(qǐng)直接從文中復(fù)制。
相關(guān)文章
js css實(shí)現(xiàn)垂直方向自適應(yīng)的三角提示菜單
這篇文章主要為大家詳細(xì)介紹了js css實(shí)現(xiàn)垂直方向自適應(yīng)的三角提示菜單的相關(guān)資料,需要的朋友可以參考下2016-06-06利用D3.js實(shí)現(xiàn)最簡(jiǎn)單的柱狀圖示例代碼
D3.js是一個(gè)基于數(shù)據(jù)操作文檔JavaScript庫(kù)。D3幫助你給數(shù)據(jù)帶來(lái)活力通過(guò)使用HTML、SVG和CSS。D3重視Web標(biāo)準(zhǔn)為你提供現(xiàn)代瀏覽器的全部功能,而不是給你一個(gè)專(zhuān)有的框架。最近在學(xué)習(xí)D3.js,這個(gè)例子是通過(guò)d3.js畫(huà)一個(gè)簡(jiǎn)單的柱狀圖。下面來(lái)一起看看吧。2016-12-12基于Cesium實(shí)現(xiàn)拖拽3D模型的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Cesium實(shí)現(xiàn)在地圖上添加一個(gè)3D模型,并且可以實(shí)現(xiàn)拖拽效果。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-06-06JS獲取及設(shè)置TextArea或input文本框選擇文本位置的方法
這篇文章主要介紹了JS獲取及設(shè)置TextArea或input文本框選擇文本位置的方法,涉及TextArea及input文本操作技巧,需要的朋友可以參考下2015-03-03js中hasOwnProperty的屬性及實(shí)例用法詳解
在本篇文章里小編給大家整理的是一篇關(guān)于js中hasOwnProperty的屬性及實(shí)例用法詳解內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。2021-11-11