注:以下部分代码或术语涉及ECMAScript 6。
1. literal
literal(字面量)即开发者写的,可直接被解析器识别,不必显式依赖API创建的量。如:
- 数字literal:
123
,0b1111011
,0o173
,0x7B
- 字符串literal:
"123"
,`12{2+1}`
- 数组literal:
[1,2,8]
- 对象literal:
{A:1,B:2,C:8}
- 正则表达式literal:
/^\d+(?:\.\d+)?$/
- 其他literal:
true
,false
,null
2. IIFE
还记得为了闭包(closure)而编写的声明即执行的函数表达式吗?这种函数表达式是IIFE,读作[iffy]。
var chars=//charCode为0x20,0x21,...,0x7F的一组字符组成的字符串,由以下IIFE表示
(function(){
var a=[];
for(let i=0x20;i<0x80;i++){
a.push(i);
}
return String.fromCharCode.apply(String,a);
})();
3. property and expando
property对于一般JavaScript开发者来说,熟悉而又陌生:
一个object的property含property key和property descriptor两部分。
property key分string和symbol两种。
property descriptor分data descriptor和accessor descriptor两种。
data descriptor有固定的value,而accessor descriptor有getter与/或setter。
property descriptor中的enumerable,configurable分别表示property是否可枚举,是否可重定义。
expando是property的一个形容词,指在规范之外扩展的,仅供实现者内部使用的。
对于jQuery而言,jQuery.fn属性可算作一个expando property。
举例:
var lengthExpando=Symbol.for("length");
function ArrayLike(){
var length=0;
// ...
Object.defineProperty(
this,
lengthExpando,// symbol as a property key
{enumerable:false,configurable:true,value:length}// data descriptor
);// define an expando property
Object.defineProperty(
this,
"length",// string as a property key
{
enumerable:false,
configurable:true,
get:function(){
return this[lengthExpando];
},
set:function(value){
var num=+value;
var len=num>>>0;
if(len!=num){
throw new RangeError("Invalid length");
}
// ...
this[lengthExpando]=len;
}
}// accessor descriptor
);// define a spec-defined property
}
4. mixin
与plugin可被安装到兼容的宿主程序的概念类似,mixin是一个class/object,它的属性/方法可动态复制到其他适配的class/object。
举例:
// define a mixin which is compatible with any Array-like class or object
var ArrayLikePrototype={
get firstElement(){
var index=0;
if(index<this.length){
return this[index];
}
//return undefined;
},
getFirstElement(){
var index=0;
if(index<this.length){
return this[index];
}
//return undefined;
},
get lastElement(){
var index=this.length-1;
if(index>-1){
return this[index];
}
//return undefined;
},
getLastElement(){
var index=this.length-1;
if(index>-1){
return this[index];
}
//return undefined;
},
// ...
};
// mix `ArrayLikePrototype` in `NodeList.prototype`
Object.defineProperties(NodeList.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));
// mix `ArrayLikePrototype` in `HTMLCollection.prototype`
Object.defineProperties(HTMLCollection.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));
//so that `document.children.firstElement` will be document.children[0]
// or even mix `ArrayLikePrototype` in `Array.prototype`
Object.defineProperties(Array.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));
//so that `[1,2,3].lastElement` will be 3, and `[1,2,3].getLastElement()` will be 3 too
5. shim and polyfill
shim 是为修正运行环境API而编写的代码。如:
// shim Window#setTimeout()
if(document.documentMode==9&&!Object.prototype.hasOwnProperty.call(window,"setTimeout")){
var WindowSetTimeout=Window.prototype.setTimeout;
Window.prototype.setTimeout=function setTimeout(callback, delay){
if(arguments.length<3||typeof callback!="function")
return WindowSetTimeout.call(this, callback, delay);
var args=Array.prototype.slice.call(arguments, 2);
return WindowSetTimeout.call(this, function(){
callback.apply(this, args);
}, delay);
};
}
//shim window.Event
if(document.documentMode>8&&typeof window.Event=="object"){
var nativeEvent=window.Event;
var shimedEvent=function Event(type/*,eventInit*/){
if(!(this instanceof Event))
throw new TypeError("Failed to construct 'Event': Please use the 'new' operator, this DOM object constructor cannot be called as a function.");
if(arguments.length===0)
throw new TypeError("Failed to construct 'Event': An event type must be provided.");
var event=document.createEvent("Event"),
eventInit={bubbles:false,cancelable:false},
p=Object.assign(eventInit,arguments[1]);
event.initEvent(type,p.bubbles,p.cancelable);
return event;
};
shimedEvent.prototype=nativeEvent.prototype;
window.Event=shimedEvent;
}
polyfill是为填补运行环境缺失的功能而提供的变通实现代码。如:
// polyfill Object.assign()
if(typeof Object.assign!="function"){
Object.assign=function assign(object,source){
var to,from,sources,nextSource,i,j,len,keys,key;
//#1
if(object==null)
throw new TypeError("Cannot convert "+object+" to Object");
to=Object(object);
//#3
if(arguments.length===1)
return to;
//#4
sources=Array.prototype.slice.call(arguments,1);
//#5
for(i=0; i<sources.length; i++){
//#a
nextSource=sources[i];
if(nextSource==null){continue;}
//#b
from=Object(nextSource);
//#d
keys=Object.keys(from);
//#e
len=keys.length;
//#f
for(j=0;j<len;j++){
key=keys[j];
to[key]=from[key];
}
}
//#6
return to;
};
}
// polyfill HTMLElement#hidden
if(typeof document.documentElement.hidden!="boolean"){
Object.defineProperty(HTMLElement.prototype,"hidden",{
get:function getHidden(){
return this.getAttribute("hidden")!=null;
},
set:function setHidden(v){
if(v)
this.setAttribute("hidden", "");
else
this.removeAttribute("hidden");
}
});
}
6. SemVer
越扯越远,这一条似乎与JavaScript不相关。
平时我们看到的一些软件库文件名如jquery-2.1.3.js,知道其中的版本号2.1.3遵循X.Y.Z,但XYZ每部分的含义,升级规则和比较/排序规则却又不清楚。
为了定义一个通用的版本号标准,GitHub联合创始人Tom Preston-Werner编写了SemVer(Semantic Versioning)规范。
SemVer 2.0.0规范定义的版本号的格式如下:
major
. minor
. patch
[ - pre
] [ + build
]
一个SemVer版本号不仅仅代表着一个独特的版本,还牵涉到其背后一系列的排序/升级/关联/筛选规则。
7. vanilla
这里的vanilla指寻常的,无特色的。vanilla js用中文说即纯手工编写,未用到第三方框架的js。
VanillaJS是一个没有可运行代码的JavaScript框架,通常被用作愚人节玩笑。它列举一些直接调用原生API而不必借助框架的实践方式,并突出这些寻常代码相对基于框架调用的代码所带来的性能优势,其思想有种道家无为的意味。但恰恰其他框架在试图证明使用框架后相对VanillaJS所带来的兼容/易用优势。
to be continued
更多见 MDN词汇表