前言
前端的知识比较零散,特别是笔者之前找工作一开始复习的时候几乎无从下手,更难成体系。故之后开始慢慢的搜集资料,网上的资料琳琅满目,但对于一个个体来说仍是零散的,故复习的同时整理出一套自己的知识体系,脑子里有这么一个大纲之后,再去学习或者复习便会事半功倍。总结的时候,形式有两种,一种是陈述,一种是以问答的方式,希望读者能习惯。笔者整理出来的大纲大概如下:
这一篇是基本知识
变量类型与类型转换
在 JS 中基本数据类型有如下七种:
- string
- number
- null
- undefined
- boolean
- symbol
- bigint
引用类型则有如下三种:
- 对象
- 函数
- 数组
引用类型与基本数据类型
基本数据类型存储的是值,而不同的是,引用类型存储的是引用(地址、指针)。观察如下代码:
const a = []
const b = a
b.push(1)
console.log(b)
console.log(a)
当我们把引用类型赋值给另一个变量时,实际上赋值的是引用类型的引用。也就是变量b
和变量a
指向的是同一块内存空间。所以修改b
自然也会影响到a
深浅拷贝
在上一小节的赋值中,我们复制了地址,在正常开发的过程中当然不希望出现这种问题,这里就可以用浅拷贝来解决这种情况,浅拷贝是拷贝一层,如果属性值是对象,则拷贝对象的地址。
常用的浅拷贝方法有Object.assign
、拓展运算符...
let obj = {
name:'jay'
}
let b = Object.assign({},obj)
b.name = 'jack'
console.log(obj.name)// jay
或者
let obj = {
name:'jay'
}
let b = {...obj}
b.name = 'jack'
console.log(obj.name)// jay
深拷贝
浅拷贝只解决了第一层的问题,如果第一层中仍存在对象,则要用到深拷贝了。
通常可以使用JSON.parse(JSON.stringify(object))
来解决。但是这个方法有如下局限性:
- 忽略undefined、symbol
- 不能序列化函数
- 不能解决循环引用
let obj = {
name:'jay'
skills:['html','css']
}
let b = JSON.parse(JSON.stringify(obj))
b.skills.push('js')
console.log(obj.skills)
当然也可以自己实现一个深拷贝,但是实现一个深拷贝是比较困难的,需要考虑到很多边界条件,这里展示一个不完整版。
const typeMap = {
'[object Array]': 'array',
'[object Object]': 'object',
'[object Function]': 'function',
'[object Symbol]': 'symbol',
'[object RegExp]': 'regexp'
}
function deepClone(target, map = new WeakMap()) {
let cloneTarget
let type = typeMap[getType(target)]
if (type === 'symbol') {
//处理symbol
return Object(Symbol.prototype.valueOf.call(target));
} else if (type === 'function') {
//处理function
return cloneFunction(target)
} else if (type === 'object' || type === 'array') {
cloneTarget = getInit(target)
} else {
return target
}
//避免循环引用
if (map.get(target)) {
return map.get(target)
} else {
map.set(target, cloneTarget)
}
//遍历
for (const key in target) {
cloneTarget[key] = deepClone(target[key], map)
}
return cloneTarget
function getInit(target) {
const constructor = target.constructor
return new constructor()
}
function getType(target) {
return Object.prototype.toString.call(target)
}
function cloneFunction(func) {
const bodyReg = /\{([\s\S]*)\}$/;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const funcString = func.toString();
if (func.prototype) {
console.log('普通函数');
const param = paramReg.exec(funcString);
const body = bodyReg.exec(funcString);
console.log(body)
if (body) {
console.log('匹配到函数体:', body[0]);
if (param) {
const paramArr = param[0].split(',');
console.log('匹配到参数:', paramArr);
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
} else {
return null;
}
} else {
return eval(funcString);
}
}
}
JS中使用typeof能得到哪些数据类型
null
虽然是基本数据类型,但是在当初设计的时候对象是000
开头的,而 null
全是0,所以有了这么一个误判。
- string
- number
- undefined
- boolean
- symbol
- function
- object
- bigint
实现一个类型判断函数
- 判断
null
- 判断基本类型
- 使用
Object.prototype.call.toString(object)
来判断引用类型
function getType(target){
//先判断null
if(target==null){
return 'null'
}
//判断基本类型
let t = typeof target
if(t !== 'object'){
return t
}
const template = {
"[object Object]": "object",
"[object Array]" : "array",
// 一些包装类型
"[object String]": "object - string",
"[object Number]": "object - number",
"[object Boolean]": "object - boolean"
}
const objectType = Object.prototype.toString.call(target)
return template[objectType]
}
转boolean
以下为假值,其他所有值都为 true
,包括所有对象(空对象、空数组)
- false
- undefined
- null
- ‘’
- NaN
- 0
- -0
对象转基本类型
对象转为基本类型时,先调用 valueOf
方法,再调用 toString
方法
var a = {
valueOf(){
return 0
}
toString(){
return '1'
}
}
1 + a // 1
'1'.concat(a) //"11"
也可以重写 Symbol.toPrimitive
,该方法在转基本类型时调用优先级最高。 Symbol.toPrimitive 指将被调用的指定函数值的属性转换为相对应的原始值。
判断一个数据是不是Array
Array.isArray(obj)
ECMAScript5
中的函数,使用ie8
会出现问题
obj instanceof Array
- 当用来检测在不同的window或iframe里构造的数组时会失败。这是因为每一个iframe都有它自己的执行环境,彼此之间并不共享原型链,所以此时的判断一个对象是否为数组就会失败。此时我们有一个更好的方式去判断一个对象是否为数组。
Object.prototype.toString.call(obj) == '[object Array]'
- 这个方法比较靠谱
obj.constructor === Array
- constructor属性返回对创建此对象的函数的引用
== 操作符
对于来说,两者类型不一样就会进行类型转换,而=则不会发生类型转换,即双方类型与值都一样时才会返回true
判断流程:
- 首先判断两者类型是否相同,相同就比大小
- 类型不同就进行类型转换
- 先判断是否在对比
null
与undefined
,如果是就return true
- 判断两者类型是否为
string
和number
,如果是则将string
转为number
1 == '1'
↓
1 == 1
- 判断其中一方是否为Boolean,如果是将Boolean转为number
'1' == true
↓
'1' == 1
↓
1 == 1
- 判断其中一方是否为
object
且另一方为string
、number
或者symbol
,如果是则将object
转为基本数据类型
'1' == { a: 'b' }
↓
'1' == '[object Object]'
- 两边都是对象的话,那么只要不是同一对象的不同引用,都为
false
注意,只要出现NaN
,就一定是false
,因为就连NaN
自己都不等于NaN
对于NaN
,判断的方法是使用全局函数 isNaN()
{}等于true还是false
{}==true
{}==false
两个都是 false
因为 a.toString() -> '[object Object]' -> NaN
其他运算符
- 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来
- 如果有一个操作数不是数值,则在后台调用
Number()
将其转换为数值
看如下例子
1 + "1"
2 * "2"
[1, 2] + [2, 1]
"a" + + "b"
- 1 + “1”
- 加性操作符:如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来
- 所以值为:“11”
- 2 * “2”
- 乘性操作符:如果有一个操作数不是数值,则在后台调用
Number()
将其转换为数值
- 乘性操作符:如果有一个操作数不是数值,则在后台调用
- [1, 2] + [2, 1]
Javascript
中所有对象基本都是先调用valueOf
方法,如果不是数值,再调用toString
方法。- 所以两个数组对象的
toString
方法相加,值为:“1,22,1”
- “a” + + “b”
- 后边的“+”将作为一元操作符,如果操作数是字符串,将调用
Number
方法将该操作数转为数值,如果操作数无法转为数值,则为NaN
。 - 所以值为:“aNaN”
- 后边的“+”将作为一元操作符,如果操作数是字符串,将调用
全局内置对象
JavaScript
中有如下内置对象:
- 数据封装类对象
String
、Array
、Object
、Boolean
、Number
- 其他对象
Math
、Date
、RegExp
、Error
、Function
、Arguments
ES6
新增对象Promise
、Map
、Set
、Symbol
、Proxy
、Reflect
以下介绍对象的一些常用方法,建议读者过一遍即可,忘了再去看看官方文档就行。
数组Array对象常用方法
修改器方法
如下方法会改变调用它们的对象自身的值
-
Array.prototype.pop()
- 删除数组最后一个元素,并返回这个元素
-
Array.prototype.push()
- 在数组的尾部增加一个或多个元素,并返回数组的新长度
-
Array.prototype.shift()
- 删除数组的第一个元素,并返回这个元素。
-
Array.prototype.unshift()
- 在数组的开头增加一个或多个元素,并返回数组的新长度。
-
Array.prototype.splice()
- 在任意的位置给数组添加或删除任意个元素。
-
Array.prototype.reverse()
- 颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个。
-
Array.prototype.sort()
- 对数组元素进行排序,并返回当前数组。
-
Array.prototype.fill()
- 将数组中指定区间的所有元素的值,都替换成某个固定的值。
-
Array.prototype.copyWithin()
- 在数组内部,将一段元素序列拷贝到另一段元素序列上,覆盖原有的值。
访问方法
下面的这些方法绝对不会改变调用它们的对象的值,只会返回一个新的数组或者返回一个其它的期望值。
-
Array.prototype.join()
- 连接所有数组元素组成一个字符串。
-
Array.prototype.slice()
- 抽取当前数组中的一段元素组合成一个新数组。
-
Array.prototype.concat()
- 返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组。
-
Array.prototype.includes()
- 判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false。
-
Array.prototype.indexOf()
- 返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。
-
Array.prototype.lastIndexOf()
- 返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。
-
Array.prototype.toSource()
- 返回一个表示当前数组字面量的字符串。遮蔽了原型链上的 Object.prototype.toSource() 方法。
-
Array.prototype.toString()
- 返回一个由所有数组元素组合而成的字符串。遮蔽了原型链上的 Object.prototype.toString() 方法。
-
Array.prototype.toLocaleString()
- 返回一个由所有数组元素组合而成的本地化后的字符串。遮蔽了原型链上的 Object.prototype.toLocaleString() 方法。
字符串常用API
-
String.prototype.split()
- 通过分离字符串成字串,将字符串对象分割成字符串数组。
-
String.prototype.slice(start, end)
- 摘取一个字符串区域,返回一个新的字符串。
-
String.prototype.substr(start, len)
- 通过指定字符数返回在指定位置开始的字符串中的字符。
-
String.prototype.substring()
- 返回在字符串中指定两个下标之间的字符。
-
String.prototype.trim()
- 从字符串的开始和结尾去除空格
-
String.prototype.concat()
- 连接两个字符串文本,并返回一个新的字符串。
-
String.prototype.match()
- 使用正则表达式与字符串相比较。
-
String.prototype.replace()
- 被用来在正则表达式和字符串直接比较,然后用新的子串来替换被匹配的子串。
-
String.prototype.search()
- 对正则表达式和指定字符串进行匹配搜索,返回第一个出现的匹配项的下标。
-
String.prototype.toString()
- 返回用字符串表示的特定对象。重写 Object.prototype.toString 方法。
DOM
DOM
事件的级别DOM
事件模型DOM
事件流DOM
事件捕获的具体流程Event
对象的常见应用- 自定义事件
DOM事件级别
DOM0
- onXXX类型的定义事件
- element.onclick = function(e) { … }
DOM2
- addEventListener方式
- element.addEventListener(‘click’, function (e) { … })
- btn.removeEventListener(‘click’, func, false)
- btn.attachEvent(“onclick”, func);
- btn.detachEvent(“onclick”, func);
DOM3
- 增加了很多事件类型
- element.addEventListener(‘keyup’, function (e) { … })
- eventUtil 是自定义对象,textInput 是 DOM3 级事件
DOM 事件模型
捕获从上到下, 冒泡从下到上。
先捕获,再到目标,再冒泡
DOM事件流
DOM标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从window对象开始,也在window对象结束。
DOM标准规定事件流包括三个阶段:
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
描述DOM事件捕获的具体流程
从window -> document -> html -> body -> … -> 目标元素
Event对象常见应用
- event.target
- 触发事件的元素
- event.currentTarget
- 绑定事件的元素
- event.preventDefault()
- 阻止默认行为
- event.cancelBubble()和event.preventBubble 都已经废弃
- event.stopPropagation()
- 阻止在捕获阶段或冒泡阶段继续传播,而不是阻止冒泡
- event.stopImmediatePropagation()
- 阻止事件冒泡并且阻止相同事件的其他侦听器被调用。
事件的代理/委托
事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件
优点:
- 可以减少事件注册,节省大量内存占用
- 可以将事件应用于动态添加的子元素上
但使用不当会造成事件在不应该触发时触发
ulEl.addEventListener('click', function(e){
var target = event.target || event.srcElement;
if(target && target.nodeName.toUpperCase() === "LI"){
console.log(target.innerHTML);
}
}, false);
自定义事件
- Event
- CustomEvent
CustomEvent不仅可以用来做自定义事件,还可以在后面跟一个object做参数
var evt = new Event('myEvent');
someDom.addEventListener('myEvent', function() {
//处理这个自定义事件
});
someDom.dispatchEvent(evt);
IE 与火狐的事件机制有什么区别? 如何阻止冒泡?
IE 只事件冒泡,不支持事件捕获;火狐同时支持件冒泡和事件捕获。
阻止冒泡:
- 取消默认操作
- w3c 的方法是 e.preventDefault()
- IE 则是使用 e.returnValue = false;
- return false
- javascript 的 return false 只会阻止默认行为
- 是用 jQuery 的话则既阻止默认行为又防止对象冒泡。
- 阻止冒泡
- w3c 的方法是 e.stopPropagation()
- IE 则是使用 e.cancelBubble = true
[js] view plaincopy
function stopHandler(event)
window.event
? window.event.cancelBubble = true
: event.stopPropagation();
}
DOM 元素的 dom.getAttribute(propName)和 dom.propName 有什么区别和联系
- dom.getAttribute(),是标准 DOM 操作文档元素属性的方法,具有通用性可在任意文档上使用,返回元素在源文件中设置的属性
- dom.propName 通常是在 HTML 文档中访问特定元素的特性,浏览器解析元素后生成对应对象(如 a 标签生成 HTMLAnchorElement),这些对象的特性会根据特定规则结合属性设置得到,对于没有对应特性的属性,只能使用 getAttribute 进行访问
- dom.getAttribute()返回值是源文件中设置的值,类型是字符串或者 null(有的实现返回"")
- dom.propName 返回值可能是字符串、布尔值、对象、undefined 等
- 大部分 attribute 与 property 是一一对应关系,修改其中一个会影响另一个,如 id,title 等属性
- 一些布尔属性
<input hidden/>
的检测设置需要 hasAttribute 和 removeAttribute 来完成,或者设置对应 property - 像
<a href="../index.html">link</a>
中 href 属性,转换成 property 的时候需要通过转换得到完整 URL - 一些 attribute 和 property 不是一一对应如:form 控件中
<input value="hello"/>
对应的是 defaultValue,修改或设置 value property 修改的是控件当前值,setAttribute 修改 value 属性不会改变 value property
JS获取dom的CSS样式
function getStyle(obj, attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
} else {
return window.getComputedStyle(obj, false)[attr];
}
}
DOM 操作——怎样添加、移除、移动、复制、创建和查找节点?
创建新节点
- createDocumentFragment() //创建一个 DOM 片段
- createElement() //创建一个具体的元素
- createTextNode() //创建一个文本节点
添加、移除、替换、插入
- appendChild()
- removeChild()
- replaceChild()
- insertBefore() //在已有的子节点前插入一个新的子节点
查找
- getElementsByTagName() //通过标签名称
- getElementsByName() // 通过元素的 Name 属性的值(IE 容错能力较强,会得到一个数组,其中包括 id 等于 name 值的)
- getElementById() //通过元素 Id,唯一性
document.write 和 innerHTML 的区别
- document.write 只能重绘整个页面
- innerHTML 可以重绘页面的一部分
Window 对象 与 document对象
window
- Window 对象表示当前浏览器的窗口,是 JavaScript 的顶级对象。
- 我们创建的所有对象、函数、变量都是 Window 对象的成员。
- Window 对象的方法和属性是在全局范围内有效的。
document
- Document 对象是 HTML 文档的根节点与所有其他节点(元素节点,文本节点,属性节点, 注释节点)
- Document 对象使我们可以通过脚本对 HTML 页面中的所有元素进行访问
- Document 对象是 Window 对象的一部分,即 window.document
IE 的事件处理和 W3C 的事件处理有哪些区别?
绑定事件
- W3C: targetEl.addEventListener(‘click’, handler, false);
- IE: targetEl.attachEvent(‘onclick’, handler);
删除事件
- W3C: targetEl.removeEventListener(‘click’, handler, false);
- IE: targetEl.detachEvent(event, handler);
事件对象
- W3C: var e = arguments.callee.caller.arguments[0]
- IE: window.event
事件目标
- W3C: e.target
- IE: window.event.srcElement
阻止事件默认行为
- W3C: e.preventDefault()
- IE: window.event.returnValue = false’
阻止事件传播
- W3C: e.stopPropagation()
- IE: window.event.cancelBubble = true
BOM
BOM
是 browser object model
的缩写,简称浏览器对象模型。主要处理浏览器窗口和框架,描述了与浏览器进行交互的方法和接口,可以对浏览器窗口进行访问和操作,譬如可以弹出新的窗口,回退历史记录,获取 url 等等
BOM 与 DOM 的关系
javascript
是通过访问BOM
对象来访问、控制、修改浏览器BOM
的window
包含了document,
因此通过window
对象的document
属性就可以访问、检索、修改文档内容与结构。document
对象又是DOM
模型的根节点。
因此, BOM
包含了 DOM
,浏览器提供出来给予访问的是 BOM
对象, 从 BOM
对象再访问到 DOM
对象, 从而 js
可以操作浏览器以及浏览器读取到的文档
BOM 对象包含哪些内容?
Window JavaScript
层级中的顶层对象, 表示浏览器窗口。Navigator
包含客户端浏览器的信息。History
包含了浏览器窗口访问过的URL
。Location
包含了当前URL
的信息。Screen
包含客户端显示屏的信息。
History 对象
History
对象包含用户(在浏览器窗口中) 访问过的 URL
方法/属性 | 描述 |
---|---|
length | 返回浏览器历史列表中的 URL 数量。 |
back() | 加载 history 列表中的前一个 URL 。 |
forward() | 加载 history 列表中的下一个 URL 。 |
go() | 加载 history 列表中的某个具体页面 |
Location 对象
Location
对象包含有关当前 URL
的信息。
属性 | 描述 |
---|---|
hash | 设置或返回从井号 (#) 开始的 URL (锚) 。 |
host | 设置或返回主机名和当前 URL 的端口号。 |
hostname | 设置或返回当前 URL 的主机名。 |
href | 设置或返回完整的 URL 。 |
pathname | 设置或返回当前 URL 的路径部分。 |
port | 设置或返回当前 URL 的端口号。 |
protocol | 设置或返回当前 URL 的协议。 |
search | 置或返回从问号 (?) 开始的 URL (查询部分) 。 |
方法 | 描述 |
---|---|
assign() | 加载新的文档。 |
reload('force') | 重新加载当前文档。参数可选,不填或填 false 则取浏览器缓存的文档 |
replace() | 用新的文档替换当前文档。 |
Window 对象
Window
对象表示一个浏览器窗口或一个框架。 在客户端 JavaScript
中, Window
对象
是全局对象,所有的表达式都在当前的环境中计算。 例如,可以只写 document
, 而
不必写 window.document
。
属性 | 描述 |
---|---|
closed | 返回窗口是否已被关闭。 |
defaultStatus | 设置或返回窗口状态栏中的默认文本。 (仅 Opera 支持) |
document | 对 Document 对象的只读引用。 请参阅 Document 对象。 |
history | 对 History 对象的只读引用。 请参数 History 对象。 |
innerHeight | 返回窗口的文档显示区的高度。 |
innerWidth | 返回窗口的文档显示区的宽度。 |
length | 设置或返回窗口中的框架数量。 |
location | 用于窗口或框架的 Location 对象。 请参阅 Location 对象。 |
name | 设置或返回窗口的名称。 |
Navigator | 对 Navigator 对象的只读引用。 请参数 Navigator 对象。 |
opener | 返回对创建此窗口的窗口的引用。 |
outerHeight | 返回窗口的外部高度。 |
outerWidth | 返回窗口的外部宽度。 |
pageXOffset | 设置或返回当前页面相对于窗口显示区左上角的 X 位置。 |
pageYOffset | 设置或返回当前页面相对于窗口显示区左上角的 Y 位置。 |
parent | 返回父窗口。 |
Screen | 对 Screen 对象的只读引用。 请参数 Screen 对象。 |
self | 返回对当前窗口的引用。 等价于 Window 属性。 |
status | 设置窗口状态栏的文本。 (默认只支持 Opera) |
top | 返回最顶层的先辈窗口。 |
window | window 属性等价于 self 属性, 它包含了对窗口自身的引用。 |
screenLeft screenTop screenX screenY | 只读整数。声明了窗口的左上角在屏幕上的的 x 坐标和 y 坐标。 IE、 Safari、 Chrome 和 Opera 支持 screenLeft 和 screenTop, 而 Chrome、 Firefox 和 Safari 支持 screenX 和 screenY。 |
方法 | 描述 |
---|---|
alert() | 显示带有一段消息和一个确认按钮的警告框。 |
blur() | 把键盘焦点从顶层窗口移开。 |
confirm() | 显示带有一段消息以及确认按钮和取消按钮的对话框。 |
createPopup() | 创建一个弹出窗口。 只有 ie 支持(不包括 ie11) |
focus() | 把键盘焦点给予一个窗口。 |
moveBy() | 可相对窗口的当前坐标把它移动指定的像素。 |
moveTo() | 把窗口的左上角移动到一个指定的坐标。 |
open() | 打开一个新的浏览器窗口或查找一个已命名的窗口。 window.open(URL,name,features,replace) |
print() | 打印当前窗口的内容。 |
prompt() | 显示可提示用户输入的对话框。 |
resizeBy() | 按照指定的像素调整窗口的大小。 |
resizeTo() | 把窗口的大小调整到指定的宽度和高度。 |
scrollBy() | 按照指定的像素值来滚动内容。 |
scrollTo() | 把内容滚动到指定的坐标。 |
setInterval() | 按照指定的周期(以毫秒计) 来调用函数或计算表达式。 |
setTimeout() | 在指定的毫秒数后调用函数或计算表达式。 |
clearInterval() | 取消由 setInterval() 设置的 timeout。 |
clearTimeout() | 取消由 setTimeout() 方法设置的 timeout。close() 关闭浏览器窗口 |
Navigator 对象
Navigator 对象包含的属性描述了正在使用的浏览器。 可以使用这些属性进行平台专用的配置。 虽然这个对象的名称显而易见的是 Netscape 的 Navigator
浏览器, 但其他实现了 JavaScript
的浏览器也支持这个对象。
属性 | 描述 |
---|---|
appCodeName | 返回浏览器的代码名。 以 Netscape 代码为基础的浏览器中, 它的值是 “Mozilla”。Microsoft 也是 |
appMinorVersion | 返回浏览器的次级版本。 (IE4、 Opera 支持) |
appName | 返回浏览器的名称。 |
appVersion | 返回浏览器的平台和版本信息。 |
browserLanguage | 返回当前浏览器的语言。 (IE 和 Opera 支持)cookieEnabled 返回指明浏览器中是否启用 cookie 的布尔值。 |
cpuClass | 返回浏览器系统的 CPU 等级。 (IE 支持) |
onLine | 返回指明系统是否处于脱机模式的布尔值。 |
platform | 返回运行浏览器的操作系统平台。 |
systemLanguage | 返回当前操作系统的默认语言。 (IE 支持) |
userAgent | 返回由客户机发送服务器的 user-agent 头部的值。 |
userLanguage | 返回操作系统设定的自然语言。 (IE 和 Opera 支持) |
plugins | 返回包含客户端安装的所有插件的数组 |
方法 | 描述 |
---|---|
javaEnabled() | 规定浏览器是否支持并启用了 Java。 |
taintEnabled() | 规定浏览器是否启用数据污点 (data tainting)。 |
Screen 对象
Screen 对象包含有关客户端显示屏幕的信息。 每个 Window 对象的 screen 属性都引用一个 Screen 对象。 Screen 对象中存放着有关显示浏览器屏幕的信息。 JavaScript 程序将利用这些信息来优化它们的输出, 以达到用户的显示要求。 例如,一个程序可以根据显示器的尺寸选择使用大图像还是使用小图像,它还可以根据显示器的颜色深度选择使用 16 位色还是使用 8 位色的图形。 另外,JavaScript 程序还能根有关屏幕尺寸的信息将新的浏览器窗口定位在屏幕中间。
属性 | 描述 |
---|---|
availHeight | 返回显示屏幕的高度 (除 Windows 任务栏之外)。 |
availWidth | 返回显示屏幕的宽度 (除 Windows 任务栏之外)。 |
bufferDepth | 设置或返回调色板的比特深度。 (仅 IE 支持)colorDepth 返回目标设备或缓冲器上的调色板的比特深度。 |
deviceXDPI | 返回显示屏幕的每英寸水平点数。 (仅 IE 支持) |
deviceYDPI | 返回显示屏幕的每英寸垂直点数。 (仅 IE 支持) |
fontSmoothingEnabled | 返回用户是否在显示控制面板中启用了字体平滑。 (仅 IE 支持) |
height | 返回显示屏幕的高度。 |
logicalXDPI | 返回显示屏幕每英寸的水平方向的常规点数。 (仅 IE 支持) |
logicalYDPI | 返回显示屏幕每英寸的垂直方向的常规点数。 (仅 IE 支持) |
pixelDepth | 返回显示屏幕的颜色分辨率(比特每像素) 。 |
updateInterval | 设置或返回屏幕的刷新率。 (仅 IE11 以下支持) |
width | 返回显示器屏幕的宽度。 |
检测浏览器版本版本有哪些方式?
- 根据 navigator.userAgent // UA.toLowerCase().indexOf(‘chrome’)
- 根据 window 对象的成员 // ‘ActiveXObject’ in window
offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别
- offsetWidth/offsetHeight 返回值包含 content + padding + border,效果与 e.getBoundingClientRect()相同
- clientWidth/clientHeight 返回值只包含 content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸
ES6
对于ES6的内容,笔者还是建议大家通读几遍阮一峰老师的ES6教程。在这篇文章中只讲述平时用的比较多的和被面试问的比较多的。
var、let和const区别
- 全局声明的var变量会挂载在window上,而let和const不会
- var声明变量存在变量提升,let和const不会
- let、const的作用范围是块级作用域,而var的作用范围是函数作用域
- 同一作用域下在let和const声明前使用会存在暂时性死区
- 不允许重复声明
- const
- 一旦声明必须赋值,不能使用null占位
- 声明后不能再修改
- 如果声明的是复合类型数据,可以修改其属性
暂时性死区
其实let/const同样也有提升的作用,但是和var的区别在于
-
var在创建时就被初始化,并且赋值为undefined
-
let/const在进入块级作用域后,会因为提升的原因先创建,但不会被初始化,直到声明语句执行的时候才被初始化,初始化的时候如果使用let声明的变量没有赋值,则会默认赋值为undefined,而const必须在初始化的时候赋值。而创建到初始化之间的代码片段就形成了暂时性死区
const
使用const关键字声明一个常量,常量的意思是不会改变的变量,const和let的一些区别是
-
const声明变量的时候必须赋值,否则会报错,同样使用const声明的变量被修改了也会报错
-
const声明变量不能改变,如果声明的是一个引用类型,则不能改变它的内存地址(可以改变它的值)
为什么日常开发中没有显式的声明块级作用域,let/const声明的变量却没有变为全局变量
可以看到使用let声明的变量x是在一个叫script作用域下的,而var声明的变量因为变量提升所以提升到了全局变量window对象中,这使我们能放心的使用新语法,不用担心污染全局的window对象
箭头函数
- 函数体内的
this
是定义时所在的对象
而不是使用时所在的对象
- 可让
this
指向固定化,这种特性很有利于封装回调函数 - 不可当作构造函数,因此箭头函数不可使用
new
命令 - 不可使用
yield
命令,因此箭头函数不能用作Generator
函数 - 不可使用
Arguments
对象,此对象在函数体内不存在(可用rest
/spread
参数代替) - 返回对象时必须在对象外面加上括号
- 普通
function
的声明在变量提升中是最高的,箭头函数没有函数提升
Promise
Promise
需要一些参数,这里需要一个函数(我们叫它执行器)作为参数,该函数有两个参数————resolve
和reject
,这两个参数也是函数(由js
引擎提供),我们可以在Promise
内部调用,当异步操作成功时,调用resolve
,否则reject
。
let p =new Promise(function(resolve, reject){
if(/* 异步操作成功 */){
resolve(data)
}else{
reject(err)
}
})
state
Promise
是有“状态”的,分别是pending
(等待态)、fulfilled
(成功态)、rejected
(失败态),pending
可以转换为fulfilled
或rejected
,但fulfilled
和rejected
不可相互转化。
resolve
/reject
方法
resolve
方法可以将pending
转为fulfilled
reject
方法可以将pending
转为rejected
。
then
方法
通过给Promise
示例上的then
方法传递两个函数作为参数,可以提供改变状态时的回调,第一个函数是成功的回调,第二个则是失败的回调。
p.then(function(data){ // resolve方法会将参数传进成功的回调
console.log(data)
}, function(err){ // reject方法会将失败的信息传进失败的回调
console.log(err)
})
例子:
let p = new Promise(function(resolve, reject){
setTimeout(function(){
let num = Math.random()
if (num > 0.5) {
resolve(num)
}else{
reject(num)
}
}, 1000)
})
p.then(function(num){
console.log('大于0.5的数字:', num)
},function(num){
console.log('小于等于0.5的数字', num)
})
// 运行第一次:小于等于0.5的数字 0.166162996031475
// 运行第二次:大于0.5的数字: 0.6591451548308984
...
链式调用
除此之外,每一个then
方法都会返回一个新的Promise
实例(不是原来那个),让then
方法支持链式调用,并可以通过返回值将参数传递给下一个then
p.then(function(num){
return num
},function(num){
return num
}).then(function(num){
console.log('大于0.5的数字:', num)
},function(num){
console.log('小于等于0.5的数字', num)
})
catch
catch
方法等同于.then(null, reject)
,可以直接指定失败的回调(支持接收上一个then
发生的错误)
Promise.all
统一处理多个Promise
,Promise.all
能将多个Promise
实例包装成一个Promise
实例
let Promise1 = new Promise(function(resolve, reject){})
let Promise2 = new Promise(function(resolve, reject){})
let Promise3 = new Promise(function(resolve, reject){})
let p = Promise.all([Promise1, Promise2, Promise3])
p.then(function(){
// 三个都成功则成功
}, function(){
// 只要有失败,则失败
})
这个组合后的Promise
实例和普通实例一样,有三种状态,这里有组成它的几个小Promise
的状态决定
- 当
Promise1
,Promise2
,Promise3
的状态都为成功态,则p
为成功态; - 当
Promise1
,Promise2
,Promise3
中有任意一个为失败态,则p
为失败态;
Promise.race()
与all
方法类似,也可以将多个Promise
实例包装成一个新的Promise
实例
不同的是,all
时大Promise
的状态由多个小Promise
共同决定,而race时由第一个转变状态的小Promise的状态决定,第一个是成功态,则转成功态,第一个失败态,则转失败态
Promise.resolve()
可以生成一个成功的Promise
Promise.resolve('成功')
等同于new Promise(function(resolve){resolve('成功')})
Promise.reject()
可以生成一个失败的Promise
Promise.reject('出错了')
等同于new Promise((resolve, reject) => reject('出错了'))
Set、Map、WeakSet 和 WeakMap 的区别?
Set
- 表示有没有,成员的值都是唯一的,没有重复的值
- 可以接受一个数组(或可迭代的数据结构)作为参数
- 注:两个对象总是不相等的
属性:
- Set.prototype.constructor:构造函数,默认就是Set函数。
- Set.prototype.size:返回Set实例的成员总数。
方法:
- add(value):添加某个值,返回 Set 结构本身。
s.add(1).add(2).add(2)
;
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
遍历方法
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回键值对的遍历器
- forEach():使用回调函数遍历每个成员
WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。但与 Set 有几个区别:
- WeakSet 的成员只能是对象,而不能是其他类型的值
- WeakSet 中的对象都是弱引用
- 如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存
- 垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。
- WeakSet 不可遍历
- 由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的
- WeakSet 结构中没有clear方法。
Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作Map的键。
遍历方法
Map 结构原生提供三个遍历器生成函数和一个遍历方法。
- keys():返回键名的遍历器。
- values():返回键值的遍历器。
- entries():返回所有成员的遍历器。
- forEach():遍历 Map 的所有成员。
WeakMap
WeakMap
的设计目的在于: 有时我们想在某个对象上面存放一些数据,但是这会形成对于这个对象的引用,而一旦不再需要这两个对象,我们就必须手动删除这个引用,否则垃圾回收机制就不会释放被引用对象占用的内存。
基本上,如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap
。
一个典型应用场景是,在网页的 DOM
元素上添加数据,就可以使用 WeakMap
结构。当该 DOM
元素被清除,其所对应的 WeakMap
记录就会自动被移除。
涉及到的模块化、Class继承、异步编程等知识我们下篇再做阐述,其余的由于篇幅有限,且 ES6
篇幅太大,网上也有总结的文章,看网上的文章或者看阮一峰老师的文档都可~
最后
行文至此,感谢阅读,一键三连是对我最大的支持。