感觉JavaScript里面还有很多基础的细节没搞明白,开个坑专门存一下。
转义特殊字符
如果要匹配的 ID 或选择器不符合 CSS 语法(比如不恰当地使用了冒号或者空格),你必须用反斜杠将这些字符转义。由于 JavaScript 中,反斜杠是转义字符,所以当你输入一个文本串时,你必须将它转义两次(一次是为 JavaScript 字符串转义,另一次是为 querySelector 转义):
<div id="foo\bar"></div>
<div id="foo:bar"></div>
<script>
console.log('#foo\bar') // "#fooar"
document.querySelector('#foo\bar') // 不匹配任何元素
console.log('#foo\\bar') // "#foo\bar"
console.log('#foo\\\\bar') // "#foo\\bar"
document.querySelector('#foo\\\\bar') // 匹配第一个 div
document.querySelector('#foo:bar') // 不匹配任何元素
document.querySelector('#foo\\:bar') // 匹配第二个 div
</script>
//补充:document.querySelector选择器特殊使用
/*
这里,一个 class 属性为"user-panel main"的 div 元素
<div>(<div class="user-panel main">)
内包含一个 name 属性为"login"的 input 元素
<input> (<input name="login"/>)
如何选择,如下所示:
*/
var el = document.querySelector("div.user-panel.main input[name='login']");
转义字符 | 译义 |
---|---|
\ ? | 在书写连续多个问好时使用,防止他们被解析成三字母词 |
\ ’ | 用于表示字符常量‘ |
\ " | 用于表示字符常量" |
\ \ | 用于表示一个反斜杠,防止他被解译成一个转义字符 |
\ a | 警告字符,表示:蜂鸣 |
\ b | 退格符 |
\ f | 换页符 |
\ n | 换行符 |
\ r | 回车符 |
\ t | 水平制表符 |
\ v | 垂直制表符 |
\ ddd | 三位八进制数代表一个ASCII字符(ddd是一个八进制数字) |
\ xdd | 二为十六进制数代表一个ASCII字符(dd是一个十六进制数字) |
var、let、const异同
1)作用域
用 var 声明的变量的作用域是它当前的执行上下文,即如果是在任何函数外面,则是全局执行上下文,如果在函数里面,则是当前函数执行上下文。换句话说,var 声明的变量的作用域只能是全局或者整个函数块的。
而 let 声明的变量的作用域则是它当前所处代码块,即它的作用域既可以是全局或者整个函数块,也可以是 if、while、switch等用{}限定的代码块。
另外,var 和 let 的作用域规则都是一样的,其声明的变量只在其声明的块或子块中可用。
function varTest() {
var a = 1;
{
var a = 2; // 函数块中,同一个变量
console.log(a); // 2
}
console.log(a); // 2
}
function letTest() {
let a = 1;
{
let a = 2; // 代码块中,新的变量
console.log(a); // 2
}
console.log(a); // 1
}
let 声明的作用域比 var 声明的作用域有更小的限定范围,更具灵活。
2)重复性
var 允许在同一作用域中重复声明,而 let 不允许,否则将抛出异常。
var a = 1;
var a = 2;
console.log(a) // 2
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
3)绑定全局对象
var 在全局环境声明变量,会在全局对象里新建一个属性,而 let 在全局环境声明变量,则不会在全局对象里新建一个属性。
var foo = 'global'
let bar = 'global'
console.log(this.foo) // global
console.log(this.bar) // undefined
- let 在全局环境声明变量 bar 保存在 [[Scopes]][0]: Script 这个变量的属性中;
- 而 [[Scopes]][1]: Global 就是我们常说的全局对象。
4)变量提升与暂存死区
- var 声明的变量在执行上下文创建阶段就会被「创建」和「初始化」,因此对于执行阶段来说,可以在声明之前使用。
- let 声明的变量在执行上下文创建阶段只会被「创建」而不会被「初始化」,因此对于执行阶段来说,如果在其定义执行前使用,相当于使用了未被初始化的变量,会报错。
//示例代码 1:
console.log(bar); // undefined
console.log(foo); // ReferenceError: foo is not defined
var bar = 1;
let foo = 2;
//示例代码 2:
var foo = 33;
{
let foo = (foo + 55); // ReferenceError: foo is not defined
}
5)const变量
const 与 let 很类似,都具有上面提到的 let 的特性,唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。因此,const 一旦声明必须初始化,否则会报错。
let a;
const b = "constant"
a = "variable"
b = 'change' // TypeError: Assignment to constant variable
如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量。
// 此处可调用 carName 变量
//此处可使用 window.carName
function myFunction() {
carName = "Volvo";
// 此处可调用 carName 变量
}
-
JavaScript 变量生命周期在它声明时初始化。
-
局部变量在函数执行完毕后销毁。
-
全局变量在页面关闭后销毁。
-
使用var关键字声明的全局作用域变量属于window对象。
-
使用let关键字声明的全局作用域变量不属于window对象。
-
使用var关键字声明的变量在任何地方都可以修改。
-
在相同的作用域或块级作用域中,不能使用let关键字来重置var关键字声明的变量。
-
在相同的作用域或块级作用域中,不能使用let关键字来重置let关键字声明的变量。
-
let关键字在不同作用域,或不用块级作用域中是可以重新声明赋值的。
-
在相同的作用域或块级作用域中,不能使用const关键字来重置var和let关键字声明的变量。
-
在相同的作用域或块级作用域中,不能使用const关键字来重置const关键字声明的变量
-
const 关键字在不同作用域,或不同块级作用域中是可以重新声明赋值的:
-
var关键字定义的变量可以先使用后声明。
-
let关键字定义的变量需要先声明再使用。
-
const关键字定义的常量,声明时必须进行初始化,且初始化后不可再修改
数据类型
1.使用 constructor 属性来查看对象
//判断是否为数组
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
//判断是否为日期对象
function isDate(myDate) {
return myDate.constructor.toString().indexOf("Date") > -1;
}
2.类型转换的多种方法
//转化为字符 x可为数字、布尔值、日期
String(x)
x.toString() //甚至可以转换函数function 结果为整个函数体( function myFunction(a, b) {...} )
//转化为数字
/*全局方法 Number() 可以将字符串转换为数字。
字符串包含数字(如 "3.14") 转换为数字 (如 3.14).
空字符串转换为 0。
其他的字符串会转换为 NaN (不是个数字)。*/
Number(x) //x可为布尔值、日期、字符;无效字符会转换成NaN
parseFloat() //解析一个字符串,并返回一个浮点数。
parseInt() //解析一个字符串,并返回一个整数。
//自动转换类型
5 + null // 返回 5 null 转换为 0
"5" + null // 返回"5null" null 转换为 "null"
"5" + 1 // 返回 "51" 1 转换为 "1"
"5" - 1 // 返回 4 "5" 转换为 5
正则表达式
var patt = /runoob/i
实例解析:
-
/runoob/i 是一个正则表达式。
-
runoob 是一个正则表达式主体 (用于检索)。
-
i 是一个修饰符 (搜索不区分大小写)。(g-执行全局匹配(查找所有匹配),m-执行多行匹配)
1.使用字符串方法
-
search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。
-
replace() 方法用于在字符串中用一些字符串替换另一些字符串,或替换一个与正则表达式匹配的子串。
-
test() 方法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。
-
exec() 方法用于检索字符串中的正则表达式的匹配。该函数返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。
2.正则表达式规则
表达式 | 描述 |
---|---|
[abc] | 查找方括号之间的任何字符。 |
[0-9] | 查找任何从 0 至 9 的数字。 |
(x | y) |
元字符 | 描述 |
---|---|
\d | 查找数字。 |
\s | 查找空白字符。 |
\b | 匹配单词边界。 |
\uxxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符。 |
量词 | 描述 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串。 |
n* | 匹配任何包含零个或多个 n 的字符串。 |
n? | 匹配任何包含零个或一个 n 的字符串。 |
使用误区
1.比较
在常规的比较中,数据类型是被忽略的,以下 if 条件语句返回 true:
var x = 10;
var y = "10";
if (x == y)
在严格的比较运算中,=== 为恒等计算符,同时检查表达式的值与类型,以下 if 条件语句返回 false:(switch 语句会使用恒等计算符(=)==进行比较:)
var x = 10;
var y = "10";
if (x === y)
2.浮点数
JavaScript 中的所有数据都是以 64 位浮点型数据(float) 来存储。
所有的编程语言,包括 JavaScript,对浮点型数据的精确度都很难确定:
var x = 0.1;
var y = 0.2;
var z = x + y // z 的结果为 0.30000000000000004
if (z == 0.3) // 返回 false
//为解决以上问题,可以用整数的乘除法来解决:
var z = (x * 10 + y * 10) / 10; // z的结果为 0.3
3.JSON 与 JS 对象
JSON 是 JS 对象的字符串表示法。它使用文本表示一个 JS 对象的信息,(JSON)本质是一个字符串。如:
var obj = {a: 'Hello', b: 'World'}; //这是一个js对象,注意js对象的键名也是可以使用引号包裹的,这里的键名就不用引号包含
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON(格式字符串)和JS对象互转(JSON.parse和 JSON.stringify)。
使用 JSON.parse() 方法从JSON字符串转换为JS对象:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'} 一个对象
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}' 一个JSON格式的字符串
JSON.parse() 就是字符串转 js 对象, JSON.stringify()就是 js 对象转字符串,
它们前提是要 json 格式才有意义。
JavaScript Promise
1.构造 Promise
new Promise(function (resolve, reject) {
// 要做的事情...
});
2.使用resolve 和 reject
resolve 和 reject 都是函数,其中调用 resolve 代表一切正常,reject 是出现异常时所调用的:
- resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
- resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。
new Promise(function (resolve, reject) {
var a = 0;
var b = 1;
if (b == 0) reject("Divide zero");
else resolve(a / b);
}).then(function (value) {
console.log("a / b = " + value);
}).catch(function (err) {
console.log(err);
}).finally(function () {
console.log("End");
});
这段程序执行结果是:
a / b = 0
End
Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:
new Promise(function (resolve, reject) {
console.log(1111);
resolve(2222);
}).then(function (value) {
console.log(value);
return 3333;
}).then(function (value) {
console.log(value);
throw "An error";
}).catch(function (err) {
console.log(err);
});
这段程序执行结果是:
1111
2222
3333
An error
JavaScript函数
1.函数参数
ES6自带参数
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
arguments对象
JavaScript 函数有个内置的对象 arguments 对象。
argument 对象包含了函数调用的参数数组,常称为隐式参数
x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
var i, sum = 0;
for (i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
2.函数调用
在浏览器中的页面对象是浏览器窗口(window 对象)。以上函数会自动变为 window 对象的函数。
myFunction() 和 window.myFunction() 是一样的:
function myFunction(a, b) {
return a * b;
}
myFunction(10, 2); // myFunction(10, 2) 返回 20
window.myFunction(10, 2); // window.myFunction(10, 2) 返回 20
全局对象
- 当函数没有被自身的对象调用时 this 的值就会变成全局对象。
- 在 web 浏览器中全局对象是浏览器窗口(window 对象)。
- 该实例返回 this 的值是 window 对象:
function myFunction() {
return this;
}
myFunction(); // 返回 window 对象
//对比对象种的this
var myObject = {
firstName:"John",
lastName: "Doe",
fullName: function () {
return this;
}
}
myObject.fullName(); // 返回 [object Object] (所有者对象)
作为函数方法调用函数
call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。
function myFunction(a, b) {
return a * b;
}
myObject = myFunction.call(myObject, 10, 2); // 返回 20
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray); // 返回 20
两个方法都使用了对象本身作为第一个参数。 两者的区别在于第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
-
在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。
-
在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。
3.闭包
function add() {
var counter = 0;
return counter += 1;
}
add();
add();
add();
// 本意是想输出 3, 但事与愿违,输出的都是 1 !
比较于:
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器为 3
- 变量 add 指定了函数自我调用的返回字值。
- 自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。
- add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
- 这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
- 计数器受匿名函数的作用域保护,只能通过 add 方法修改。
DOM
1.HTMLCollection
getElementsByTagName 和 getElementsByClassName 这两个方法查找多个 dom 元素,返回的是 htmlcollection 类型,是伪数组而不是真数组,故不能使用数组的方法。
我们可以使用数组原型配合 slice 方法,利用 call,apply,bind 方法将伪数组转为真数组。
var x=document.getElementById("main");
var y=x.getElementsByTagName("p");
console.log(y)//在控制台我们可以看到原型proto为htmlcollection,是伪数组
//伪数组转为真数组方法1
console.log(Array.prototype.slice.call(y))//在控制台我们可以看到原型proto为Array(0),是真数组
//伪数组转为真数组方法2
console.log(Array.prototype.slice.apply(y))//在控制台我们可以看到原型proto为Array(0),是真数组
//伪数组转为真数组方法3
console.log(Array.prototype.slice.bind(y)())//在控制台我们可以看到原型proto为Array(0),是真数组
2.NodeList
集合 length 属性常用于遍历集合中的元素。
//修改所有 <p> 元素的背景颜色:
var myCollection = document.getElementsByTagName("p");
var i;
for (i = 0; i < myCollection.length; i++) {
myCollection[i].style.backgroundColor = "red";
}
而大部分浏览器的 querySelectorAll() 返回 NodeList 对象。
//修改节点列表中所有 <p> 元素的背景颜色:
var myNodelist = document.querySelectorAll("p");
var i;
for (i = 0; i < myNodelist.length; i++) {
myNodelist[i].style.backgroundColor = "red";
}
HTMLCollection 与 NodeList 的区别
HTMLCollection | NodeList |
---|---|
HTML 元素的集合 | 一个文档节点的集合 |
可以通过 name,id 或索引来获取 | 只能通过索引来获取 |
/ | 只有 NodeList 对象有包含属性节点和文本节点。 |
JavaScript对象
1.JavaScript prototype(原型对象)
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
var myFather = new Person("John", "Doe", 50, "blue");
Person.nationality = "English";
console.log(myFather.nationality) //undefined
对比于:使用prototype 属性(可添加属性及方法)
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
console.log(myFather.nationality) //English
2.Window
<script>
txt = "<p>浏览器代号: " + navigator.appCodeName + "</p>";
txt+= "<p>浏览器名称: " + navigator.appName + "</p>";
txt+= "<p>浏览器版本: " + navigator.appVersion + "</p>";
txt+= "<p>启用Cookies: " + navigator.cookieEnabled + "</p>";
txt+= "<p>硬件平台: " + navigator.platform + "</p>";
txt+= "<p>用户代理: " + navigator.userAgent + "</p>";
txt+= "<p>用户代理语言: " + navigator.language + "</p>";
document.getElementById("example").innerHTML=txt;
</script>
window.history.back()//返回上一页
window.history.forward()//前往下一页
window.history.go(1); // go() 里面的参数表示跳转页面的个数 例如 history.go(1) 表示前进
window.history.go(-1); // go() 里面的参数表示跳转页面的个数 例如 history.go(-1) 表示后退一个页面
window.history.go(0); // go() 里面的参数为0,表示刷新页面
ES6-ES11指路:https://blog.csdn.net/lyyrhf/article/details/115338763