下面是从http://justineo.github.io/slideshows/semantic-html摘录的关于大部分 HTML 标签语义化含义的内容,可简要理解各种标签的含义。

全局属性

id

标示符 (用于引用),不应依赖其语义处理相应元素

class

authors are encouraged to use values that describe the nature of the content

title
  • 链接 - 描述目标信息
  • 图片 - 版权 / 描述
  • 引用 - 来源信息
  • 交互元素 - 操作指南
lang

内容的语言

元数据 (metadata)

meta
  • 元数据
  • name 属性决定种类,content 属性表示内容
  • 标准元数据名 (application-name author description generator keywords)
  • 已注册的扩展元数据名 (WHATWG Wiki MetaExtensions)
链接(links)
链接类型
  • 外部资源链接
    指向用来组成当前文档的外部资源,通常由 UA 自动处理
  • 超链接
    用来「导航」到其他资源 (可以在 UA 中打开 下载 …)
  • 元数据,用来描述文档本身与其他资源的关系

  • 必须包含 rel 及 href 属性

link + rel + author link + rel + license 都有预定义的语义

  • rel=”stylesheet” 链接到样式表 (外部资源)

  • rel=”alternate” 链接到当前文档的其他形式 (超链接)

  • rel=”prev” rel=”next” 链接到文档的前一篇 / 后一篇 / 前一页 / 后一页 (超链接) 在生成站点目录、归档视图时很有帮助。

  • rel=”icon” 当前文档的 favicon (外部资源)

a元素
  • 存在 href 属性时为超链接

  • 缺少 href 属性时为链接占位符

与 link 元素不同,a 元素代表的超链接都是显式的。

a + rel
  • rel=”prev” rel=”next” 链接到文档的前一篇 / 后一篇 / 前一页 / 后一页 (超链接)
  • rel=”nofollow”

当前文档的作者并不推荐超链接指向的文档 (超链接标注)
由 Google 引入,他们认为适用场景有 (via):

  1. 不可信赖的内容
  2. 付费链接
  3. 按优先级别进行抓取 (比如通知 Googlebot 不要抓取「注册」或「登陆」页面)
rel 属性

其他在 HTML 规范中预定义的 rel 属性值及其含义参见 HTML5 草案中 Link types 一节

区块 (sections)

section 元素
  • 按主题将内容分组,通常会有标题 (heading)
  • 并非「语义化的 div」

何时使用?

一个简单的评判标准:当你希望这个元素的内容体现在文档的_提纲 (outline)_ 中时,用 section 是合适的。

可以帮助 UA 迅速获得导航内容,例如读屏器可以省去很多渲染直接跳到导航位置。

不一定要包含 ul,也可用自然文本进行导航。

article 元素
  • 独立的文档、页面、应用、站点
  • 可以单独发布、重用
  • 可以是…
  • 一篇帖子
  • 一篇报刊文章
  • 一则用户评论
  • 一个可交互的 widget
aside 元素
  • 表示与周围内容关系不太密切的内容 (eg. 广告)
  • 通常表现为侧边栏内容 (eg. 相关背景内容)、引述内容
h1–h6 元素
<body>
    <h1>Let's call it a draw(ing surface)</h1>
    <h2>Diving in</h2>
    <h2>Simple shapes</h2>
</body>

语义上等价于:

<body>
  <h1>Let's call it a draw(ing surface)</h1>
  <section>
    <h1>Diving in</h1>
  </section>
  <section>
    <h1>Simple shapes</h1>
  </section>
</body>
hgroup 元素
  • 标题的组合

  • 用于副标题、标语 (tagline) 等

    The Lord of the Rings

    The Return of the King

    The Lord of the Rings

    "One ring to rule them all."

hgroup 中级别最高的标题才出现在提纲中

header 元素
  • 一组介绍性描述或导航信息 (目录 / 搜索框 / logo / …)

  • 通常包含 h1–h6 hgroup

  • 不影响文档提纲的生成

    Welcome to...

    Voidwars!

  • 代表最近的父级区块内容的页脚

  • 作者信息 / 相关文档 / 版权信息

  • 不影响文档提纲的生成

address 元素

代表与最近的父级 article 或 body 关联的联系人信息

<address>
  <a href="../People/Raggett/">Dave Raggett</a> 
  <a href="../People/Arnaud/">Arnaud Le Hors</a> 
  contact persons for the <a href="Activity">W3C HTML Activity</a>
</address>

分组内容 (grouping content)

p 元素
  • 「段落」的显式表述
    段落是主题接近的若干句子组成的文本块 (via)
    -非优先考虑的选择
    例如 address 的内容也是一个段落,但有更准确的语义
hr 元素
  • 原意为「horizontal rule」(水平分隔线)
  • HTML5 中重定义为不同主题内容间的分隔符
  • 区块内容之间不需要用 hr 元素分隔
pre 元素
  • 表示已排版的内容
  • 代码片段 / ASCII art / …
blockquote 元素
  • 引用的来自其他来源的内容

  • cite 属性表示该来源的 URL

  • 署名必须放在 blockquote 外

    His next piece was the aptly named Sonnet 130:

    My mistress' eyes are nothing like the sun
    Coral is far more red than her lips red
    [...]

ol ul li 元素
  • 有序 / 无序列表

  • 改变列表项顺序是否影响表达

  • ol 下 li 元素的 value 属性代表该列表项的序号值

    Relegation zone:

    1. Bolton Wanderers
    2. Blackburn Rovers
    3. Wolverhampton Wanderers
dl dt dd 元素
  • 名值对的集合

  • 术语定义表 / 元数据 / FAQ / …

    happiness
    n.
    The state of being happy.
    Good fortune; success. Oh happiness! It worked!
    rejoice
    v.intr. To be delighted oneself .
    v.tr. To cause one to be delighted.
figure 元素
  • 比较独立的、被主要内容引用的部分
  • 插画 / 图表 / 照片 / 代码 / …
  • 通常会有一个标题 (figcaption)
figcaption 元素
  • 图表标题 / 图例 / 代码说明 / …
div 元素
  • 本身无语义
  • 可以和 class lang title 等属性结合,为一系列连续的内容增加语义
  • 最后考虑的选择

文本级语义 (text-level semantics)

em 元素
  • 表示侧重点的强调

  • 强调级别由 em 的嵌套个数决定

  • em 的位置不同,文本本身含义不同

  • 在可视化 UA 上一般渲染为斜体

    Bats can fly.

    Bats can fly.

    Bats can fly.

三句含义各不相同

strong 元素
  • 表示内容的重要性

  • 重要程度由 strong 的嵌套个数决定

  • strong 的位置不同,文本本身含义不变

  • 在可视化 UA 上一般渲染为粗体

    Warning. A huge wave of zombies is approaching.

i 元素
  • 不再只是「斜体」

  • 表示另一种叙述方式

  • 分类学名词 / 外来语片段 / 舞台指示 / 船名 / …

  • 建议与 class / lang 属性搭配使用

    Sunflower (Helianthus annuus) is an annual plant native to the Americas.

    There is a certain je ne sais quoi in the air.

    Titanic sank in the North Atlantic Ocean on 15 April 1912.

b 元素
  • 不再只是「粗体」

  • 表示某种需要引起注意却又没有其他额外语义的内容

  • 摘要中的关键词 / 评介中的产品名称 / 文章的开篇内容 …

  • 建议与 class 属性搭配使用

    Kittens 'adopted' by pet rabbit

    Six abandoned kittens have found an unexpected new mother figure — a pet rabbit.

    Veterinary nurse Melanie Humble took the three-week-old kittens to her Aberdeen home.

    [...]
small 元素
s 元素
  • 不再只是「带删除线的文字」

  • 表示不再准确或不再相关的内容

  • 与 del 元素含义不同

    Buy our Iced Tea and Lemonade!

    Recommended retail price: $3.99 per bottle

    Now selling for just $2.99 a bottle!

u 元素
  • 不再只是「带下划线的文字」

  • 表示用非文本进行的标注的内容

  • 中文专名 / 拼写检查的错误内容 / …

    屈原放逐,乃賦離騒左丘失明,厥有國語。(司馬遷《報任安書》)

cite 元素
  • 引述的作品标题

  • 书 / 论文 / 散文 / 电影 / 歌曲 / 电视节目 / 画作 / …

    My favorite movie is Transformers by Michael Bay.

q 元素
  • 引用的来自其他来源的段内内容

  • cite 属性表示该来源的 URL

  • 不用 q 而用引号亦正确

    The W3C page About W3C says the W3C's mission is To lead the World Wide Web to its full potential by developing protocols and guidelines that ensure long-term growth for the Web.

abbr 元素
  • abbreviation or acronym (区别?)

  • 其 title 属性的含义为所写的全称

    The WHATWG started working on HTML5 in 2004.

建议在用户不熟悉的缩写词汇第一次出现时用 abbr + title 进行语义标注,帮助其理解

dfn 元素
  • 用来展现一个术语的定义实例

  • 最接近的父级段落、定义列表组或区块内容必须包含 dfn 元素指定术语的定义

    The GDO is a device that allows off-world teams to open the iris.

很容易抽取出特定术语的含义,从而很容易回答「What is …?」类的问题

time 元素
  • 为表述的内容增加一个机器可读的时间数据

  • datetime 属性值必须是预定义的几种时间格式之一

  • 如果不含 datetime 属性,则会解析其文本内容值

    http://www.web2con.com/ Web 2.0 Conference: - at the Argent Hotel San Francisco CA
code samp kbd 元素
  • code - 代码片段
  • samp - 计算机程序的输出
  • kbd - 用户输入的内容 / 按键
mark 元素
  • 在引用的文字中使用,表示在当前文档中需要引起注意但原文中并没有强调的含义 (eg. 对一篇文章的分析中对原文的标注)

  • 表示与用户当前的行为相关的内容 (eg. 高亮显示搜索关键词)

    6月13日下午,一场大雨过后,正阳门箭楼被带着水雾的脚手架包裹得严严实 实。北京旧城中轴线上的这座标志性建筑,正经历着新中国成立后规模最大的一次修缮。

    [...]

    6月13日的那场大雨,将故宫端门外西朝房冲洗得干干净净。

    作者为什么两次提到6月13日的大雨?请谈谈你的看法。

ruby rt rp 元素
  • 注音标示,「ruby」来自日本印刷业

  • 主要于 CJK 文字

    ()(xié)(shè)(huì)

span 元素
  • 本身无语义

  • 可以和 class lang 等属性结合,为文本片段增加语义

  • 有更合适的元素时不应选择 span

    var greet = function() {
    console.log(“Hello world.”);
    }

更改记录 (edits)

ins del 元素
  • 表示对当前文档内容进行的增添与删改
  • cite 属性指向对某个修改的说明文档的 URL
  • datetime 属性表示了修改发生的时间 (取值规范)
  • 用来记录文档的编辑历史

嵌入内容 (embedded content)

img 元素
  • src alt 属性决定了图片的含义
  • 有 src 且 alt 为空字符串,代表装饰用图
  • 有 src 且 alt 为非空字符串,图为文档内容的一部分
  • 有 src 且无 alt,图为内容一部分但无等价的文本内容可用
  • 用 alt 文本替换图片,文档含义尽可能不变

    You are standing in an open field west of a house. A white houseThe house is white  with a boarded front door.    There is a small mailbox here.

iframe embed object param 元素
  • iframe - 内嵌的浏览上下文

  • embed - 外部应用或可交互内容的整合入口

  • object - 通用外部资源 根据具体内容可以被处理为图片、内嵌的浏览上下文、供插件调用的资源

  • param - 为 object 元素传递的参数


相当于 imgiframe 的效果

<embed src="catgame.swf" type="application/x-shockwave-flash" quality="high">

<object data="catgame.swf" type="application/x-shockwave-flash"> 
  <param name="quality" value="high">
  <p>Plugin needed.</p>
</object>

功能等价但 object 提供更好的回退策略

多媒体元素
  • video - 视频
  • audio - 音频

公共属性:src crossorigin preload autoplay mediagroup loop muted controls

source 元素
  • 表示所在多媒体元素的可替代资源 (可能不同格式 / 清晰度,读取失败或无法解码时可以依次尝试)

  • type 属性中除了 MIME 类型外,可使用 codecs= 来指定编码

track 元素
  • 用来为多媒体元素指定「文本轨」

  • kind 属性描述文本轨的类型,可用值包括 subtitles captions descriptions chapters metadata

表格数据 (tabular data)

table 元素
  • 用来表示超过一维的数据
caption 元素
  • 表示所处的 table 的标题

当所处的 table 是外部 figure 元素的唯一子元素,应首选 figcaption

tbody thead tfoot 元素
  • 均为一组表格行
  • thead 表示列头 (通常为列标题,单元格用 th 元素)
  • tfoot 表示列脚 (通常为列数据汇总)
col colgroup tr 元素
  • 列,列组,行
td th 元素
  • td - 数据单元格
  • th - 标题单元格

th 的 scope 属性表示标题对应的数据范围

类似于 Java 语言中将异常(Exception)分为 CheckedExceptionRuntimeException一样,ECMA262 定义 Error 分为“早期错误(early error)”与“运行时错误(runtime error)”。

“早期错误”意即能够在程序进行任意构造求值操作之前检测到并报出的错误,包含下面几类:

  1. 语法错误;
  2. 对同一个属性定义多个 setter 或多个 getter;
  3. 对同一个属性同时定义 value 和 setter/getter;
  4. 正则表达式语法错误;
  5. 严格模式中有 重复的属性赋值;
  6. 严格模式中使用 wi th 关键字;
  7. 独立严格模式下的 函数定义中具有重复的参数定义;
  8. returnbreakcontinue 的不合适使用;
  9. 向非引用赋值

除了这些错误以外都属于运行时错误,不同的错误类型将会对程序带来一定的影响,例如:

<script>var i =0  j = 0;</script>
<script>
    ++i;
    syntax error
</script>
<script>
    ++j;
    throw new Error('runtime error');
</script>
<script>
    console.log(i + '/' + j);//0/1
</script>

内建的 Error 包含下面几种类型:

  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError
参考

List of ES3 Incompatibilities introduced by ES5.

From Annex E:

  • 7.1: Unicode format control characters are no longer stripped from ECMAScript source text before processing. In Edition 5 if such a character appears in a StringLiteral or RegularExpressionLiteral the character will be incorporated into the literal where in Edition 3 the character would not be incorporated into the literal.

    (function () {
    return eval(‘“\u200C\u200D\uFEFF”.length == 3’);
    })();

  • 7.2: Unicode character is now treated as whitespace and its presence in the middle of what appears to be an identifier could result in a syntax error which would not have occurred in Edition 3.

    (function () {
    try {
    eval(‘var foo\uFEFFbar’);
    } catch (e) {
    return e instanceof SyntaxError;
    }
    })()

  • 7.3: Line terminator characters that are preceded by an escape sequence are now allowed within a string literal token. In Edition 3 a syntax error would have been produced.

    (function () {
    try {
    eval(“‘foo\\nbar’;”);
    return true;
    } catch (e) {
    return false;
    }
    })();

  • 7.3: Regular expression literals now return a unique object each time the literal is evaluated. This change is detectable by any programs that test the object identity of such literal values or that are sensitive to the shared side effects.

    (function () {
    function re(){ return /(?:)/; }
    return re() !== re();
    })();

  • 7.8.5: Edition 5 requires early reporting of any possible RegExp constructor errors that would be produced when converting a RegularExpressionLiteral to a RegExp object. Prior to Edition 5 implementations were permitted to defer the reporting of such errors until the actual execution time creation of the object.

  • 7.8.5: In Edition 5 unescaped “/“ characters may appear as a CharacterClass in a regular expression literal. In Edition 3 such a character would have been interpreted as the final character of the literal.

    (function () {
    try {
    var re = eval(‘/[/]/‘);
    return re.test(‘/‘);
    } catch (e) {
    return false;
    }
    })();

  • 10.4.2: In Edition 5 indirect calls to the eval function use the global environment as both the variable environment and lexical environment for the eval code. In Edition 3 the variable and lexical environments of the caller of an indirect eval was used as the environments for the eval code.

    (function (global) {
    //TODO: maybe try other types of indirect calls
    return (function () { return global === (0 eval)(‘this’); }).call({});
    })(this);

  • 15.4.4: In Edition 5 all methods of Array.prototype are intentionally generic. In Edition 3 toString and toLocaleString were not generic and would throw a TypeError exception if applied to objects that were not instances of Array.

    (function () {
    try {
    Array.prototype.toString.call({});
    Array.prototype.toLocaleString.call({});
    return true;
    } catch (e) {
    return false;
    }
    });

  • 10.6: In Edition 5 the array indexed properties of argument objects that correspond to actual formal parameters are enumerable. In Edition 3 such properties were not enumerable.

    (function () {
    return arguments.propertyIsEnumerable(‘0’);
    })(0);

  • 10.6: In Edition 5 the value of the [[Class]] internal property of an arguments object is “Arguments”. In Edition 3 it was “Object”. This is observable if toString is called as a method of an arguments object.

    (function () {
    return ({}).toString.call(arguments) == “[object Arguments]”;
    })();

  • 12.6.4: for-in statements no longer throw a TypeError if the in expression evaluates to null or undefined. Instead the statement behaves as if the value of the expression was an object with no enumerable properties.

    (function () {
    try {
    for(var prop in null);
    for(prop in undefined);
    } catch (e) {
    return false;
    }
    return true;
    })();

  • 15: Implementations are now required to ignore extra arguments to standard built-in methods unless otherwise explicitly specified. In Edition 3 the handling of extra arguments was unspecified and implementations were explicitly allowed to throw a TypeError exception.

  • 15.1.1: The value properties NaN Infinity and undefined of the Global Object have been changed to be read-only properties.

    (function (_NaN _Infinity _undefined) {
    NaN = Infinity = undefined = null;
    if (!isNaN(NaN) || Infinity != _Infinity || undefined !== _undefined) {
    //TODO: restore values
    return false;
    }
    return true;
    })(NaN Infinity);

  • 15.1.2.1: Implementations are no longer permitted to restrict the use of eval in ways that are not a direct call. In addition any invocation of eval that is not a direct call uses the global environment as its variable environment rather than the caller’s variable environment.

    (function (global) {
    try {
    return [eval]0 === global;
    } catch (e) {
    return false;
    }
    }).call({} this);

  • 15.1.2.2: The specification of the function parseInt no longer allows implementations to treat Strings beginning with a 0 character as octal values.

    (function () {
    return parseInt(‘010’) === 10;
    })();

  • 15.3.4.3: In Edition 3 a TypeError is thrown if the second argument passed to Function.prototype.apply is neither an array object nor an arguments object. In Edition 5 the second argument may be any kind of generic array-like object that has a valid length property.

    (function () {
    try {
    return (function (a b) { return a + b == 10; }).apply({} {0:5 1:5 length:2});
    } catch (e) {
    return false;
    }
    })();

  • 15.3.4.3 15.3.4.4: In Edition 3 passing undefined or null as the first argument to either Function.prototype.apply or Function.prototype.call causes the global object to be passed to the indirectly invoked target function as the this value. If the first argument is a primitive value the result of calling ToObject on the primitive value is passed as the this value. In Edition 5 these transformations are not performed and the actual first argument value is passed as the this value. This difference will normally be unobservable to existing ECMAScript Edition 3 code because a corresponding transformation takes place upon activation of the target function. However depending upon the implementation this difference may be observable by host object functions called using apply or call. In addition invoking a standard built-in function in this manner with null or undefined passed as the this value will in many cases cause behaviour in Edition 5 implementations that differ from Edition 3 behaviour. In particular in Edition 5 built-in functions that are specified to actually use the passed this value as an object typically throw a TypeError exception if passed null or undefined as the this value.

    (function () {
    try {
    //Maybe test ({}).toString.call(null) == ‘[object Null]’
    return ({}).hasOwnProperty.call(null ‘’) false;
    } catch (e) {
    //ToObject in hasOwnProperty should throw TypeError if null
    return true;
    }
    })();

  • 15.3.5.2: In Edition 5 the prototype property of Function instances is not enumerable. In Edition 3 this property was enumerable.

    !Function.propertyIsEnumerable(‘prototype’);

  • 15.5.5.2: In Edition 5 the individual characters of a String object’s [[PrimitiveValue] may be accessed as array indexed properties of the String object. These properties are non-writable and non-configurable and shadow any inherited properties with the same names. In Edition 3 these properties did not exist and ECMAScript code could dynamically add and remove writable properties with such names and could access inherited properties with such names.

    (function () {
    String.prototype[1] = ‘x’;
    var foo = new String(‘foo’);
    foo[0] = ‘y’; //non-writable
    delete foo[0]; //non-configurable
    return foo[0] == ‘f’ && foo[1] == ‘o’;
    })();

  • 15.9.4.2: Date.parse is now required to first attempt to parse its argument as an ISO format string. Programs that use this format but depended upon implementation specific behaviour (including failure) may behave differently.

    (function () {
    try{
    return !!Date.parse(“2014-09-07T15:24:08.011Z”);
    }catch(e){
    return false;
    }
    })();

  • 15.10.2.12: In Edition 5 \s now additionally matches <BOM>.

    (function () {
    return /\s/.test(‘\uFEFF’);
    })();

  • 15.10.4.1: In Edition 3 the exact form of the String value of the source property of an object created by the RegExp constructor is implementation defined. In Edition 5 the String must conform to certain specified requirements and hence may be different from that produced by an Edition 3 implementation.

  • 15.10.6.4: In Edition 3 the result of RegExp.prototype.toString need not be derived from the value of the RegExp object’s source property. In Edition 5 the result must be derived from the source property in a specified manner and hence may be different from the result produced by an Edition 3 implementation.

  • 15.11.2.1 15.11.4.3: In Edition 5 if an initial value for the message property of an Error object is not specified via the Error constructor the initial value of the property is the empty String. In Edition 3 such an initial value is implementation defined.

    (function () {
    var error = new Error();
    return typeof error.message == ‘string’ && error.message.length == 0;
    })();

  • 15.11.4.4: In Edition 3 the result of Error.prototype.toString is implementation defined. In Edition 5 the result is fully specified and hence may differ from some Edition 3 implementations.

    (function () {
    var foo = new Error bar = new Error;
    foo.name = ‘Foo’;
    foo.message = bar.name = ‘Bar’;
    return foo.toString() == ‘Foo: Bar’ && bar.toString() == ‘Bar’;
    })();

  • 15.12: In Edition 5 the name JSON is defined in the global environment. In Edition 3 testing for the presence of that name will show it to be undefined unless it is defined by the program or implementation.

    (function (global) {
    return typeof global.JSON != ‘undefined’;
    })(this);

From Annex D:

  • 11.8.2 11.8.3 11.8.5: ECMAScript generally uses a left to right evaluation order however the Edition 3 specification language for the > and <= operators resulted in a partial right to left order. The specification has been corrected for these operators such that it now specifies a full left to right evaluation order. However this change of order is potentially observable if side-effects occur during the evaluation process.

    (function(){
    var i = 1 j = 1;
    (i*=2) > 1 > (i+=1);
    (j*=2) <= 1 <= (j+=1);
    return 3 === i && 3 === j;
    })();

  • 11.1.4: Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitializer does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.

    (function () {
    return [1 ].length === 1;
    })();

  • 11.2.3: Edition 5 reverses the order of steps 2 and 3 of the algorithm. The original order as specified in Editions 1 through 3 was incorrectly specified such that side-effects of evaluating Arguments could affect the result of evaluating MemberExpression.

  • 12.4: In Edition 3 an object is created as if by new Object() to serve as the scope for resolving the name of the exception parameter passed to a catch clause of a try statement. If the actual exception object is a function and it is called from within the catch clause the scope object will be passed as the this value of the call. The body of the function can then define new properties on its this value and those property names become visible identifiers bindings within the scope of the catch clause after the function returns. In Edition 5 when an exception parameter is called as a function undefined is passed as the this value.

  • 13: In Edition 3 the algorithm for the production FunctionExpression with an Identifier adds an object created as if by new Object() to the scope chain to serve as a scope for looking up the name of the function. The identifier resolution rules (Section 10.1.4 in Edition 3) when applied to such an object will if necessary follow the object’s prototype chain when attempting to resolve an identifier. This means all the properties of Object.prototype are visible as identifiers within that scope. In practice most implementations of Edition 3 have not implemented this semantics. Edition 5 changes the specified semantics by using a Declarative Environment Record to bind the name of the function.

  • 15.10.6: RegExp.prototype is now a RegExp object rather than an instance of Object. The value of its [[Class]] internal property which is observable using Object.prototype.toString is now “RegExp” rather than “Object”.

    (function () {
    return ({}).toString.call(RegExp.prototype) == ‘[object RegExp]’;
    })();

Other changes:

  • 11.5.1: A PropertyName in a PropertyAssignment can consist of an
    IdentifierName this makes possible to use Reserved Words.

    (function () {
    var obj;
    try {
    eval(‘obj = {if:1}’);
    return obj[‘if’] == 1;
    } catch (e) {
    return false;
    }
    })();

hasOwnPropertyin 都可以用来判断一个对象的成员是否存在,但有很大的区别,前者不会搜索对象的原型链中的成员,但后者会;前者是 Object 原型中的函数,后者是 Javascript 操作符等。关于第一中区别,可以通过阅读 ECMAScript 规范来了解其细节。

hasOwnProperty

[ECMA-262 3rd edition](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262 %203rd%20edition %20December%201999.pdf) 对 hasOwnProperty 的描述非常简单:“返回对象(不包括原型链)中是否有该成员”。该版本针对对象成员定义了四个属性:ReadOnlyDontEnumDontDeleteInternal

ECMA-262 5.1rd edition 重新定义了成员属性,提供了更灵活的访问权限。在该版本中,对象成员分为“数据成员(Data Property)”和“存取成员(Accessor Property)”两种。前者包含属性:ValueWritableEnumerableConfigurable,后者包含GetSetEnumerableConfigurable。对于不同的成员定义方式,其类型自然也不同。

var o = {
    a:1 //Data Property
    set b(){} //Accessor Property
    get c(){} //Accessor Property
};
o.d = 1;//Data Property
o.__defineSetter('m'  function(m){});//Accessor Property
o.__defineGetter('n'  function(n){});//Accessor Property
Object.defineProperty(o 'e' {});//Data Property
Object.defineProperty(o 'e' {set:function(){}});//Accessor Property
Object.create(null {f:{}});//Data Property
Object.create(null {f:{set:function(){}}});//Accessor Property

需要注意的是不能同时定义“value”与“set/get”。

ES5 中的 hasOwnProperty 需要访问一个内部方法:GetOwnProperty,该方法返回一个新的属性描述符(Property Descriptor ),或者是“数据成员”或者是“存取成员”。对于字符串来说,它有一个自己的 GetOwnProperty方法,允许以数字作为 property name,代表在指定位置上是否存在字符,该值不超过字符串长度减一。该方法仅返回“数据成员”格式,因为字符串是不可变的。

in

in 操作符只能用于对象而非简单类型,它调用内部方法 HasProperty,该方法递归搜索原型链,直到找到对应的成员。在 ES5 中,该方法还涉及另一个内部方法:GetOwnProperty。因此对于字符串,下面的表达式返回真:

2 in new String('abc')
总结

判断一个对象 O 是否携带有成员 P,一般可以:

undefined === O.P

但对于值为 undefined 的成员无效,这时就需要使用 in 操作符:

var Class = function(){this.P = undefined;};
Class.prototype = {Q:undefined;};
var O = new Class();

!!O.P;//false
!!O.Q;//false
'P' in O;//true
'Q' in O;//true
O.hasOwnProperty('P');//true
O.hasOwnProperty('Q');//false

JavaScript 中的==运算符用以比较两侧的值是否“近似”相等,区别于===的严格相等。

==可以达到以下效果:

null==undefined //true
[]==false //true
[]=='' //true
[1]=='1' //true

要说明 JavaScript 引擎在计算 == 运算符时做了什么,先要了解几个内部概念和方法。

Type

ECMAScript 规范规定了六种变量类型:null undefined string number boolean object。Type 不同于运算符 typeof ,它可以分辨出 null 和 object,但不能分辨 function 和 object,当然事实上并没有 function 这样一种类型。

可以这样模拟 Type 的行为:

function Type(e) {
    if (undefined === e) {
        return 'undefined';
    } else if (null === e) {
        return 'null';
    } else if ('number' === typeof e) {
        return 'number';
    } else if ('string' === typeof e) {
        return 'string';
    } else if ('boolean' === typeof e) {
        return 'boolean';
    } else return 'object';
}
0的符号

另外需要说明的是0本身包括两个值,正零:+0,和负零:-0。一般不会对这两个值进行区分,甚至使用 === 运算符也分辨不出:

+0===-0 //true

在ECMAScript中有内部内部方法可以区别出这两个值,当然我们也可以做到这一点:

function isPositiveZero(e) {
    return 0 === e && 1 / e > 0;
}

function isNegativeZero(e) {
    return 0 === e && 1 / e < 0;
}

关于这两点将会在后面的侦断中用到。

ToNumber

转换为数字,规则如下:

输入类型 结果
Undefined NaN
Null +0
Boolean 真返回1,假返回+0
Number 直接返回
String 字面意义
Object 调用ToNumber(toPrimitive),hint:Number
toPrimitive

该内部方法将一个对象转换为原始类型,在上面提到的六种类型中,前五种都属于原始类型。对于非原始类型,将根据一个成为 hint 的值访问该对象的 Default Value 属性来获取原始值。hint 取值只能为 “string” 和 “number”(默认)。如果为 “string”,将依次调用对象的 toStringvalueOf 来获取原始值,如果为 “number”,将依次调用 valueOftoString 方法,可见顺序依赖于 hint 值。

==

== 操作x,y两个值时要经过一系列的类型和值的侦断,在 ECMAScript 内部称之为 The Abstract Equality Comparison Algorithm

  1. 如果 Type(x) 不同于 Type(y) 执行第 14 步。
  2. 如果 Type(x) 为 Undefined 返回真。
  3. 如果 Type(x) 为 Null 返回真。
  4. 如果 Type(x) 不是 Number 执行第 11 步。
  5. 如果 x 为 NaN 返回假。
  6. 如果 y 为 NaN 返回假。
  7. 如果 x 与 y 有相同的值 返回真。
  8. 如果 x 为 +0 并且 y 为 −0 返回真。
  9. 如果 x 为 −0 并且 y 为 +0 返回真。
  10. 返回假。
  11. 如果 Type(x) 为 String 那么如果 x 和 y 具有相同的字符序列(等长并且对应位置字符相同)返回真,否则,返回假。
  12. 如果 Type(x) 为 Boolean 如果 x 和 y 都是真或者都是假则返回真,否则 返回假。
  13. 如果x和y引用相同的对象返回真,否则 返回假。
  14. 如果 x 为 null 并且 y 为 undefined 返回真。
  15. 如果 x 为 undefined 并且 y 为 null 返回真。
  16. 如果 Type(x) 为 Number 并且 Type(y) 为 String 返回 x == ToNumber(y) 的结果。
  17. 如果 Type(x) 为 String 并且 Type(y) 为 Number 返回 ToNumber(x) == y 的结果。
  18. 如果 Type(x) 为 Boolean 返回 ToNumber(x) == y 的结果。
  19. 如果 Type(y) 为 Boolean 返回 x == ToNumber(y) 的结果。
  20. 如果 Type(x) 为 String 或者 Number 并且 Type(y) 为 Object 返回 x == ToPrimitive(y) 的结果。
  21. 如果 Type(x) 为 Object 并且 Type(y) 为 String 或者 Number 返回 ToPrimitive(x) == y 的结果。
  22. 返回假。

有了这个流程,就可以知道上面提到的几个式子成立的原理:

[]==false

任意数组转换为布尔值时都为真,但与布尔值进行== 运算操作时,首先会将布尔转换为数字,即 false=>0,接着再与数组进行 == 运算。这时,需要进行 toPrimitive([] Number) 运算了,返回0,所以式子返回真。

[1]=='1'

数组与字符串比较,直接转换为 toPrimitive([1] String) == '1',显然为真。

总结

在使用 == 进行操作之前,一定要明确两边值类型所带来的结果差异,必要时,直接强转为布尔值进行计算。

测试

该页面展示了比较两个不同类型值得过程中所发生的事情。

参考

Node Packaged Modules(NPM) 中使用的版本号系统遵循语义化版本2.0.0

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  1. 主版本号:当你做了不兼容的API 修改,
  2. 次版本号:当你做了向下兼容的功能性新增,
  3. 修订号:当你做了向下兼容的问题修正。

NPM中所依赖的其它模块可以指定为特定的版本,也可以指定一个版本号范围,为此 Node-semver 引擎提供了一套灵活的语法:

>

大于某版本,如 “>0.1.2”

<

小于某版本,如 “<0.2.1”

>=

大于等于某版本,如 “>=0.1.2”

<=

小于等于某版本,如 “>=0.1.2”

-

两个版本范围之内,包含边界,如 “0.1.2 - 0.1.9”,相当于 “>=0.1.2” and “<=0.1.9”

^

当前版本至下一个主版本,如 “^1.1.2”,相当于 “>=1.1.2” and “<2.0.0”

~

当前版本至下一个次版本,如 “~1.1.2”,相当于 “>=1.1.2” and “<1.2.0”

另外,* x和空代表任意,下面几个的含义相同:
“1.2.x”,”1.2.*”,”1.2”

选用合适的版本范围选择符,避免依赖模块的小版本升级导致的连锁强迫升级。

参考

过宽的大段文字内容对读者不够友好,尝试阅读一下这里的第一段文字,是否在换行时遇到困难。

像报纸一样,web 设计时遇到大段文字一般都会尝试将文字内容分成多列显示,在技术上可以通过加入表格(table)或任意其它块级元素标签解决。显然这样的设计欠缺灵活性,需要手动分割文字内容,过多或过少的文字都将影响分割算法。CSS 2.1 后带来了新的布局功能————多列布局,很好地解决了此问题。

#####语法

多列布局

多列布局适用于非替换 block 元素(除 table 外),table-cellinline-block 元素。

article{
    columns:3;
}

这段 CSS 代码即定义所有 article 元素分为3列进行排版。这是最大列数定义,当文字不足时,也可能按2列或1列显示。

也可以这样定义:

article{
    columns:10em;
}

这意味着每列最多显示10个字符宽度。

事实上,columnscolumn-countcolumn-width 的缩写。大多数时候仅需给出一个值,当两个值都给出时,一般仅有一个能影响最终排版,column-count 代表可以分割的最大列数。

######列间隙

使用 column-gap 设置列与列之间的间隙,如:

article{
    column-gap:3em;
}

######列分割线

列分割线由 column-rule-colorcolumn-rule-widthcolumn-rule-style 定义,语法类似与 border ,如:

article{
    column-rule-color:#28b;
    column-rule-style:dashed;
    column-rule-width:1px;
}

或者简写为:

article{
    column-rule:1px #28b dashed;
}

######分割位置

可以定义一些分割位置的建议,如不能在某些元素的中间分割:

article p{
    break-before:avoid;
    break-after:column;
    break-inside:avoid;
}

这些属性仅对块级元素有效,不过好像目前还没有浏览器支持它们。

######夸列元素

可以定义夸列元素,如:

article h1{
    column-span:all|none;
}

######列填充策略

两种策略:平衡和非平衡的,目前只有 Firefox 支持:

article{
    column-fill:balance|auto;
}

#####浏览器支持

虽然多列布局一直处于 Candidate Recommendation 阶段,但是现代 PC 和 Mobile 浏览器几乎已经全部实现, IE 从 10 开始支持。部分浏览器需要加厂商前缀。

  • IE 10+
  • Firefox 5+
  • Chrome 12+
  • Safari 3.2+
  • Opera 11.1+
  • Android 2.1+
  • iOS 3.2+

下面是多列布局所需的所有 CSS 属性的 LESS

.column(@w){
    -webkit-columns:@w;
    -moz-columns:@w;
    columns:@w;
}
.column-gap(@len){
    -webkit-column-gap:@len;
    -moz-column-gap:@len;
    column-gap:@len;
}
.column-rule-color(@color){
    -webkit-column-rule-color:@color;
    -moz-column-rule-color:@color;
    column-rule-color:@color;
}
.column-rule-style(@style:solid){
    -webkit-column-rule-style:@style;
    -moz-column-rule-style:@style;
    column-rule-style:@style;
}
.column-rule-width(@width){
    -webkit-column-rule-width:@width;
    -moz-column-rule-width:@width;
    column-rule-width:@width;
}
.break-before(@break){
    -webkit-break-before:@break;
    -moz-break-before:@break;
    break-before:@break;
}
.break-after(@break){
    -webkit-break-after:@break;
    -moz-break-after:@break;
    break-after:@break;
}
.break-inside(@break){
    -webkit-break-inside:@break;
    -moz-break-inside:@break;
    break-inside:@break;
}
.column-span(@span){
    -webkit-column-span:@span;
    -moz-column-span:@span;
    column-span:@span;
}
.column-fill(@fill:balance){
    -webkit-column-fill:@fill;
    -moz-column-fill:@fill;
    column-fill:@fill;
}

查看多列布局的实际效果,点击这里

#####总结

使用 CSS 多列布局不仅大大提高了布局灵活性,对屏幕阅读器、打印机和 SEO 也更友好。但需要针对旧浏览器设计功能降级。

#####参考

Internet Explorer 11(IE11) 自去年六月份发布以来虽然据说也取得了不错的成绩,但在中国好像还看不到其占有率。获取 IE11 可以从两种方式:安装 Win8,自带 IE11;从 Win7 的 IE9/10 升级,但 XP 在中国仍然有超过60%的占有率,而 XP 最高也只能升级到 IE8

前端测试仍在徘徊在 IE6 ~ IE10 之间,但在开发过程中偶然间发现了 IE11 与众 IE 不同之处。

前端开发一直将浏览器分为 W3C 和 IE 两种,特别是将 IE 众版本当做异类对待。微软这次决定洗心革面,将 IE11 打造成一款不是 ‘IE’ 的浏览器,拥有与其它 ‘W3C’ 浏览器一样的特性。

重要变动

IE11 支持了完整的 flex 能力(参见利用flexbox构建可伸缩布局),于 Firefox 之后第二个拥有无前缀 CSS 属性名。

支持了 SPDY 协议。

ActiveXObject 对象不再存在了,这使得许多依靠检测该对象来嗅探浏览器类型的代码失效。

同样,document.all 的布尔值也会返回 false 。许多浏览器拥有该对象但是在转成布尔值时故意返回 false 用以兼容之前无数使用该对象判断浏览器类型的代码。现在,只有 IE6~9 会返回 true。

UA中一直存在的 MSIE 被删除,依赖于此获取浏览器类型和版本号的代码将失效。要判断其类型和版本,必须 MSIETrident 共用了。

移除了 attachEvent ,以 addEventListener 取代之,这也会破坏使用该方法判断浏览器类型的代码。

IE8 引入的 XDomainRequest 被删除,取而代之的是支持跨域资源共享(CORS)的 XMLHttpRequest

总结

显然 IE11 的改进破坏了几乎所有用于区分 W3CIE 浏览器的方法,使得无数现存代码无法取得其是 IE 浏览器的事实。或许这就是微软的目的:IE11 不再是 ‘IE’ 了,你不需要在判断出来它了。

下面给出使用 UA 获取 IE 版本的代码:

/**
* Get version if it’s a microsoft internet explorer.
*
* @return version code or else null if it’s not a IE.
*/
function getIEVersion(){
var ua = navigator.userAgent matches tridentMap={‘4’:8 ‘5’:9 ‘6’:10 ‘7’:11};

    matches = ua.match(/MSIE (\d+)/i);

    if(matches&&matches[1])
    {   
        //find by msie
        return +matches[1];
    }

    matches = ua.match(/Trident\/(\d+)/i);
    if(matches&&matches[1])
    {   
        //find by trident
        return tridentMap[matches[1]]||null;
    }
    
    //we did what we could
    return null;
}

由于 UA 可以随意伪造,所以并没有合适的方法能够保证检测出真正的浏览器环境,因此代码都不应依赖于具体的环境和版本。

参考

需求

可伸缩布局技术产生已久,但对其利用非常地少,至今只能在一些移动站点上隐约看到它的身影。这不仅仅因为其只能针对较新的浏览器,而且其 API 也较为复杂。

现今的针对多屏设备的站点依然强依赖于媒体查询。其后果是会产生大量冗余的 CSS 代码与百分比宽高定义,增加维护难度。相比之下,可伸缩布局技术提供了一次编写代码适配多种屏幕尺寸的能力。

例如,我们想要构建一个下面这样的横排布局:

|-----|-----|----------|
|  1  |  1  |     2    |
|-----|-----|----------|

HTML 代码为:

<div class="wrapper">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>

要求在不同的屏幕宽度下依旧保持这种比例关系:1:1:2。我们可能会这样编写css代码:

.wrapper{width:100%;}
.item{float:left;width:25%;}
.item:last-child{width:50%;}

各个 item 子元素的宽度比例需要小心的维护,如果需要新增加一个元素,比例值需要重新计算,你肯定不想遇到一个不能整除的除法计算,比如100/6。

上面的例子中,各个子元素的宽度和等于父元素,如果期望之间存在差值怎么办,比如每个子元素存在一个固定的 1px 右边距,那么宽度该如何定义?

使用 calc 是一个方法:

.wrapper{width:100%;}
.item{float:left;width:calc(25% - 1px);margin-right:1px;}
.item:last-child{width:50%;}

只可惜这种方式依然需要清醒地人工计算,何况 calc 本身支持并不好。

使用 ::after 也是一种方法,不过显然会带来更多问题。

可伸缩布局(flex)提供了相当简单地分配剩余空间的方法,并且书写很傻瓜————你不需要关心最终是如何计算的,总之它能很清晰地实现你想要的比例布局:

.wrapper{width:100%;display:flex;}
.item{flex:1;margin-right:1px;}
.item:last-child{flex:2;margin-right:0;}

对,你只需要告诉浏览器你想要的比例,多出来的 marginpaddingborder都不必额外考虑。

语法

flex 作用于内外两级元素,外层称之为“容器”,内层称之为“元素”。需要将容器设置:

display:flex;/*块级元素*/
/*或*/
display:inline-flex;/*内联元素*/

与之前的 display:inlinedisplay:block 没什么分别。经过这样的设置,其直接子元素即刻拥有可伸缩能力。要定义子元素的占比,设置:

flex:1;
/*或*/
flex:2;

系统会根据各个元素的占比自动计算其真实尺寸。值得一提的是,拥有 flex 设置的元素仅均分剩余空间的大小————固定尺寸的子元素不受影响。以上面的 HTML 结构为例,书写 CSS:

.wrapper{width:200px;display:flex;}
.item:first-child{width:50px;}
.item:nth-child(1){flex}
.item:last-child{flex:2;}

那么产生的布局是:

|-----|-----|----------|
| 50px| 50px|  100px   |
|-----|-----|----------|

其中第一个元素固定为 50px,第二个元素占剩余的 1/3,即(200-50)/3=50px,最后一个元素占2/3,即 100px。

flex 拥有主轴侧轴的概念,可以简单地理解为 XY 坐标系。默认横向为 X 轴,纵向为 Y 轴。可以通过 flex-direction 作用于容器来改变设置。在主轴上子元素的对齐由 justify-content 控制,侧轴子元素对齐由 align-items 控制,同时还可以控制元素显示顺序的 order,相关具体意义及备选值可查看 W3C 草案

flex

很不幸,flex 语法目前仍然处于草案阶段,并且经历了一次 box 旧语法的废弃————上面例子中的语法是最新的写法,从2009年开始各浏览器厂商陆续实现了一种现在被废弃的 box 语法,我们称之为老语法。更糟糕的是,微软的 IE10(包括桌面端和移动端)浏览器实现了一种介于新语法和旧语法之间的中间语法。下面的表格列举了这三种语法的API:

含义 新语法(-webkit- -moz-) 老语法(-webkit- -moz-) IE10语法
1 弹性容器定义 display : flex/inline-flex display : box/inline-box display : -ms-flexbox
2 子元素排列方式 flex-direction : row/ column-row/column/column-reverse box-orient : horizontal/vertical/inline-axis/block-axis/inherit -ms-flex-direction : row/column/row-reverse/column-reverse/inherit
3 主轴子元素对齐 justify-content : flex-start/ flex-end/center/space-around/space-between box-pack : start/end/center/justify -ms-flex-pack : start/end/center/justify
4 侧轴子元素分布 align-content : flex-start/ flex-end/center/space- around/space-between NOT SUPPORTED -ms-flex-line-pack: start/end/center/justify/distribute/stretch
5 侧轴方向子元素对齐 align-items : flex-start/flex-end/center/stretch box-align : start/end /center/baseline/stretch -ms-flex-align : start/end/center/baseline/stretch
6 弹性子元素伸缩值 flex : [positive-flex] [negative-flex] [preferred-size] box-flex : [positive-flex] -ms-flex : [positive-flex] [negative-flex] [preferred-size]
7 子元素排列顺序 order : 1 box-ordinal-group : 1 (positive) -ms-flex-order : 1
8 在子元素中覆盖父元素定义的第5项 align-self : flex-start/flex- end/center/stretch NOT SUPPORTED -ms-flex-item-align : auto/start/end/center/baseline/stretch
9 换行 flex-wrap : wrap/no-wrap/wrap-reverse NOT SUPPORTED -ms-flex-wrap : none/wrap/wrap-reverse

需要指出的是新语法支持多行模式,老语法并不支持。

浏览器支持

Chrome,Safari,Opera,Firefox,IE10+,Android对可伸缩布局进行了支持,其中一些版本仅支持老语法,而另一些同时支持两种语法,查看这里

因此似乎针对 iOS , Android 和 Windows Phone 8 移动设备开发的网站更适合应用 flex 技术,因为这些平台的浏览器都支持其中至少一种语法。针对 PC 你需要一种优雅的降级。

我做了一些针对不同语法的测试,在这里

总结有几点需要注意:

  • 针对 webkit 编程,需要兼容老语法,目前大多数使用 webkit 的浏览器都还不支持新的语法;
  • 仅在横向方向上应用 flex,垂直放向上可以看见老语法在分配高度比例时存在问题;
  • 如果子元素的内容区大小不同时,老语法会引起子元素的不均匀分配,即使子元素能够容纳其内容,这个时候,只要为每个子元素设定 width:100%即可,新语法和IE10在这方面没有问题,即使子元素的内容区溢出。opera(presto)在这个问题上处于中间状态,即内容区不溢出,子元素按照预订比例分配,如果溢出,子元素将会被撑大;
总结

flex 在针对现在浏览器编程的环境中是一个很方便的工具,IE11 和 Firefox 现在已经实现了无前缀的语法,相信 webkit 也会很快完成转换,届时新语法就会成熟,但老版本的 webkit 仍在存在很大的市场,因此在书写可伸缩 CSS 代码时仍然要兼容老语法,这会限制 flex 的应用。相对于普通的百分比计算方法,老语法提供的功能仍然足够日常使用。

另外,可以使用 autoprefixer 来自动屏蔽这三个版本之间的差异。

参考

定义

在几个 getElementsBy* 方法中,getElementsByName 算是比较特殊的,表面上看即只有它不能在 Element 上调用。

W3C 将该方法定义在 HTMLDocument 接口中:

interface HTMLDocument : Document {
           attribute DOMString       title;
  readonly attribute DOMString       referrer;
  readonly attribute DOMString       domain;
  readonly attribute DOMString       URL;
           attribute HTMLElement     body;
  readonly attribute HTMLCollection  images;
  readonly attribute HTMLCollection  applets;
  readonly attribute HTMLCollection  links;
  readonly attribute HTMLCollection  forms;
  readonly attribute HTMLCollection  anchors;
           attribute DOMString       cookie;
    
  void               open();
  void               close();
  void               write(in DOMString text);
  void               writeln(in DOMString text);
  NodeList           getElementsByName(in DOMString elementName);
};

按照此定义, getElementsByName 方法应该仅存在于 HTMLDocument 中而非 Document 中。在能够访问 Document 接口的浏览器(Opera,Chrome,Firefox,Safari和 Internet Explorer 10)中,测试下列代码:

!!Document.prototype.getElementsByName

结果如下:

浏览器 Opera Chrome Firefox Safari IE10
结果 false true false true true

分别观察一下 GeckoWebkit 关于 (HTML)Document 部分的 IDL :

//Gecko 中 HTMLDocument.webidl 文件
interface HTMLDocument : Document {
NodeList getElementsByName(DOMString elementName);
};
//Webkit 中 Document.idl 文件
interface Document : Node {
NodeList getElementsByName([Default=Undefined] optional DOMString
}

可见两者将 getElementsByName 定义在了不同的接口中,似乎 Gecko 的做法更符合 W3C 规范。

对此的解释可能是 WebkitInternet Explorer 按照 whatwg 的 HTML5 草案进行了实现。

返回类型

关于 getElementsBy* 方法的返回类型,whatwg 规定为 HTMLCollectionW3C 规定为 NodeListHTMLCollectionNodeList 两者很类似,都有 length 属性,都可以用数字索引或 item() 方法方位其中元素。但其差异也是明显的,前者成员为 HTMLElement ,而后者为 Node ,前者拥有 namedItem() 方法。现代浏览器对其实现不一致:

浏览器 Opera/Safari/Android Chrome/Firefox Internet Explorer(+WP8)
getElementsByTagName NodeList HTMLCollection HTMLCollection
getElementsByName NodeList NodeList HTMLCollection
getElementsByClassName NodeList HTMLCollection HTMLCollection

显然应该退化到 NodeNodeList 进行编程,避免依赖特定的类型返回值。

0%