HTML 语义类标签
语义类标签是什么,使用它有什么好处?
1、语义类标签对开发者更为友好,使用语义类标签增强了可读性,即便是在没有CSS的时候,开发者也能够清晰地看出网页的结构,也更为便于团队的开发和维护。
2、除了对人类友好之外,语义类标签也十分适宜机器阅读。它的文字表现力丰富,更适合搜索引擎检索(SEO),也可以让搜索引擎爬虫更好地获取到更多有效信息,有效提升网页的搜索量,并且语义类还可以支持读屏软件,根据文章可以自动生成目录等等。
“用对”比“不用”好,“不用”比“用错”好
作为自然语言延伸的语义类标签
em
em标签告诉浏览器把其中的文本表示为强调的内容。
对于所有浏览器来说,这意味着要把这段文字用斜体来显示。
和strong是不同的产物
作为标题摘要的语义类标签
h1-h6
h1-h6是最基本的标题,它们表示了文章中不同层级的标题
hgroup
在hgroup中的h1-h6被视为同一标题的不同组成部分
作为整体结构的语义类标签
正确使用整体结构类的语义标签,可以让页面对机器更友好
header 头部标签
nav 导航链接标签
footer 尾部标签
aside 侧边栏标签
section 标签定义文档中的节(section、区段),比如章节、页眉、页脚或文档中的其他部分
article 独立的自包含内容。一般来说,article会有标题部分( 包含在header内 ),有时也会包含footer。
address 一个给机器阅读的地址,而是表示“文章(作者)的联系方式”
<body> <header> <nav> …… </nav> </header> <aside> <nav> …… </nav> </aside> <article> <header>……</header> <section>……</section> <section>……</section> <section>……</section> <footer>……</footer> </article> <article> …… </article> <article> …… </article> <section>……</section> <section>……</section> <section>……</section> <footer> <address>……</address> </footer> </body>
语义类标签一览
aside 表示侧边栏、导航性质的工具内容
article 文字主体部分、有明确的独立性
hgroup 标题组
h1~h6 各级标题
abbr 表示缩写
hr 横向分隔线
p 表示段落
strong 加粗、表示很重要
blockquote 表示段落级引述内容
q 表示行内的引述内容
cite 表示引述的作品名
time 日期、方便机器阅读
figure 插入文章中的内容、不限于图片、代码、表格等等
figcaption 内容标题
dfn 包裹被定义的名词
nav 导航目录
ol 有序列表
ul 无序列表
pre 预先排版、不需要浏览器换行
samp 计算机程序的示例输出
code 定义计算机代码
samll 补充评论
s 划线 错误内容、主要用于电商打折前的价格
i 斜体 读的变调
b 黑体 关键字
u 下划线 避免歧义的标记
data 和time类似、利于机器阅读
var 变量、多用于计算机和数学领域
kbd 用户输入、键盘按键居多
sub 下标
sup 上标
bdo,bdi 语言书写方向(从右到左、或者从左到右)
mark 高亮
wbr 可以换行的位置
menu ul的变体、用于功能菜单
dl,dd,dt 对一些术语的定义
main 整个页面只出现一个、页面的主要内容、特殊的div
JavaScript 关于类型
七种数据类型一览
运行时类型是代码实际执行过程中我们用到的类型。所有的类型数据都会属于7个类型之一。从变量、参数、返回值到表达式中间结果,任何JavaScript代码运行过程中产生的数据,都具有运行时类型。
原始数据类型
Boolean
含义:表示逻辑上的真或假
取值:true 和 false
Null
含义:表示值为空
取值:null
注意:
1、null是关键字。
2、可以通过将变量的值赋值为null将其清空
Undeffined
含义:表示未初始化
取值:undefined
注意:
1、undefined是运行时创建的全局变量。
2、没有为函数传参,该函数值为undefined,或函数没有显示返回,则返回值为undefined
Number
含义:表示数字
取值:-(2^63-1) ~ 2^63-1
注意:
1、符合IEEE754-2008规定的双精度浮点数规则。
2、既可以表示整数,又可以表示浮点数。
3、还引入了+Infinity,-Infinity和NaN。
4、只有一个整数又两种表示方法:+0 和 -0 。
5、非整数不能通过==或===来判断,但是可以采用Math.abs(0.1+0.2-0.3)<=Number.EPSILON
String
含义:表示文本数据
取值:最大长度2^53-1
注意:
1、采用UTF16
2、处理非BMP(超出U+0000 - U+FFFF范围)的字符需要格外小心
Symbol
含义:表示独一无二的值
取值:通过Symbol函数生成的、如:let s = Symbol()
注意:
1、主要为了表征对象属性名的唯一性,基本上类似String类型
2、Symbol函数前不能使用new命令
3、Symbol函数可接受字符串参数作为Symbol实例的描述
4、Symbol值不能与其他类型的值进行运算
演示代码:
// ES6 引入了一种新的原始数据类型Symbol, 表示独一无二的值。 它是 JavaScript 语言的第七种数据类型, 前六种是: undefined、 null、 布尔值( Boolean)、 字符串( String)、 数值( Number)、 对象( Object)。 // 例子: var teacher = { [Symbol('name')]: '忠彬老师', [Symbol('description')]: '讲课讲得好' } var dabinge = { [Symbol('name')]: '大彬哥', [Symbol('description')]: '帅' } var target = {}; Object.assign(target, teacher, dabinge); console.log(target); // console.log(target, teacher, dabinge); // 这个在书写插件和库的时候很重要, 因为经常涉及到选项或者参数合并, symbal很好的解决了这个问题。 // 解决问题的场景: var teacher = { name: '忠彬老师', description: '讲课讲得好' } var dabinge = { name: '大彬哥', description: '帅' } var target = {}; //结合两个对象复制到一个新对象 Object.assign(target, teacher, dabinge); console.log(target); // console.log(target, teacher, dabinge);
Object类型
含义:表示一组属性的集合
取值:
1、字面量、如:var person = {name: 'tom' , age: '18'};
2、Object函数、如:var obj = Object(value); 、参数的若是原始类型的值则返回其包装对象、参数若是对象则返回其本身
3、Object构造函数、如:var obj = new Object(); 、与Object函数的规则类型,但语义不同、Object函数表示类型转换、Object构造函数表示生成一个新的对象。
4、Object.create方发、如:const me = Object.create(person); 、指定原型对象和属性、返回一个新的对象
注意:
1、对象有两种属性:数据属性、访问器属性
3、对象的属性名可以是String类型、也可以是Symbol类型
相关问题
- 为什么有的编程规范要求用void 0代替undefined?
因为JavaScript的代码undefined是一个变量,而并非是一个关键字,这是JavaScript语言公认的设计失误之一,所以,我们为了避免无意中被篡改,我建议使用 void 0 来获取undefined值。
- 字符串有最大长度吗?
有、最大长度为2^53-1
- 0.1 + 0.2不是等于0.3么?为什么JavaScript里不是这样的?
根据浮点数的定义,非整数的Number类型无法用 ==(===也不行) 来比较:
console.log( 0.1 + 0.2 == 0.3);
这里输出的结果是false,说明两边不相等的,这是浮点运算的特点,浮点数运算的精度问题导致等式左右的结果并不是严格相等,而是相差了个微小的值。
所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用JavaScript提供的最小精度值:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
检查等式左右两边差的绝对值是否小于最小精度,才是正确的比较浮点数的方法。这段代码结果就是 true 了。
- ES6新加入的Symbol是个什么东西?
Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象key的集合,在ES6规范中,整个对象系统被用Symbol 重塑。
表示独一无二的值。
- 为什么给对象添加的方法能用在基本类型上?
Symbol.prototype.hello = () => console.log("hello"); var a = Symbol("a"); console.log(typeof a); //symbol,a并非对象 a.hello(); //hello,有效
运算符提供了装箱操作,它会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对应对象的方法。
类型转换
讲完了基本类型,我们来介绍一个现象:类型转换。
因为JS是弱类型语言,所以类型转换发生非常频繁,大部分我们熟悉的运算都会先进行类型转换。大部分类型转换符合人类的直觉,但是如果我们不去理解类型转换的严格定义,很容易造成一些代码中的判断失误。
其中最为臭名昭著的是JS中的“ == ”运算,因为试图实现跨类型的比较,它的规则复杂到几乎没人可以记住。
这里我们当然也不打算讲解==的规则,它属于设计失误,并非语言中有价值的部分,很多实践中推荐禁止使用“ ==”,而要求程序员进行显式地类型转换后,用 === 比较。
其它运算,如加减乘除大于小于,也都会涉及类型转换。幸好的是,实际上大部分类型转换规则是非常简单的,如下表所示:
在这个里面,较为复杂的部分是Number和String之间的转换,以及对象跟基本类型之间的转换。我们分别来看一看这几种转换的规则。
StringToNumber
字符串到数字的类型转换,存在一个语法结构,类型转换支持十进制、二进制、八进制和十六进制,比如:
30;
0b111;
0o13;
0xFF。
此外,JavaScript支持的字符串语法还包括正负号科学计数法,可以使用大写或者小写的e来表示:
1e3;
-1e-2。
需要注意的是,parseInt 和 parseFloat 并不使用这个转换,所以支持的语法跟这里不尽相同。
在不传入第二个参数的情况下,parseInt只支持16进制前缀“0x”,而且会忽略非数字字符,也不支持科学计数法。
在一些古老的浏览器环境中,parseInt还支持0开头的数字作为8进制前缀,这是很多错误的来源。所以在任何环境下,都建议传入parseInt的第二个参数,而parseFloat则直接把原字符串作为十进制来解析,它不会引入任何的其他进制。
多数情况下,Number 是比 parseInt 和 parseFloat 更好的选择。
NumberToString
在较小的范围内,数字到字符串的转换是完全符合你直觉的十进制表示。当Number绝对值较大或者较小时,字符串表示则是使用科学计数法表示的。这个算法细节繁多,我们从感性的角度认识,它其实就是保证了产生的字符串不会过长。
具体的算法,你可以去参考JavaScript的语言标准。由于这个部分内容,我觉得在日常开发中很少用到,所以这里我就不去详细地讲解了。
装箱转换
每一种基本类型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
装箱机制会频繁产生临时对象,在一些对性能要求较高的场景下,我们应该尽量避免对基本类型做装箱转换。
使用内置的 Object 函数,我们可以在JavaScript代码中显式调用装箱能力。
var symbolObject = Object(Symbol("a")); console.log(typeof symbolObject); //object console.log(symbolObject instanceof Symbol); //true console.log(symbolObject.constructor == Symbol); //true
每一类装箱对象皆有私有的 Class 属性,这些属性可以用 Object.prototype.toString 获取:
var symbolObject = Object(Symbol("a")); console.log(Object.prototype.toString.call(symbolObject)); //[object Symbol]
在 JavaScript 中,没有任何方法可以更改私有的 Class 属性,因此Object.prototype.toString 是可以准确识别对象对应的基本类型的方法,它比 instanceof 更加准确。
但需要注意的是,call本身会产生装箱操作,所以需要配合 typeof 来区分基本类型还是对象类型。
拆箱转换
在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两个方法,这两个方法都返回一个对象,然后我们进行o*2这个运算的时候,你会看见先执行了valueOf,接下来是toString,最后抛出了一个TypeError,这就说明了这个拆箱转换失败了。
到 String 的拆箱转换会优先调用 toString。我们把刚才的运算从o*2换成 o + “”,那么你会看到调用顺序就变了。
var o = { valueOf : () => {console.log("valueOf"); return {}}, toString : () => {console.log("toString"); return {}} } 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
七种规范类型
List 和 Record: 用于描述函数传参过程。
Set:主要用于解释字符集等。
Completion Record:用于描述异常、跳出等语句执行过程。
Reference:用于描述对象属性访问、delete等。
Property Descriptor:用于描述对象的属性。
Lexical Environment 和 Environment Record:用于描述变量和作用域。
Data Block:用于描述二进制数据。
JavaScript对象:关于面向对象
什么是面向对象?
从人类的认知角度来说,对象应该是下列事物之一:
- 一个可以触摸或者可以看见的东西;
- 人的智力可以理解的东西;
- 可以指导思考或行动(进行想象或施加动作)的东西。
设计者也利用各种不同的语言特性来抽象描述对象,最为成功的流派是使用“类”的方式来描述对象,这诞生了诸如 C++、Java等流行的编程语言。
而 JavaScript 早年却选择了一个更为冷门的方式:原型(关于原型,我在下一篇文章会重点介绍,这里你留个印象就可以了)。这是我在前面说它不合群的原因之一。
然而很不幸,因为一些公司政治原因,JavaScript推出之时受管理层之命被要求模仿Java,所以,JavaScript创始人Brendan Eich在“原型运行时”的基础上引入了new、this等语言特性,使之“看起来更像Java”。
JavaScript 对象的特征
- 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
对象具有唯一标识的内存地址、所以对象是具有唯一性的。
var o1 = { a: 1 }; var o2 = { a: 1 }; console.log(o1 == o2); // false
- 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
- 对象具有行为:即对象的状态,可能因为它的行为产生变迁。
关于对象的第二个和第三个特征“状态和行为”,不同语言会使用不同的术语来抽象描述它们,比如C++中称它们为“成员变量”和“成员函数”,Java中则称它们为“属性”和“方法”。
在 JavaScript中,将状态和行为统一抽象为“属性”,考虑到 JavaScript 中将函数设计成一种特殊对象,所以 JavaScript中的行为和状态都能用属性来抽象。
下面这段代码中,o是对象,d是一个属性,而函数f也是一个属性,尽管写法不太相同,但是对JavaScript来说,d和f就是两个普通属性。
var o = { d: 1, f() { console.log(this.d); } };
JavaScript中对象独有的特色是:对象具有高度的动态性,这是因为JavaScript赋予了使用者在运行时为对象添改状态和行为的能力。
JavaScript对象的两类属性
第一类属性,数据属性。
它比较接近于其它语言的属性概念。数据属性具有四个特征。
- value:就是属性的值。
- writable:决定属性能否被赋值。
- enumerable:决定for in能否枚举该属性。
- configurable:决定该属性能否被删除或者改变特征值。
定义属性的代码会产生数据属性,其中的writable、enumerable、configurable都默认为true。
可以使用内置函数 Object.getOwnPropertyDescripter来查看。
如果我们要想改变属性的特征,或者定义访问器属性,我们可以使用Object.defineProperty。
如代码演示:
var o = { a: 1 }; Object.defineProperty(o, "b", {value: 2, writable: false, enumerable: false, configurable: true}); //a和b都是数据属性,但特征值变化了 Object.getOwnPropertyDescriptor(o,"a"); // {value: 1, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor(o,"b"); // {value: 2, writable: false, enumerable: false, configurable: true} o.b = 3; console.log(o.b); // 2 // 因为writable特征为false,所以我们重新对b赋值,b的值不会发生变化。
第二类属性是访问器(getter/setter)属性。
它也有四个特征。
- getter:函数或undefined,在取属性值时被调用。
- setter:函数或undefined,在设置属性值时被调用。
- enumerable:决定for in能否枚举该属性。
- configurable:决定该属性能否被删除或者改变特征值。
在创建对象时,也可以使用 get 和 set 关键字来创建访问器属性,代码如下所示:
var o = { get a() { return 1 } }; console.log(o.a); // 1
访问器属性跟数据属性不同,每次访问属性都会执行getter或者setter函数。这里我们的getter函数返回了1,所以o.a每次都得到1。
实际上JavaScript 对象的运行时是一个“属性的集合”,属性以字符串或者Symbol为key,以数据属性特征值或者访问器属性特征值为value。
如以上面的对象o为例:
“a”是key。
{writable:true,value:1,configurable:true,enumerable:true}
是value。
未完待续......
未完待续......
(内容总结于源自winter《重学前端》)