垃圾回收机制
最后更新于:2022-04-01 23:55:12
##垃圾收集##
**3. 垃圾收集**
JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
垃圾收集机制的原理:找出那些不再继续使用的变量,然后释放其占用的内存。
垃圾收集器是按固定的时间间隔,周期性地执行回收操作。
垃圾收集器如何判断哪些变量不需要使用了呢?常见的有两种方式
**(1)标记清除**
当变量进入环境(比如在函数中声明一个变量)时,就将这个变量标记为“进入环境”。
标记变量的方式可以是任意的。
垃圾收集器在运行时会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记,而在此之后再被标记的变量将被视为待删除的变量,原因是环境中的变量以及无法访问到这些变量了,最后完成内存清除工作,销毁那些带标记的值并回收它们占用的内存空间。
**(2) 引用计数**
引用计数是不太常见的垃圾收集策略。引用计数可以说是跟踪记录每个值被引用的次数。比如:当声明了一个变量并将一个引用类型值赋给变量时,则这个值的引用次数是1,当同一个值又被赋给另一个变量,则该值的引用次数加1,相反,当包含对这个值引用的变量取得了另外一个值(也就是不指向前面的值)时,这个值的引用次数减1,当这个值的引用次数为0时,就会被销毁并释放内存空间了。
解除引用:一旦数据不再有用,最好通过将其值设置为null来释放其引用。
';
编程风格
最后更新于:2022-04-01 23:55:10
## 编风格程
作为前端开发人员,我相信每一个人都或多或少的用到原生的JavaScript,也正是因为用的人多,导致编码风格也是多种多样的,而不规范的编码风格,不仅会导致一些奇怪的问题出现,而且不利于后期维护和提高执行效率。
基于本人也在开发中因为规范而出现各种问题,我特意的整理了一下JavaScript编码规范(并不强制,只是推荐)。
**1、变量**
声明变量必须加上`var`关键字,而且每个`var`只声明一个变量,增加可读写。
推荐:
```
var name = 'TG';
var sex = 'man';
```
不推荐:
```
var name = 'TG', sex = 'man';
```
**2、常量**
常量的命名方式:用大写字符,并用下划线分隔。尽量不要使用const关键词。
```
var MY_NAME = 'TG';
```
原因:IE并不支持const
**3、行尾分号**
总是使用分号,对于可用可不用的行尾分号,使用分号。
**4、嵌套函数**
可以使用,可以减少重复代码,隐藏帮助函数等好处
**5、块内函数声明**
不要在块内声明一个函数
不推荐:
```
if(a){
function foo(){}
}
```
推荐:
```
if(a){
var foo = function(){}
}
```
**6、异常处理**
可以使用
```
try{}catch(e){}
throw exception
```
**7、eval()**
```
只用于解析序列化串
```
原因:eval()会让程序执行的比较混乱。
**8、with(){}**
尽量少用。
**9、缩进**
用4个空格作为一缩进,而不是使用tab
原因:因为在不同浏览器上,tab的长度不一。
**10、字符串过长截取**
每行代码不超过80个字符。如代码过长,可使用+运算符拼接。
原因:过长会导致需要拖动横向滚动条才看得到后面的代码,降低开发效率,而且在复制黏贴时有可能错漏。
**11、大括号**
区块起首的大括号,不要另起一行
推荐:
```
if (true) {
}
```
不推荐:
```
if (true)
{
}
```
**12、构造函数**
对于构造函数,命名采用首字母大写,其他函数一律小写。
原因:可读性,区分构造函数和普通函数
**13、注释**
合理的加上注释,有利于后期维护,提高可读性。
**14、{}和[]**
使用{}代替new Object(),使用[]代替new Array()
**15、单引号(')**
尽量使用单引号('),只在JSON文件中使用双引号。
**16、变量和函数声明**
变量名和函数名在JavaScript机制下会发生声明提升(也就是会提前到顶部声明),所以建议变量和函数应该在使用前声明。
**17、使用===和!==代替==和!=**
在JavaScript中,比较运算符进行计算时会进行强制转换,==和!=会产生一些意想不到的结果,所以应该用“严格相等”===。
**18、换行**
在语句块和下一个语句之间留一个空行,提高可读性。
**19、命名**
构造函数或类名使用驼峰式命名
**20、嵌入规则**
JavaScript程序应该尽量放在.js的文件中。
**21、命名规则**
JavaScript 中的标识符的命名规则:
以字母、下划线'_'或美元符号'$'开头
允许名称中包含字母,数字,下划线'_'和美元符号'$'
区分大小写
变量、属性和函数名应该用驼峰式:
```
var isLogin = false;
```
私有函数用下划线开头:
```
function getFirstName(){
function _getName(){}
}
```
构造函数和类名应该首字母大写。
对象中私有变量和函数以下划线开头。
**22、语句**
对于复合语句,if, for, while, do, switch, try … catch 等代码体,函数定义的函数体,对象的定义等都需要放在花括号'{}'里面。
'{' 应在行末,标志代码块的开始。
'}' 应在一行开头,标志代码块的结束,同时需要和'{'所在行的开始对齐,以表明一个完整的复合语句段。这样可以极大地提高代码的可阅读性,控制逻辑能清晰地表现出来。
被包含的代码段应该再缩进 4 个空格。
即使被包含的代码段只有一句,也应该用花括号'{}'包含。尽管不用花括号代码也不会错,但如若需要增加语句的话,则较容易因花括号遗漏而引起的编译错误或逻辑错误。
return语句在使用时也需注意,如果用表达式的执行作为返回值,应该把表达式和 return 放在同一行中,以免换行符被误解析为语句的结束而引起返回错误。return 关键字后若没有返回表达式,则返回 undefined。构造器的默认返回值为 this。
return a + b;
**23、方法链(调用链)**
如果使用方法链,应该每行只调用一个方法:
Animal
.getName()
.getFirstName()
**24、使用三元运算符**
三元运算符不应该用在一行,应该分割成多行替代。
推荐:
```
var foo = (a === b)
? 1
: 2;
```
不推荐:
```
var foo = (a === b) ?1 : 2;
```
**25、逗号**
对于数组和对象不要使用多余的“,”
不推荐:
```
var arr = [1,2,]
var person = {
name: 'TG'
};
```
原因:IE不兼容
**26、for-in**
对于数组,尽量避免使用for-in
';
JavaScript开发技巧合集
最后更新于:2022-04-01 23:55:08
## 开发技巧
**1、使用var声明变量**
如果给一个没有声明的变量赋值,默认会作为一个全局变量(即使在函数内赋值)。要尽量避免不必要的全局变量。
**2、行尾使用分号**
虽然JavaScript允许省略行尾的分号,但是有时不注意的省略,会导致不必要的错误。建议在可用可不用行尾分号的地方加上分号。
**3、获取指定范围内的随机数**
```
var getRandom = function(max, min) {
min = arguments[1] || 0;
return Math.floor(Math.random() * (max - min + 1) + min);
};
```
上面的函数接受一个你希望的随机最大数和一个你希望的随机最小数。
**4、打乱数字数组的顺序**
```
var sortArray = array.sort(function(){
return Math.random() - 0.5;
});
```
**5、取出数组中的随机项**
```
var ran = array[Math.floor(Math.random() * array.length)];
```
**6、去除字符串的首尾空格**
```
var s = string.trim();
```
**7、类数组对象转为数组**
比如:类数组对象遍历:
```
Array.prototype.forEach.call(argumens,function(value){
})
```
DOM的NodeList和HTMLCollection也是类数组对象
**8、获取数组中的最大值和最小值**
```
var max = Math.max.apply(Math, array);
var min = Math.min.apply(Math, array);
```
**9、清空数组**
array.length = 0;
array = [];
**10、保留指定小数位**
```
var num = num.toFixed(2);
```
返回字符串,保留两位小数
**11、使用for-in循环来遍历对象的属性**
```
for(var key in object) {
// object[key]
}
```
不要用for-in来遍历数据
**12、获取某月天数**
```
function getMonthDay(date){
date = date || new Date();
if(typeof date === 'string') {
date = new Date(date);
};
date.setDate(32);
return 32 - date.getDate();
}
```
传入date参数,可以是字符串、日期对象实例;为空表示当月天数
**13、浮点数问题**
```
0.1 + 0.2 = 0.30000000000000004 != 0.3
```
JavaScript的数字都遵循IEEE 754标准构建,在内部都是64位浮点小数表示
**14、JSON序列化和反序列化**
使用`JSON.stringify()`来将JavaScript对象序列化为有效的字符串。
使用`JSON.parse()`来将有效的字符串转换为JavaScript对象。
在AJAX传输数据时很有用
**15、使用“===”替换“==”**
相等运算符(==)在比较时会将操作数进行相应的类型转换,而全等运算符(===)不会进行类型转换。
**16、避免使用with()**
使用with()可以把变量加入到全局作用域中,因此,如果有其它的同名变量,一来容易混淆,二来值也会被覆盖。
**17、不要使用eval()或函数构造器**
eval()和函数构造器(Function consturctor)的开销较大,每次调用,JavaScript引擎都要将源代码转换为可执行的代码。
**18、简化if语句**
```
if (condition) {
fn();
}
```
可替换成:
```
condition && fn();
```
**19、给可能省略的参数赋默认值**
```
function test(a, b){
a = a || '1';
}
```
**20、给数组循环中缓存length的值**
如果你确定循环中数组的长度不会变化,那么你可以这样:
```
var length = array.length;
for(var i = 0; i < length; i++) {
}
```
可以避免在每次迭代都将会重新计算数组的大小,提高效率
**21、合并数组**
对于小数组,我们可以这样:
```
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = arr1.concat(arr2); // [1,2,3,4,5,6]
```
不过,concat()这个函数并不适合用来合并两个大型的数组,因为其将消耗大量的内存来存储新创建的数组。在这种情况之个,可以使用`Array.prototype.push.apply(arr1,arr2)`来替代创建一个新数组。
这种方法不是用来创建一个新的数组,其只是将第一个第二个数组合并在一起,同时减少内存的使用:
```
Array.prototype.push.apply(arr1, arr2);
console.log(arr1); // [1,2,3,4,5,6]
```
**22 枚举对象“自身”的属性**
for...in除了枚举对象“自身”的属性外,还会枚举出继承过来的属性。
```
var hasOwn = Object.prototype.hasOwnProperty;
var obj = {name: 'tg', age: 24};
for(var name in obj) {
if (hasOwn.call(obj, name)) {
console.log(name + ':' + obj[name]);
}
}
// name:tg
// age:24
```
';
错误处理机制
最后更新于:2022-04-01 23:55:05
## 错误处理机制
**1、 try-catch语句**
ECMA-262第3版引入了`try-catch`语句,作为JavaScript中处理异常的一种标准方式。
语法:
```
try{
// 可能会导致错误的代码
}catch (error){
// 在错误发生时怎么处理
}
```
也就是说,我们应该把所有可能会抛出错误的代码都放在try语句块中,而把那些用于错误处理代码放在catch块中。
`try-catch`语句的逻辑是:如果try块中的任何代码发生了错误,就会立即退出代码执行过程,然后接着执行catch块。此时,catch块会接收到一个包含错误信息的对象。
注意:即使你不想使用这个错误对象,也要给它起个名字。
虽然这个对象在不同浏览器中可能包含不同信息,但是都有一个保存着错误消息的message属性,还有一个保存错误类型的name属性(并不是所有浏览器都有)。
```
try{
}catch (error){
console.log(error.message);
}
```
在跨浏览器编程时,最好还是只使用message属性。
**1.1 finally子句**
当使用`finally`子句时,其代码无论如何都会执行,也就是说,不管是正常执行还是出错了,`finally`子句都会执行。甚至`return`语句,也不会阻止`finally`子句的执行。
看下面的例子:
```
function test(){
try{
console.log('a');
return 2;
}catch(error){
console.log('b');
}finally{
console.log('c');
}
}
console.log(test());
//结果
a
c
2
```
从运行结果,我们可以看到,`return`语句并没有阻止`finally`子句的执行,而且是在`finally`子句执行后才会返回`return`语句的值。
**2、错误类型**
执行代码期间可能会发生的错误有多种类型。每种错误都有对应的错误类型,而当错误发生时,会抛出相应类型的错误对象。
ECMA-262定义了下列7中错误类型:
```
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
```
Error是基类型,其他错误类型都继承自该类型。所有错误类型共享了一组相同的属性。
**(1)EvalError类型**
EvalError类型的错误会在使用eval()函数而发生异常时抛出。简单的说,如果没有把eval()当成函数调用,就会抛出异常。比如:
```
new eval() // 抛出EvalError
eval = foo; // 抛出EvalError
```
注意:在ES5中已经不在出现了。
**(2)RangeError类型**
RangeError类型的错误会在数值超出相应范围时触发。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。
```
var item = new Array(-20); // 抛出RangeError异常
```
**(3)ReferenceError类型**
在找不到对象的情况下,会发生ReferenceError。通常,在访问不存在的变量时,就会发生这种错误。
```
var obj = x; // 在x并未声明的情况下抛出ReferenceError
```
**(4)SyntaxError类型**
SyntaxError是解析代码时发生的语法错误。
```
var 1a; // 变量名错误,抛出SyntaxError
```
**(5)TypeError类型**
在变量中保存着意外的类型,或在访问不存在的方法时,都会导致这种错误。
```
var o = new 10; //抛出TypeError
```
**(6)URIError类型**
URIError是URI相关函数的参数不正确时抛出的错误,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。
**2.2 抛出错误**
与try-catch语句相配的还有一个throw操作符,用于随时抛出自定义错误。抛出错误时,必须要给throw操作符指定一个值,这个值可以是任何类型。
```
throw 1;
throw 'tg';
throw true;
throw {name: 'tg'};
```
上面的代码都是有效的。
在遇到throw操作符时,代码会立即停止运行。仅当有try-catch语句捕获到被抛出的值时,代码才会继续执行。
**2.3 Error对象**
所有抛出的错误都是Error构造函数的实例。Error构造函数接受一个参数,表示错误提示,可以从实例的message属性读到这个参数。
在JavaScript中,Error对象的实例必须有message属性,表示出错时的提示信息。在大多数JavaScript引擎中,Error实例还可能有name和stack属性,分别表示错误的名称和错误的堆栈。
```
var err = new Error('出错了');
err.message; // "出错了"
```
**2.4 自定义错误**
我们还可以创建自定义错误消息,最常用的错误类型是Error、RangeError、ReferenceError和TypeError。
```
throw new Error('报错了');
throw new RangeError('数组长度错误');
```
另外,利用原型链还可以通过继承Error来创建自定义错误类型:
```
function CustomError(message){
this.name = 'CustomError';
this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError('我的错误信息');
```
**3、错误(error)事件**
任何没有通过try-catch处理的错误都会触发window对象的error事件。
onerror事件处理程序不会创建event对象,但它接受三个参数:错误消息、错误所在的URL和行号。
```
window.onerror = function(message, url, line){
};
```
当你在事件处理程序中返回false,可以阻止浏览器报告错误的默认行为
```
window.onerror = function(message, url, line){
return false;
};
```
**4、调试技术**
**4.1 alert方法**
在以前,大多数都是在要调试的代码中插入alert()函数,看是否执行到这一步来判断哪里出错,这种方式比较麻烦,因为alert()会阻止后续代码的执行(除非你关闭了alert弹窗),而且调试后还要清理。
**4.2 console**
随着浏览器的不断改善,现在的浏览器都有JavaScript控制台,我们可以向这些控制台输出消息,比如最常用的console对象,它的常用方法如下:
- error(message):将错误消息记录到控制台
- info(message):将信息性消息记录到控制台
- log(message):将一般消息记录到控制台
- warn(message):将警告消息记录到控制台
```
function test(){
console.log('结果:' + (1 + 2));
}
```
**4.3 throw**
使用throw抛出错误。
';
SVG
最后更新于:2022-04-01 23:55:03
## SVG:可伸缩的矢量图形
这里只是简要的介绍一下SVG,如要深入,推荐看《SVG经典入门》
**1、SVG**
**1.1 概述**
SVG是一种用于描述图形的XML语法。由于结构是XML格式,使得它可以插入HTML文档,成为DOM的一部分,然后用JavaScript和CSS进行操作。
一个简单的SVG文件如下:
```
```
**1.2 使用方法**
要使用SVG有很多方法,最简单的就是直接将SVG代码嵌入到HTML中:
```
```
SVG代码也可以单独写在一个文件中,后缀是“.svg”,然后用在`、
';
常用API合集
最后更新于:2022-04-01 23:55:01
## 常用API合集
**一、节点**
**1.1 节点属性**
```
Node.nodeName //返回节点名称,只读
Node.nodeType //返回节点类型的常数值,只读
Node.nodeValue //返回Text或Comment节点的文本值,只读
Node.textContent //返回当前节点和它的所有后代节点的文本内容,可读写
Node.baseURI //返回当前网页的绝对路径
Node.ownerDocument //返回当前节点所在的顶层文档对象,即document
Node.nextSibling //返回紧跟在当前节点后面的第一个兄弟节点
Node.previousSibling //返回当前节点前面的、距离最近的一个兄弟节点
Node.parentNode //返回当前节点的父节点
Node.parentElement //返回当前节点的父Element节点
Node.childNodes //返回当前节点的所有子节点
Node.firstChild //返回当前节点的第一个子节点
Node.lastChild //返回当前节点的最后一个子节点
//parentNode接口
Node.children //返回指定节点的所有Element子节点
Node.firstElementChild //返回当前节点的第一个Element子节点
Node.lastElementChild //返回当前节点的最后一个Element子节点
Node.childElementCount //返回当前节点所有Element子节点的数目。
```
**1.2 操作**
```
Node.appendChild(node) //向节点添加最后一个子节点
Node.hasChildNodes() //返回布尔值,表示当前节点是否有子节点
Node.cloneNode(true); // 默认为false(克隆节点), true(克隆节点及其属性,以及后代)
Node.insertBefore(newNode,oldNode) // 在指定子节点之前插入新的子节点
Node.removeChild(node) //删除节点,在要删除节点的父节点上操作
Node.replaceChild(newChild,oldChild) //替换节点
Node.contains(node) //返回一个布尔值,表示参数节点是否为当前节点的后代节点。
Node.compareDocumentPosition(node) //返回一个7个比特位的二进制值,表示参数节点和当前节点的关系
Node.isEqualNode(noe) //返回布尔值,用于检查两个节点是否相等。所谓相等的节点,指的是两个节点的类型相同、属性相同、子节点相同。
Node.normalize() //用于清理当前节点内部的所有Text节点。它会去除空的文本节点,并且将毗邻的文本节点合并成一个。
//ChildNode接口
Node.remove() //用于删除当前节点
Node.before() //
Node.after()
Node.replaceWith()
```
**1.3 Document节点**
**1.3.1 Document节点的属性**
```
document.doctype //
document.documentElement //返回当前文档的根节点
document.defaultView //返回document对象所在的window对象
document.body //返回当前文档的节点
document.head //返回当前文档的节点
document.activeElement //返回当前文档中获得焦点的那个元素。
//节点集合属性
document.links //返回当前文档的所有a元素
document.forms //返回页面中所有表单元素
document.images //返回页面中所有图片元素
document.embeds //返回网页中所有嵌入对象
document.scripts //返回当前文档的所有脚本
document.styleSheets //返回当前网页的所有样式表
//文档信息属性
document.documentURI //表示当前文档的网址
document.URL //返回当前文档的网址
document.domain //返回当前文档的域名
document.lastModified //返回当前文档最后修改的时间戳
document.location //返回location对象,提供当前文档的URL信息
document.referrer //返回当前文档的访问来源
document.title //返回当前文档的标题
document.characterSet属性返回渲染当前文档的字符集,比如UTF-8、ISO-8859-1。
document.readyState //返回当前文档的状态
document.designMode //控制当前文档是否可编辑,可读写
document.compatMode //返回浏览器处理文档的模式
document.cookie //用来操作Cookie
```
**1.3.2 Document节点的方法**
**(1)读写方法**
```
document.open() //用于新建并打开一个文档
document.close() //不安比open方法所新建的文档
document.write() //用于向当前文档写入内容
document.writeIn() //用于向当前文档写入内容,尾部添加换行符。
```
**(2)查找节点**
```
document.querySelector(selectors) //接受一个CSS选择器作为参数,返回第一个匹配该选择器的元素节点。
document.querySelectorAll(selectors) //接受一个CSS选择器作为参数,返回所有匹配该选择器的元素节点。
document.getElementsByTagName(tagName) //返回所有指定HTML标签的元素
document.getElementsByClassName(className) //返回包括了所有class名字符合指定条件的元素
document.getElementsByName(name) //用于选择拥有name属性的HTML元素(比如
';
作用域
最后更新于:2022-04-01 23:54:58
## 作用域
**1.1 作用域**
几乎所有的编程语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。
作用域有全局作用域和局部作用域(一般是在函数内)之分。
**1.1.1 全局作用域**
在代码中任何地方都能访问到的对象拥有全局作用域。
一般来说,拥有全局作用域有以下几种情况:
**(1)在最外层的函数和在最外层函数外面定义的变量拥有全局作用域**
例子:
```
var name = 'tg';
function test(){
var name2 = 'tg';
}
```
在上面的例子中,变量name和函数test()就拥有全局作用域
**(2)所有未定义而直接赋值(不用var关键字声明)的变量被自动声明为拥有全局作用域**
```
funciton test(){
var age = 10;
name = 'tg';
}
test();
console.log(age); // 会报错undefined
console.log(name); // "tg"
```
变量name拥有全局作用域,而age在函数外面是无法访问到的
**(3)所有window对象的属性拥有全局作用域**
window对象的内置属性都由拥有全局作用域,比如window.location、Date对象等
**1.1.2 局部作用域**
局部作用域不像全局作用域,它被限定在一个范围内,最常见的局部作用域就是在函数内部,我们也称为**函数作用域**。
**函数作用域**是指变量能够被使用的代码区间。超出作用域的变量值一般为undefined,或者被其他同名变量值所覆盖。
```
funciton test(){
var age = 10;
console.log(age);
}
test(); // 10
console.log(age); // 会报错undefined
```
在上面的例子中,在函数外面是无法访问到变量age的,但在函数内部是可以访问的。
要记住,对于变量或函数,它的作用域取决于定义时的作用域,而不是在调用它的作用域中。
**1.2 作用域链**
在ES 5中,将作用域链称为**词法环境**。
当代码在一个作用域中执行时,会创建变量对象的一个作用域链(scope chain)。
作用域链的用途:保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链的前端,始终都是当前执行的代码所在作用域的变量对象。如果这个环境是函数,则将其活动对象作为变量对象,然后对于每一个函数的形参,都命名为该活动对象的命名属性。
活动对象在最开始只包含一个变量,即arguments对象(在全局环境中是不存在的)。
看一个例子:
```
var name = 'p';
function test(){
var name = 'tg';
function get(){
console.log(name);
}
get();
}
test(); // "tg"
```
当执行get()时,将创建函数get()的执行环境(调用对象),并将该对象置于作用域链的前端(开头),然后将函数test()的调用对象链接在之后,最后是全局对象,然后从作用域链的前端开始查找标识符name,很显然,变量name的值是"tg";
作用域链:get() -> test() -> window
每次进入一个新的作用域,都会创建一个用于搜索变量和函数的作用域链。
函数的局部变量不仅有权访问函数作用域中的变量,而且有权访问其他包含(父)环境,乃至全局作用域。但是全局作用域只能访问在全局作用域中定义的变量和函数,不能直接访问局部作用域中的任何数据。
变量的作用域有助于确定应该何时释放内存。
**1.3 JavaScript没有块级作用域**
JavaScript中并没有块级作用域。也就是说,对于if、for、while、switch等块结构是没有作用域的。
```
if(true){
var name = 'tg';
}
console.log(name); // "tg"
```
在if语句里定义了一个name变量,但它并不会向在函数内那样,但函数执行结束后就销毁,而是会一直存在,因为它被添加到了当前的执行环境(也就是全局环境)中。
对于for循环也是一样:
```
for(var i = 0; i < 10; i++){
//循环体
}
console.log(i); // 10
```
**(1)声明变量**
使用var声明的变量会自动被添加到最接近的环境中,比如在函数内部,最接近的环境就是函数的局部环境。如果初始化变量没有使用var声明,会自动被添加到全局环境中。
**(2)查询标识符**
标识符的查询规则是:逐级向上查询,如果在局部环境中找到了该标识符,搜索过程就停止,变量就绪,否则,会继续向上查询,直到全局环境的变量对象,如果在全局环境中也没有找到这个标识符,就表示该变量尚未声明(通常会报错)。
```
var name = 'tg2';
function test(){
var name = 'tg';
console.log(name); // "tg"
}
test();
```
在上面的例子中,在函数内部已经找到了name标识符,所以返回的是"tg"
';
原型链
最后更新于:2022-04-01 23:54:56
## 原型链
**3.1 原型**
每一个JavaScript对象(null除外)都和另一个对象相关联,也可以说,继承另一个对象。另一个对象就是我们熟知的“原型”(`prototype`),每一个对象都从原型继承属性。只有null除外,它没有自己的原型对象。
我们可以通过`__proto__`(首尾都是双下划线)来获取实例的原型对象。
注意:`__proto__`连接的是实例与构造函数的原型对象之间,而不是实例与构造函数之间。
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JavaScript代码`Object.prototype`获得对原型对象的引用。
通过关键字new和构造函数调用创建的对象的原型就是构造函数的`prototype`属性的值。比如:通过new Object()创建的对象继承自Object.prototype;通过new Array()创建的对象的原型就是Array.prototype。
没有原型的对象为数不多,`Object.prototype`就是其中之一,它不继承任何属性。
所有的内置构造函数都具有一个继承自`Object.prototype`的原型。
**3.1 原型链**
在JavaScript中,原型链是实现继承的主要方式。
原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
可用`__proto__`属性来获取或设置对象的原型。
每个构造函数都有一个原型对象(prototype),原型对象本身也是对象,所以它也有自己的原型,而它本身的原型对象也有自己的原型,这样层层递进,就形成了一条链,这个链就是**原型链**。
JavaScript引擎在访问对象的属性时,会先在对象本身中查找,如果没有找到,则会去原型链中查找,如果找到,则返回值,如果整个原型链中都没有找到这个属性,则返回undefined。
```
var person = {
name: 'human'
};
var person1 = {
name: 'tg',
__proto__: person
};
var person2 = {
__proto__: person
};
console.log(person1.name); // "tg"
console.log(person2.name); // "human"
console.log(person1.id); // undefined
```
从上面例子的运行结果,我们也可以看出原型链的运行机制:从对象本身出发,沿着`__proto__`查找,直到找到属性名称相同的值(没有找到,则返回undefined)。
所有对象都继承自`Ojbect`,而这个继承也是通过原型链实现的。所有函数的默认原型都是Object的实例,因此默认的原型都会包含一个内部指针,指向`Object.prototype`。而`Object.prototype`的`__proto__`的属性值为null,标志着原型链的结束。
**3.2 原型和实例**
有两种方式来确定原型和实例之间的关系:
- 使用`instanceof`操作符
```
function Person(){}
var person = new Person();
console.log(person instanceof Object); // true
console.log(person instanceof Person); // true
```
- 使用`isPrototypeOf()`方法。
```
console.log(Object.prototype.isPrototypeOf(person)); // true
console.log(Person.prototype.isPrototypeOf(person)); // true
```
';
this关键字
最后更新于:2022-04-01 23:54:54
## this关键字
JavaScript代码都存在于一定的`上下文对象`中。上下文对象通过`this`关键字来动态指定,它永远指向当前对象。简单的说,就是返回属性或方法“当前”所在的对象。
**this的工作原理**
在5种不同的情况下,`this`指向的各不相同。
**(1)全局范围内**
```
this
```
当在全局范围内使用`this`,它将指向全局对象
**(2)函数调用**
```
function test(){
console.log(this);
}
test();
```
这里的`this`也指向全局对象。
**(3)方法调用**
```
test.foo();
```
这个例子中,`this`指向test对象。
**(4)调用构造函数**
```
new test();
```
如果函数倾向于`new`关键词一块使用,则我们称这个函数是构造函数。在函数内部,`this`指向新创建的实例对象。
**(5)显式的设置this**
```
function test(a, b) {}
var bar = {};
test.apply(bar, [1, 2]); //数组将会会被扩展
test.call(bar , 1, 2); // 传递到test的参数是: a = 1, b = 2
```
当使用`Function.prototype`上的`call`或`apply`方法时,函数内的`this`将会被显式设置为函数调用的第一个参数。
**改变this指向的方法**
JavaScript提供了call、apply、bind这三个方法,来切换/固定this的指向。
**(1)call()**
语法:
```
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
```
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
**(2)apply()**
语法:
```
apply([thisObj[,argArray]])
```
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明: 如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。 如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。 bind()方法 bind()方法是在ECMAScript 5中新增的方法。 toString()方法
函数的toString方法返回函数的源码。
```
function f(){
return 1;
}
f.toString()
//function f(){
// return 1;
//}
```
**(3)bind()**
bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
```
var bar=function(){
console.log(this.x);
}
var foo={
x:3
}
bar();
bar.bind(foo)();
/*或*/
var func=bar.bind(foo);
func();
输出:
undefined
3
```
注意:bind()返回的是函数。
';
概述
最后更新于:2022-04-01 23:54:52
## 对象概述
面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript中并没有类的概念,所以它的对象也有有所不同。
ECMAScript对象是一个无序属性的集合,其属性可以包含基本值、对象或函数。
对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。
每个对象都是基于一个引用类型创建的。
**1、对象**
**1.1 创建对象**
(1)创建自定义对象的最简单方式就是创建一个Object的实例,然后给其添加属性和方法:
```
var person = new Object();
person.name = 'tg';
person.age = 10;
person.say = function(){
console.log(this.name);
}
```
上面的例子创建了一个名为person的对象,并为它添加了两个属性(name、age)和一个方法(say())。
(2)对象字面量
```
var person = {
name: 'tg',
age: 10,
say: function(){
console.log(this.name);
}
}
```
这个person对象和上面例子是等价的。
**1.2 属性类型**
ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问它们。该规范将它们放在了两对方括号中,表示特性是内部值,如[[Enumerable]]。
ECMAScript中有两种属性:数据属性和访问权属性
**1.2.1 数据属性**
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。
数据属性有4个描述特性:
- [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。
- [[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。
- [[Writable]]:表示能否修改属性的值。
- [[Value]]: 包含这个属性的数据值。读取属性值时,从这个位置读;写入属性值时,把新值保存在这个位置。默认值为undefined。
要修改属性默认的特性,必须使用ECMAScript 5的`Object.defineProperty()`方法,这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。
```
var person = {};
Object.defineProperty(person, 'name', {
writable: false,
value: 'tg'
});
console.log(person.name); // "tg"
person.name = 'tg2';
console.log(person.name); // "tg"
```
在上面的例子中,我们将person对象中的名为name的属性的`writable`设置为false,也就是不可修改,所以即使后面执行了person.name='tg2',最后person对象的name值依旧是原始值。
注意:在严格模式下,如果对一个不可修改的属性执行赋值操作,会抛出错误;非严格模式下则忽略赋值操作。
一旦将configurable特性设置为false后,就不能再把它变回可配置的了,如果再修改除writable之外的特性,都会导致错误。
**1.2.2 访问器属性**
访问器属性不包含数据值,它们包含一对getter和setter函数(非必需)。在读取访问器属性时,会调用getter函数,返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,它负责决定如何处理数据。
访问器属性:
- [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。比如直接在对象上定义的属性,它们的这个特性默认值为true。
- [[Enumerable]]:表示能否通过for-in循环返回属性。对于直接在对象上定义的值,默认为true。
- [[Get]]:在读取属性时调用的函数,默认为undefined
- [[Set]]:在写入属性时调用的函数,默认为undefined
访问器属性不能直接定义,也是要使用`Object.defineProperty()`方法来定义。
```
var person = {
_age: 20,
intro: ''
};
Object.defineProperty(person, 'age', {
get: function() {
return this._age;
},
set: function(newValue){
if(newValue < 18) {
this.intro = '装嫩';
this._age = newValue;
}
}
});
console.log(person.age); // 20
person.age = 17;
console.log(person.intro); // "装嫩"
```
在上面的例子中,访问器属性age有一个getter函数和一个setter函数。getter函数返回`_age`的值,setter函数通过判断`age`的设置值来改变其他属性值。
**1.2.3 定义多个属性**
ECMAScript 5提供的`Object.defineProperties()`方法可以通过描述符一次定义多个属性,这个方法接收两个对象参数,第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象要添加或修改的属性一一对应。
```
var person = {};
Object.defineProperties(person, {
_age: {
value: 20
},
intro: {
value: ''
},
age: {
get: function(){
return this._age;
},
set: function(newValue){
if(newValue < 18) {
this.intro = '装嫩';
this._age = newValue;
}
}
}
});
```
**1.2.4 读取属性的特性**
ECMAScript 5提供的`Object.getOwnPropertyDescriptor()`方法可以取得给定属性的描述符,它接受两个参数:属性所在的对象和要读取其描述符的属性名称,返回来的是一个对象,如果是访问器属性,这个对象的属性有configurable、enumerable、get和set;如果是数据属性,这个对象的属性有configurable、enumerable、writable和value。
```
var person = {
_age: 20,
intro: ''
};
Object.defineProperty(person, 'age', {
get: function() {
return this._age;
},
set: function(newValue){
if(newValue < 18) {
this.intro = '装嫩';
this._age = newValue;
}
}
});
var descriptor = Object.getOwnPropertyDescriptor(person,'age');
console.log(descriptor.enumerable); // false
console.log(typeof descriptor.get); // "function"
```
在JavaScript中,可以针对任何对象--包括DOM和BOM对象,使用`Object.getOwnPropertyDescriptor()`方法。
';
面向对象的程序设计
最后更新于:2022-04-01 23:54:50
## 面向对象的程序设计
';
Notification
最后更新于:2022-04-01 23:54:47
## Notification
Notifications API 的通知接口用于向用户配置和显示桌面通知。
语法:
```
let notification = new Notification(title, options)
```
参数:
* title:一定会被显示的通知标题
* options 可选,一个被允许用来设置通知的对象。它包含以下属性:
- dir : 文字的方向;它的值可以是 auto(自动), ltr(从左到右), or rtl(从右到左)
- lang: 指定通知中所使用的语言。这个字符串必须在 BCP 47 language tag 文档中是有效的。
- body: 通知中额外显示的字符串
- tag: 赋予通知一个ID,以便在必要的时候对通知进行刷新、替换或移除。
- icon: 一个图片的URL,将被用于显示通知的图标。
### 属性
**静态属性**
`Notification.permission `
只读,一个用于表明当前通知显示授权状态的字符串。可能的值包括:denied (用户拒绝了通知的显示), granted (用户允许了通知的显示), 或 default (因为不知道用户的选择,所以浏览器的行为与 denied 时相同).
**实例属性**
| 属性 | 描述 |
| :--: | :--: |
| Notification.title | 在构造方法中指定的 title 参数 |
| Notification.dir | 通知的文本显示方向 |
| Notification.lang | 通知的语言 |
| Notification.body | 通知的文本内容 |
| Notification.tag | 通知的 ID |
| Notification.icon | 通知的图标图片的 URL 地址 |
**事件**
| 事件 | 描述 |
| :--: | :--: |
| Notification.onclick | 处理 click 事件的处理 |
| Notification.onshow | 处理 show 事件的处理 |
| Notification.onerror | 处理 error 事件的处理 |
| Notification.onclose | 处理 close 事件的处理 |
### 方法
**静态方法**
`Notification.requestPermission()`
用于当前页面想用户申请显示通知的权限。这个方法只能被用户行为调用(比如:onclick 事件),并且不能被其他的方式调用。
**实例方法**
| 方法 | 描述 |
| :--: | :--: |
| Notification.close() | 用于关闭通知 |
**简单实例**
```
// 申请权限
function requestNotification(title, options) {
// 先检查浏览器是否支持
if (!('Notification' in window)) {
alert('This browser does not support desktop notification');
}
// 检查用户是否同意接受通知
else if (Notification['permission'] === 'granted') {
this.openNotification(title, options);
}
// 否则我们需要向用户获取权限
else if (Notification['permission'] !== 'denied') {
Notification.requestPermission((permission) => {
if (permission === 'granted') {
// 如果用户同意,就可以向他们发送通知
openNotification(title, options);
}
});
}
}
function openNotification(title, options) {
const notification = new Notification(title, options);
notification.onclose = (event) => {
// 当关闭时
}
}
requestNotification('您有一条消息通知', {
body: '来自XX',
requireInteraction: true,
data: {},
icon: 'notification-icon.jpg'
});
```
';
Web Speech
最后更新于:2022-04-01 23:54:45
## Web Speech 语音输入
老版本中,如果我们要部署一个带有语音搜索功能的input,可用如下代码:
```
```
然后通过webkitspeechchange事件来监听用户输入:
```
var speech = document.getElementById('speech');
speech.onwebkitspeechchange = funciton(){
}
```
注意:目前只有Chrome支持这种带语音的输入框。
在新版本中,我们还可以用JavaScript操作语音输入,就是通过Web Speech这个API。(也是只有Chrome支持)
主要有两部分:
- 语言识别(将所说的转换成文本文字)
- 语言合成(将文本文字读出来)
**1、语言识别**
**1.1 SpeechRecognition对象**
这个API部署在`SpeechRecognition`对象之上。
**1.1.1 检测是否支持**
```
if ('webkitSpeechRecognition' in window) {
// 支持
}
```
确定支持后,新建一个`SpeedchRecognition`的实例对象:
```
if ('webkitSpeechRecognition' in window) {
var recognition = new webkitSpeechRecognition();
}
```
**1.1.2 属性和方法**
**属性**
- continous:是否让浏览器始终进行语言识别,默认为false,也就是说,当用户停止说话时,语音识别就停止了。这种模式适合处理短输入的字段。
- maxAlternatives:设置返回的最大语音匹配结果数量,默认为1
- lang:设置语言类型,默认值就继承自HTML文档的根节点或者是祖先节点的语言设置。
**方法**
- start():启动语音识别
- stop():停止语音识别
- abort():中止语音识别
**1.1.3 事件**
浏览器会询问用户是否许可浏览器获取麦克风数据
这个API提供了11个事件。
- audiostart:当开始获取音频时触发,也就是用户允许时。
- audioend:当获取音频结束时触发
- error:当发生错误时触发
- nomatch:当找不到与语音匹配的值时触发
- result: 当得到与语音匹配的值时触发,它传入的是一个SpeechRecognitionEvent对象,它的results属性就是语音匹配的结果数组,最匹配的结果排在第一位。该数组的每一个成员是SpeechRecognitionResult对象,该对象的transcript属性就是实际匹配的文本,confidence属性是可信度(在0到1之间)
- soundstart
- soundend
- speechstart
- speechend
- start:当开始识别语言时触发
- end:当语音识别断开时触发
看个实例:
```
var speech = document.getElementById('speech');
if('webkitSpeechRecognition' in window) {
var recognition = new webkitSpeechRecognition();
recognition.onaudiostart = function(){
speech.value = '开始录音';
};
recognition.ononmatch = function(){
speech.value = '没有匹配结果,请再次尝试';
};
recognition.onerror = function(){
speech.value ='错误,请再次尝试';
};
// 如果得到与语音匹配的值,则会触发result事件。
recognition.onresult = function(event){
if(event.results.length > 0) {
var results = event.results[0];
var topResult = results[0];
if(topResult.confidence > 0.5) {
} else {
speech.value = '请再次尝试';
}
}
}
}
```
**2、语音合成**
语音合成只有Chrome和Safari支持。
**2.1 SpeechSynthesisUtterance对象**
打开控制台,黏贴下面的函数,然后调用:
```
funciton speak(textToSpeak){
var newUtterance = new SpeechSynthesisUtterance();
newUtterance.text = textToSpeak;
window.speechSynthsisi.speak(newUtterance);
}
```
**2.1 SpeechSynthesisUtteranc的实例对象的属性**
- text:识别的文本
- volume:音量(0~1)
- rate:发音速度
- pitch:音调
- voice:声音
- lang:语言类型
**2.2 window.speechSynthesis.getVoices()**
通过API提供给用户的声音在很大程度上取决于操作系统。谷歌有自己的一套给Chrome的默认声音,可以在Mac OS X,Windows和Ubuntu上使用。Mac OS X的声音也可用,所以和OSX的Safari的声音一样。你可以通过开发者工具的控制台看有哪种声音可用。
`window.speechSynthesis.getVoices()`用来获取发音列表,返回一个数组,每个元素的name属性表示声音名称
**2.3 window.speechSynthsisi.speak()**
`window.speechSynthsisi.speak()`方法是用于发音的。
';
Performance API
最后更新于:2022-04-01 23:54:43
## Performance API 高精度时间戳
PerFormance API是ECMAScript 5才引入的,它的精度可达到1毫秒的千分之一。
目前,所有主要浏览器都已经支持`performance`对象,包括Chrome 20+、Firefox 15+、IE 10+、Opera 15+。
**1.1 performance.timing对象**
`performance`对象是全局的,它的`timing`属性是一个对象,它包含了各种与浏览器性能有关的时间数据,提供浏览器处理网页各个阶段的耗时。
`performance.timing`对象包含下列属性(全部只读):
```
navigationStart:当前浏览器窗口的前一个网页关闭,发生unload事件时的Unix毫秒时间戳。如果没有前一个网页,则等于fetchStart属性。
unloadEventStart:如果前一个网页与当前网页属于同一个域名,则返回前一个网页的unload事件发生时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。
unloadEventEnd:如果前一个网页与当前网页属于同一个域名,则返回前一个网页unload事件的回调函数结束时的Unix毫秒时间戳。如果没有前一个网页,或者之前的网页跳转不是在同一个域名内,则返回值为0。
redirectStart:返回第一个HTTP跳转开始时的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。
redirectEnd:返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的Unix毫秒时间戳。如果没有跳转,或者不是同一个域名内部的跳转,则返回值为0。
fetchStart:返回浏览器准备使用HTTP请求读取文档时的Unix毫秒时间戳。该事件在网页查询本地缓存之前发生。
domainLookupStart:返回域名查询开始时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。
domainLookupEnd:返回域名查询结束时的Unix毫秒时间戳。如果使用持久连接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值。
connectStart:返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。
connectEnd:返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。
secureConnectionStart:返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全连接,则返回0。
requestStart:返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳。
responseStart:返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳。
responseEnd:返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。
domLoading:返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的Unix毫秒时间戳。
domInteractive:返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。
domContentLoadedEventStart:返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、所有脚本开始运行时)的Unix毫秒时间戳。
domContentLoadedEventEnd:返回当前网页所有需要执行的脚本执行完成时的Unix毫秒时间戳。
domComplete:返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的Unix毫秒时间戳。
loadEventStart:返回当前网页load事件的回调函数开始时的Unix毫秒时间戳。如果该事件还没有发生,返回0。
loadEventEnd:返回当前网页load事件的回调函数运行结束时的Unix毫秒时间戳。如果该事件还没有发生,返回0。
```
**1.2 performance中的方法**
**(1)performance.now()**
`performance.now`方法返回当前网页自从`performance.timing.navigationStart`到当前时间之间的微秒数(毫秒的千分之一)。也就是说,它的精度可以达到100万分之一秒。
**(2)performance.mark()**
mark方法用于为相应的视点做标记。
clearMarks方法用于清除标记,如果不加参数,就表示清除所有标记。
**(3)performance.getEntries()**
浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个HTTP请求。`performance.getEntries`方法以数组形式,返回这些请求的时间统计信息,有多少个请求,返回数组就会有多少个成员。
**1.3 performance.navigation对象**
除了时间信息,performance还可以提供一些用户行为信息,主要都存放在performance.navigation对象上面。
它有两个属性:
**(1)performance.navigation.type**
该属性返回一个整数值,表示网页的加载来源,可能有以下4种情况:
```
0:网页通过点击链接、地址栏输入、表单提交、脚本操作等方式加载,相当于常数performance.navigation.TYPE_NAVIGATENEXT。
1:网页通过“重新加载”按钮或者location.reload()方法加载,相当于常数performance.navigation.TYPE_RELOAD。
2:网页通过“前进”或“后退”按钮加载,相当于常数performance.navigation.TYPE_BACK_FORWARD。
255:任何其他来源的加载,相当于常数performance.navigation.TYPE_UNDEFINED。
```
**(2)performance.navigation.redirectCount**
该属性表示当前网页经过了多少次重定向跳转。
';
Page Visibility API
最后更新于:2022-04-01 23:54:40
## PageVisibility
**1、PageVibility**
PageVisibility API是用于判断页面是否处于浏览器的当前窗口,即是否可见。
这API是部署在`document`对象上的。
**1.1 属性**
它有两个属性:
- `document.hidden`:返回一个布尔值,表示当前是否被隐藏,只读
- `document.visibilityState`:只读,表示页面当前的状态,有四个可能值:`visibile`(页面可见)、`hidden`(页面不可见)、`prerender`(页面正处于渲染之中,不可见)、`unloaded`(如果文档被卸载了)
在使用这两个属性时,要加上不同浏览器的私有前缀:
获取`hidden`属性值:
```
function getHiddenProp() {
var prefixes = ['webkit', 'moz', 'ms', 'o'];
if ( 'hidden' in document) return 'hidden;
for(var i = 0; i < prefixes.length; i++) {
var hidden = prefixes[i] + 'Hidden';
if( hidden in document) {
return hidden;
}
};
return null;
}
```
获取`visibilityState`属性
```
function getVisibilityState() {
var prefixes = ['webkit', 'moz', 'ms', 'o'];
if ( 'visibilityState' in document) return 'visibilityState;
for(var i = 0; i < prefixes.length; i++) {
var visibilityState = prefixes[i] + 'VisibilityState';
if( hidden in document) {
return visibilityState;
}
};
return null;
}
```
**1.2 事件**
当页面的可见状态发生变化时,会触发`visibilityChange`事件(也是需要加上私有前缀)
```
var hidden = getHiddenProp();
var visibilityChange = hidden.split(/[H|h]/, '')[0] + 'visibilitychange';
document.addEventListener(visibilityChange, function(){
console.log( document[getVisibilityState] );
});
```
';
WebRTC
最后更新于:2022-04-01 23:54:38
## WebRTC
WebRTC(Web Real-Time Communication,网页实时通信),是一个支持网页浏览器进行实时语音对话或视频对话的API。
**1、getUserMedia**
要播放摄像头的影像,首先需要一个video标签:
```
```
获取摄像头影像主要是通过`navigator.getUserMedia`这个接口,这个接口的支持情况已经逐渐变好了([点击这里](http://caniuse.com/#search=getUserMedia)),不过,使用的时候还是要加上前缀的。
兼容代码:
```
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
```
语法:
```
navigator.getUserMedia(constraints, successCallback, errorCallback);
```
参数说明:
- constraints:Object类型,指定了请求使用媒体的类型
- succeCallback:启用成功时的函数,它传入一个参数,为视频流对象,可以进一步通过`window.URL.createObjectURL()`接口把视频流转换为对象URL。
- errorCallback:启动失败时的函数。它传入一个参数,为错误对象(chrome)或错误信息字符串(Firefox),可能值:
```
PERMISSION_DENIED:用户拒绝提供信息。
NOT_SUPPORTED_ERROR:浏览器不支持硬件设备。
MANDATORY_UNSATISFIED_ERROR:无法发现指定的硬件设备。
```
例如要启用视频设备(摄像头),可这样:
```
navigator.getUserMedia({
video: true
});
```
如果要同时启用视频设备和音频设备,可这样:
```
navigator.getUserMedia({
video: true,
audio: true
});
```
**1.1 获取摄像头完整实例**
```
```
当点击直播按钮时,电脑会提升用户是否允许使用摄像头,允许之后,网页上就可以实时显示摄像头影像了。如果不允许,就会触发错误事件。
**1.1.1 截图**
除了实时直播外,我们还可以做实时截图效果,这时我们需要利用`
';
Luminosity API
最后更新于:2022-04-01 23:54:36
## Luminosity
**6、屏幕亮度(Luminosity API)**
Luminosity API用来屏幕亮度调节,不过目前只有Firefox支持。
当移动设备的亮度传感器感知外部亮度发生显著变化时,会触发devicelight事件。
```
window.addEventListener('devicelight', function(event) {
console.log(event.value + 'lux');
});
```
上面代码表示,devicelight事件的回调函数,接受一个事件对象作为参数。该对象的value属性就是亮度的流明值。
';
vibrate
最后更新于:2022-04-01 23:54:34
## vibrate
**5、设备震动(Vibration API)**
Vibration接口用于在浏览器中发出命令,使得设备振动。
**(1)检测是否可用**
目前,只有Chrome和Firefox的Android平台最新版本支持它。
```
navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;
if (navigator.vibrate) {
// 支持
}
```
**(2)振动**
```
navigator.vibrate(1000);
```
vibrate()方法的参数就是振动持续的毫秒数,除了单个数值外,还可以接受一个数组作为参数,表示振动的模式。偶数位置的数组成员表示振动的毫秒数,奇数位置的数组成员表示等待的毫秒数。
```
navigator.vibrate([200,100,300])
```
上面代码表示,设备先振动200毫秒,然后等待100毫秒,再接着振动300毫秒。
注意:vibrate是一个非阻塞式的操作,即手机振动的同时,JavaScript代码仍然继续向下运行。要停止振动,只有将0毫秒或者一个空数组传入vibrate方法。
';
Blob
最后更新于:2022-04-01 23:54:31
## Blob
**2、Blob**
Blob(Binary Large Object)对象代表了一段二进制数据,提供了一系列操作接口。比如通过new Blob()创建的对象就是Blob对象.又比如,在XMLHttpRequest里,如果指定responseType为blob,那么得到的返回值也是一个blob对象.
**2.1 生成Blob对象**
生成Blob对象有两种方法:一种是使用Blob构造函数,另一种是对已有的Blob对象使用slice()方法切出一段。
**(1)Blob构造函数**
```
var blob = new Blob(data, type)
```
Blob构造函数接受两个参数:
参数data是一组数据,所以必须是数组,即使只有一个字符串也必须用数组装起来.
参数type是对这一Blob对象的配置属性,目前也只有一个type也就是相关的MIME需要设置 type的值:
'text/csv,charset=UTF-8' 设置为csv格式,并设置编码为UTF-8
'text/html' 设置成html格式
注意:任何浏览器支持的类型都可以这么用
```
var blob = new Blob(['我是Blob'],{type: 'text/html'});
```
**2.2 属性**
```
blob.size //Blob大小(以字节为单位)
blob.type //Blob的MIME类型,如果是未知,则是“ ”(空字符串)
```
**2.3 slice()**
slice()返回一个新的Blob对象,包含了源Blob对象中指定范围内的数据。
```
blob.slice(
optional long long start,
optional long long end,
optional DOMString contentType };
```
参数说明:
start 可选,开始索引,可以为负数,语法类似于数组的slice方法.默认值为0.
end 可选,结束索引,可以为负数,语法类似于数组的slice方法.默认值为最后一个索引.
contentType可选 ,新的Blob对象的MIME类型,这个值将会成为新的Blob对象的type属性的值,默认为一个空字符串.
**2.4 Blob的使用**
使用Blob最简单的方法就是创建一个URL来指向Blob:
```
下载
var data= 'Hello world!';
var blob = new Blob([data], {
type: 'text/html,charset=UTF-8'
});
window.URL = window.URL || window.webkitURL;
document.querySelector("#getData").href = URL.createObjectURL(blob);
```
上面的代码将Blob URL赋值给a,点击后提示下载文本文件data.txt,文件内容为“Hello World”。
**2.5 URL.createObjectURL()**
```
objectURL = URL.createObjectURL(blob);
```
使用URL.createObjectURL()函数可以创建一个Blob URL,参数blob是用来创建URL的File对象或者Blob对象,返回值格式是:blob://URL。
注意:在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法传入创建的URL为参数,用来释放它。浏览器会在文档退出的时候自动释放它们,但是为了获得最佳性能和内存使用状况,你应该在安全的时机主动释放掉它们。
**2.6 乱码问题**
当数据中包含汉字时,导出的文件可能会出现乱码,不过我们可以这样解决:
```
var data = "\ufeff" + "汉字";
```
';
检测设备方向
最后更新于:2022-04-01 23:54:29
## 检测设备方向
**7、手机设备方向**
**7.1 方向**
Orientation API用于检测手机的摆放方向(竖放或横放)。
**(1)检测浏览器是否支持**
```
if(window.DeviceOrientationEvent){
//支持
}else{
//不支持
}
```
**(2)监听方向变化**
一旦设备的方向发生变化,会触发deviceorientation事件,可以对该事件指定回调函数。
```
window.addEventListener("deviceorientation", listener,false);
function listener(event){
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
}
```
上面代码中,event事件对象有alpha、beta和gamma三个属性,它们分别对应手机摆放的三维倾角变化。要理解它们,就要理解手机的方向模型。当手机水平摆放时,使用三个轴标示它的空间位置:x轴代表横轴、y轴代表竖轴、z轴代表垂直轴。event对象的三个属性就对应这三根轴的旋转角度。
- alpha:表示围绕z轴的旋转,0~360(度)。当设备水平摆放时,顶部指向地球的北极,alpha此时为0。
- beta:表示围绕x轴的旋转,-180~180(度),由前向后。当设备水平摆放时,beta此时为0。
- gramma:表示围绕y轴的选择,-90~90(度),从左到右。当设备水平摆放时,gramma此时为0。
**7.2 移动(motion)**
**(1)检测是否支持**
```
if(window.DeviceMotionEvent){
//支持
}else{
//不支持
}
```
**(2)和方向事件一样,移动也有监听事件:devicemotion**
```
window.addEventListener('devicemotion',listener,true)
function listener(event){
var acceleration = event.acceleration;
var accelerationIncludingGravity = event.accelerationIncludingGravity;
var rotationRate = event.rotationRate;
var interval = event.interval;
}
```
上面代码中,event事件对象有acceleration、accelerationIncludingGravity、rotationRate和interval四个属性。
属性说明:
**(1)acceleration、accelerationIncludingGravity**
acceleration和accelerationIncludingGravity属性都包含三个轴:
x轴:西向东(acceleration.x)
y轴:南向北(acceleration.y)
z轴:垂直地面(acceleration.z)
**(2)rotationRate**
rotationRate有三个值:
alpha: 设备沿着垂直屏幕的轴的旋转速率 (桌面设备相对于键盘)
beta: 设备沿着屏幕左至右方向的轴的旋转速率(桌面设备相对于键盘)
gamma: 设备沿着屏幕下至上方向的轴的旋转速率(桌面设备相对于键盘)
**(3)interval**
interval 表示的是从设备获取数据的频率,单位是毫秒。
更多:检测设备方向
**简单的摇一摇功能:**
```
var SHAKE_THRESHOLD = 3000;
var last_update = 0;
var x = y = z = last_x = last_y = last_z = 0;
if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', deviceMotionHandler, false);
}
function deviceMotionHandler(eventData) {
var acceleration = eventData.accelerationIncludingGravity;
var curTime = new Date().getTime();
var diffTime = curTime - last_update;
if (diffTime > 100) {
last_update = curTime;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;
var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
if (speed > SHAKE_THRESHOLD) {
//dosomething
};
last_x = x;
last_y = y;
last_z = z;
}
}
```
';