链接:https://time.geekbang.org/column/intro/154
(一HTML语义)
这里我们可以介绍一下 em 标签。
今天我吃了一个<em>苹果</em>。
今天我吃了<em>一个</em>苹果。
章 - 回显示
<h1>HTML语义</h1>
<p>balah balah balah balah</p>
<h2>弱语义</h2>
<p>balah balah</p>
<h2>结构性元素</h2>
<p>balah balah</p>
......
h1-h6 是最基本的标题,它们表示了文章中不同层级的标题。有些时候,我们会有副标题,为了避免副标题产生额外的一个层级,我们使用 hgroup 标签。
<hgroup>
<h1>JavaScript对象</h1>
<h2>我们需要模拟类吗?</h2>
</hgroup>
<p>balah balah</p>
......
从 HTML 5 开始,我们有了 section 标签,这个标签可不仅仅是一个“有语义的 div”,它会改变 h1-h6 的语义。section 的嵌套会使得其中的 h1-h6 下降一级,因此,在 HTML5 以后,我们只需要 section 和 h1 就足以形成文档的树形结构:
<section>
<h1>HTML语义</h1>
<p>balah balah balah balah</p>
<section>
<h1>弱语义</h1>
<p>balah balah</p>
</section>
<section>
<h1>结构性元素</h1>
<p>balah balah</p>
</section>
......
</section>
作为整体结构的语义类标签
<body>
<header>
<nav>
……
</nav>
</header>
<aside>
<nav>
……
</nav>
</aside>
<section>……</section>
<section>……</section>
<section>……</section>
<footer>
<address>……</address>
</footer>
</body>
article 是一种特别的结构,它表示具有一定独立性质的文章。所以,article 和 body 具有相似的结构,同时,一个 HTML 页面中,可能有多个 article 存在。一个典型的场景是多篇新闻展示在同一个新闻专题页面中,这种类似报纸的多文章结构适合用 article 来组织。
article 是一种特别的结构,它表示具有一定独立性质的文章。所以,article 和 body 具有相似的结构,同时,一个 HTML 页面中,可能有多个 article 存在。一个典型的场景是多篇新闻展示在同一个新闻专题页面中,这种类似报纸的多文章结构适合用 article 来组织。
body 里面有自己的 header 和 footer,然后里面是竖篇的 article,每一个 article 里面都有自己的 header、section、footer。这是一个典型的多文章结构。在这个结构里,我们看到了一些新标签,我也来逐个介绍一下。header,如其名,通常出现在前部,表示导航或者介绍性的内容。footer,通常出现在尾部,包含一些作者信息、相关链接、版权信息等。header 和 footer 一般都是放在 article 或者 body 的直接子元素,但是标准中并没有明确规定,footer 也可以和 aside,nav,section 相关联(header 不存在关联问题)。aside 表示跟文章主体不那么相关的部分,它可能包含导航、广告等工具性质的内容。aside 很容易被理解为侧边栏,实际上二者是包含关系,侧边栏是 aside,aside 不一定是侧边栏。aside 和 header 中都可能出现导航(nav 标签),二者的区别是,header 中的导航多数是到文章自己的目录,而 aside 中的导航多数是到关联页面或者是整站地图。最后 footer 中包含 address,这是个非常容易被误用的标签。address 并非像 date 一样,表示一个给机器阅读的地址,而是表示“文章(作者)的联系方式”,address 明确地只关联到 article 和 body。
(二 如何运用语义类标签来呈现Wiki网页)
类型转换
装箱转换每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。前文提到,全局的 Symbol 函数无法使用 new 来调用,但我们仍可以利用装箱机制来得到一个 Symbol 对象,我们可以利用一个函数的 call 方法来强迫产生装箱。我们定义一个函数,函数里面只有 return this,然后我们调用函数的 call 方法到一个 Symbol 类型的值上,这样就会产生一个 symbolObject。我们可以用 console.log 看一下这个东西的 type of,它的值是 object,我们使用 symbolObject instanceof 可以看到,它是 Symbol 这个类的实例,我们找它的 constructor 也是等于 Symbol 的,所以我们无论从哪个角度看,它都是 Symbol 装箱过的对象:
/** 装箱*/
var symbolObject = (function(){ return this; }).call(Symbol("a"));
console.log(typeof symbolObject); //object
console.log(symbolObject instanceof Symbol); //true
console.log(symbolObject.constructor == Symbol); //true
var symbolObject = Object(Symbol("a")); console.log(typeof symbolObject); //object console.log(symbolObject instanceof Symbol); //true console.log(symbolObject.constructor == Symbol); //true
var symbolObject = Object(Symbol("a"));
console.log(Object.prototype.toString.call(symbolObject)); //[object Symbol]
/拆箱*/
在 JavaScript 标准中,规定了 ToPrimitive 函数,它是对象类型到基本类型的转换(即,拆箱转换)。对象到 String 和 Number 的转换都遵循“先拆箱再转换”的规则。通过拆箱转换,把对象变成基本类型,再从基本类型转换为对应的 String 或者 Number。拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。
var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
o * 2
// valueOf
// toString
// TypeError
我们定义了一个对象 o,o 有 valueOf 和 toString 两个方法,这两个方法都返回一个对象,然后我们进行 o2 这个运算的时候,你会看见先执行了 valueOf,接下来是 toString,最后抛出了一个 TypeError,这就说明了这个拆箱转换失败了。到 String 的拆箱转换会优先调用 toString。我们把刚才的运算从 o2 换成 String(o),那么你会看到调用顺序就变了。
···
var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
String(o)
// toString
// valueOf
// TypeError
···
在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为。
···
var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
o[Symbol.toPrimitive] = () => {console.log("toPrimitive"); return "hello"}
console.log(o + "")
// toPrimitive
// hello
···
JavaScript 对象的特征
对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
对象有状态:对象具有状态,同一对象可能处于不同状态之下。
对象具有行为:即对象的状态,可能因为它的行为产生变迁。
var o1 = { a: 1 };
var o2 = { a: 1 };
console.log(o1 == o2); // false
对 JavaScript 来说,属性并非只是简单的名称和值,JavaScript 用一组特征(attribute)来描述属性(property)。先来说第一类属性,数据属性。它比较接近于其它语言的属性概念。数据属性具有四个特征。
value:就是属性的值。
writable:决定属性能否被赋值。
enumerable:决定 for in 能否枚举该属性。
configurable:决定该属性能否被删除或者改变特征值
第二类属性是访问器(getter/setter)属性,它也有四个特征。getter:函数或 undefined,在取属性值时被调用。setter:函数或 undefined,在设置属性值时被调用。enumerable:决定 for in 能否枚举该属性。configurable:决定该属性能否被删除或者改变特征值。
如果所有对象都有私有字段[[prototype]],就是对象的原型;读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。
这个模型在 ES 的各个历史版本中并没有很大改变,但从 ES6 以来,JavaScript 提供了一系列内置函数,以便更为直接地访问操纵原型。三个方法分别为:Object.create 根据指定的原型创建新对象,原型可以是 null;Object.getPrototypeOf 获得一个对象的原型;Object.setPrototypeOf 设置一个对象的原型。
在 JavaScript 中,我们把不带控制能力的语句称为普通语句。普通语句有下面几种。声明类语句var 声明const 声明let 声明函数声明类声明表达式语句空语句debugger 语句这些语句在执行时,从前到后顺次执行(我们这里先忽略 var 和函数声明的预处理机制),没有任何分支或者重复执行逻辑。普通语句执行后,会得到 [[type]] 为 normal 的 Completion Record,JavaScript 引擎遇到这样的 Completion Record,会继续执行下一条语句。这些语句中,只有表达式语句会产生 [[value]],当然,从引擎控制的角度,这个 value 并没有什么用处。如果你经常使用 Chrome 自带的调试工具,可以知道,输入一个表达式,在控制台可以得到结果,但是在前面加上 var,就变成了 undefined。Chrome 控制台显示的正是语句的 Completion Record 的[[value]]。