js暂时性死区
在ES6中新增的定义变量的关键字let和const
,会带来一个暂时性死区的问题,暂时性死区简单来讲就是变量未定义就调用了。在ES6中let
和const
定义变量是没有变量提升这一功能的。所以才会造成暂时性死区这个问题。
在ES5中定义变量的关键字var
会将变量名称全部提升到代码最前面将变量名进行行定义,再进行赋值。
// 相当于将一行定义变量的代码分成了两行执行
var a = 1;
↓
var a; // 在js的最顶部
a = 1;
let和const的区别
let
是定义变量的,而const
是定义常量的。
cosnt
定义的常量如果是基本类型,值是不可以改变的。如果定义的是引用类型,那么引用类型中的值是看以改变的,只要堆地址不改变就行。
那么这里又涉及到了堆和栈。堆和栈其实只是内存存储数据的一个地方。
堆:一般用来存储引用数据类型的值。
栈:一般用来存储基本数据类型的变量名和值,引用类型的变量名和堆地址。
所以说const定义的常量的值是存在堆中的,而改变存储的值是可以的,但是栈中存储的堆地址却不会改变
bom包含哪些对象
navigator
包含有关浏览器的信息
localtion
Location 对象包含有关当前 URL 的信息。
screen
Screen 对象包含有关客户端显示屏幕的信息。
history
History 对象包含用户(在浏览器窗口中)访问过的 URL。
window
Window 对象表示浏览器中打开的窗口。
数组方法
concat
链接两个数组,返回值是合并后的数组,该方法不改变原数组
indexOf
检索数组中的某个值,如果这个值存在则返回这个值的索引,如果不存在的返回-1
lastIndexOf
从尾部检索数组中的某个值,如果这个值存在返回这个值的索引,不存在则返回-1
every
判断数组中的每一项是否符合条件,如果符合条件则返回true,否则返回false
some
判断数组中是否有符合条件的项,如果有则返回true,若没有则返回false
join
将数组中的每一项通过一个字符进行链接成一个字符串
pop
删除数组的最后一个元素,并返回该元素,此方法会改变原来的数组
shift
删除数组的第一个元素,并返回该元素,此方法会改变原来的数组
push
在数组的尾部添加一个元素,或多个元素,并返回新数组的长度,该方法会改变原数组
sort
数组排序,通过传入一个回调函数进行数组排序,此方法会修改原数组
reverse
反转数组,将数组进行颠倒过来,此方 法会改变原数组
slice
截取数组,传入两个参数一个是起始位置一个是结束位置,此方法不改变原数组,返回值是截取的数组
unshift
在数组的头部添加一个或多个元素,并返回新数组的长度,该方法会改变原数组
splice
截取数组,传入两个参数第一个是起始位置,第二个是数量,返回值是截取的数组,此方法改变原数组
split
将字符串根据某个特定的字符转化成数组。
forEach
遍历数组,将数组循环一遍。
map
映射数组,传入一个回调函数,并写入生成条件,生成对应条件的新数组,并返回这个新数组,此方法不改变原数组
filter
过滤数组,传入一个回调函数,写入筛选条件,返回一个满足条件的数组,此方法不改变原数组
reduce
迭代将数组中的每一项合并,最终计算出一个总值,返回出去
findIndex
查找某个元素的索引
flat
将多维数组转成一维数组。参数可以为数字,可以不传,同样也可以传为Infinity表示不管多少层嵌套均可转化成一维数组
flatMap
对原数组的每一个成员执行一个函数并返回一个新数组并且函数的执行结果均会跟在每一个成员后面
fill
使用制定的元素填充数组,其实就是用默认内容初始化数组。
Includes
函数判断是否包含某一元素,不能定位,它直接返回true或者false表示是否包含元素,对NaN一样能有有效。
静态方法
Array.isArray
判断是否是一个数组,是则返回true,否则返回false
Array.from
将一个类数组对象或者可遍历对象转换成一个真正的数组。
Array.of
将一系列值转换成一个数组
对象方法
Object.is
判断是否全等
Object.assign
浅复制
Object.keys
方法会返回一个由一个给定对象的自身可枚举属性名组成的数组。
Object.values
方法会返回一个由一个给定对象的自身可枚举属性的值组成的数组。
Object.entries
方法会返回一个由一个给定对象的自身可枚举的键值对组成的二维数组。
数值的扩展
Number.parseInt
将parseInt方法添加到了Number对象上,调用方式不变
Number.parseFloat
同上
Number.isNaN
同上
Number.isInteger
判断一个数是不是一个整数
Math.sign
判断一个数的正负 正数返回1负数返回-1
Math.trunc()
取整
Math.cbrt
开立方根
Math.sqrt
开平方根
字符串的扩展
${}
模板字符串
Includes
返回布尔值,表示是否找到了参数字符串。
startsWith
返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith
返回布尔值,表示参数字符串是否在原字符串的尾部。
Repeat
参数值为介于0和正无穷大之间的整数 : [0, +∞) 。表示在新构造的字符串中重复了多少遍原字符串。
扩展运算符/...运算符
数组和对象
可以复制对象和数组
合并对象和数组
解构对象和数组
数组
将类数组转成真数组
将字符串转为字符数组
对象
将数组转换成对象
对象转成数组: Array.keys()
Array.from
转换
对象转数组必须每一项的键都是数字,并且必须是连续的,必须有length属性
新增数据类型
Set:
概念:
似于数组,但它的一大特性就是所有元素都是唯一的,没有重复。
我们可以利用这一唯一特性进行数组的去重工作。
数组去重实例:
let set6 = new Set([1, 2, 2, 3, 4, 3, 5])
console.log('distinct 1:', set6)
添加元素:
Set.add(val)
删除元素:
Set.delete(val)
判断元素是否存在:
Set.has(val)
清除所有元素:
Set.clear()
数组转set:
New Set(arr);
Set转数组:
[…Set]
可以使用Set实例对象的keys()
,values()
,entries()
方法进行遍历。
Set
的键名和键值是同一个值,它的每一个元素的key
和value
是相同的,所有keys()
和values()
的返回值是相同的,entries()
返回的元素中的key
和value
是相同的。
在向Set加入值时,Set不会转换数据类型,内部在判断元素是否存在时用的类似于精确等于(===)的方法,“2”和2是不同的,NaN等于其自身。
WeakSet:
概念:
WeakSet和Set类似,同样是元素不重复的集合,它们的区别是WeakSet内的元素必须是对象,不能是其它类型。
特点:
1.元素必须是对象。
2.弱引用,不被计入垃圾回收
添加进WeakSet的元素对象,WeakSet不会对元素对像的引用计数加1,对于被添加进WeakSet的元素对象,只要该元素对象没有被除WeakSet以外的其他对象引用,就会被垃圾回收释放,在WeakSet中的该元素对象自动被释放,不会出现内存泄漏。
因为这一特性,其性能要比map要高,对于存储无顺序要求的,不重复的,临时存储的场景,可以使用它。
例子:
const ws = new WeakSet()
var a = {p1:'1', p2:'2'}
ws.add(a)
a = null
console.log(ws.has(a));
先将对象添加到WeakSet中,然后将对象设成null,然后再下面的has方法判定时,结果显示,表示WeakSet中已经不存在该对象。
3.不能遍历
因为其对内部的元素对象是弱引用,随时会被垃圾回收释放掉,所以其不支持size和forEach等遍历方法。
Map:
概念:
Javascript的Object本身就是键值对的数据结构,但实际上属性和值构成的是”字符串-值“对,属性只能是字符串,如果传个对象字面量作为属性名,那么会默认把对象转换成字符串,结果这个属性名就变成"[object Object]"
。
ES6提供了"值-值"
对的数据结构,键名不仅可以是字符串,也可以是对象。它是一个更完善的Hash结构。
使用:
设置值:
Map.set(key,val)
获取值:
Map.get(key)
获取map的大小:
Map.size
判断是否存在:
Map.has(key)
删除键值对:
Map.delete(key)
清空map对象:
Map.clear()
Map也可以对set进行链式调用,同样可以使用for of 循环,也可以使用object的keys,values,entries的方法,forEach遍历同样可以使用
Symbol:
Symbol,是一种数据类型。在定义时直接调用即可。
例如:
Var sy = Symbol();
唯一性,通常用作对象的键,永不重复。
深拷贝与浅拷贝
浅复制
object.assign({},obj)
把一个对象克隆一份给另一个对象,只能把元对象的基本数据类型克隆一份,引用类型克隆不了,
也就是说克隆后的对象改变了引用类型的数值,同时也会改变原对象的属性值
深拷贝
原对象的属性值无论是基本类型还是引用类型都是复制给新对象的,任何属性值之间不存在引用关系,也就是复制后的对象改变其中任何一个属性值都不会影响原对象
JSON.parse(JSON.stringify())配合使用
...复制对象
...也可以展开对象
let obj2 = {...obj}
数组合并
Object.assign({},obj1,obj2)
或者是
let obj = {...obj1,...obj2}
解构对象
let obj = {x:1,y:1,z:3}
let {x,y,...z}=obj
数组转对象
let obj = {...[1,2,3,5,9,8]}
数组的每一个下标作为对象的建,
数组的每一个值作为对象的值
异步函数
概念
也叫async函数,解决异步嵌套的问题,异步函数是生成器函数的高级语法糖,也就是生成器函数的高级封装,比生成器函数更好用,一般使用异步函数配合Promise是最佳的消除异步嵌套的方案
语法:
在函数声明的时候添加一个async关键字,表明该函数是异步函数
async关键字是添加在function关键字前面
特性:
1.异步函数调用函数名,会立即执行函数的函数体
2.异步函数默认返回一个异步函数
如果想要获取return后面的值需要通过返回值`.then(result=>{
})`
或者通过过`Promise.resolve`取值
Promise.resolve(返回值).then( result =>{
})
不能通过返回值['[[PromiseValue]]']取值,这样取出来的值是undefined
3.async经常配合await关键字使用
await是个关键字 只能和异步函数配合使用
也就是await只能出现在异步函数中,否则会报错
await 表示 等待的意思
await 后面可以跟一个具体的数值或一个Promise实例或一个异步函数
异步函数里面的代码会按照同步的方式执行
闭包
ES5闭包:
两个函数嵌套,内(子)函数使用了,外(父)函数的变量或者参数,导致这个变量或者函数参数被保留了袭来,延长了变量或函数参数的使用周期,从而导致这个变量或者函数或者参数被内(子)函数去使用
ES6闭包:
两个作用域嵌套,内(子)作用域使用了,外(父)作用域的变量或者参数,导致这个变量或者参数被保留了袭来,延长了变量或参数的使用周期,从而导致这个变量或者参数被内(子)作用域去使用
Promise消除回调地狱
方法一:
/*需要借助Promise来消除回调嵌套 链式调用*/
let promiseAjax = function(json) {
return new Promise((resolve, reject) => {
$.ajax({
url: json.url,
dataType: json.dataType,
type: 'json',
success(data) {
resolve(data);
},
error(err) {
reject(err);
}
})
})
}
promiseAjax({
url: '1.json',
type: 'get',
dataType: 'json',
}).then(data => {
console.log(data);
}).catch(erro => {
})
方法二:
/* 当所有的异步全部成功之后才会执行then,只要有一个异步执行失败,就会执行catch all([promise,....]).then(allData = >{}).catch(err =>{}) */
let promiseAjax = url => {
return new Promise((resolve, reject) => {
$.ajax({
url,
dataType: 'json',
success(data) {
resolve(data)
},
error(err) {
reject(err)
}
})
})
}
let p1 = promiseAjax('1.json');
let p2 = promiseAjax('2.json');
Promise.all([p1, p2]).then(resolve => {
console.log(resolve)
})
//jQuery3.X版本之后ajax方法中会自动返回一个Promise对象
Export 和 export default的区别
- export与export default均可用于导出常量、函数、文件、模块等
- 在一个文件或模块中,export、import可以有多个,export default仅有一个
- 通过export方式导出,在导入时要加{ },export default则不需要
- 输出单个值,使用export default
- 输出多个值,使用export
- export default与普通的export不要同时使用
Export 和 module.export的区别
通常exports方式使用方法是:
exports.[function name] = [function name]
moudle.exports方式使用方法是:
moudle.exports= [function name]
这样使用两者根本区别是
exports 返回的是模块函数
module.exports 返回的是模块对象本身,返回的是一个类
使用上的区别是
exports的方法可以直接调用
module.exports需要new对象之后才可以调用
面向对象的继承
ES6继承
Class A extends B{
Constructor(){
Super();
}
方法名(){
Super.方法名();
}
}
ES5继承
// 原型链式继承
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
}
function SubType() {
this.subpropertype = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
return this.subpropertype;
}
var ins = new SubType();
console.log(ins.subpropertype);//false
console.log(ins.getSuperValue());//true
//构造函数式继承
function SuperType(){
this.color=['1','2','3','4'];
}
function SubType(){
SuperType.call(this);
}
var ins1=new SubType();
ins1.color.pop()
console.log(ins1.color);//[1,2,3]
var ins2=new SubType()
ins2.color.push('5');
console.log(ins2.color);//[1,2,3,4,5]
优点:可以在子类型构造函数中向超类型构造函数传递参数
缺点:在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能ES6的新特性
Function Parent (){
}
Parent.prototype=function fn(){
}
Function Child(){
Parent.apply(this,arguments)
}
New关键字的作用
// 因为JS中,对象都是new 对应的函数()创建出来的,
// new 关键字对函数的影响(new关键字到底做了什么):
// 1.在该函数内部创建一个对象
// 2.函数内部的this指向创建出来的的这个对象
// 3.对象的proto指向函数的prototype
// 4. 函数默认返回该对象
作用域链和原型链
作用域链
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain,不简称sc)来保证对执行环境有权访问的变量和函数的有序访问。
简单来说外面的不能访问作用域里定义的变量,作用域里定义的变量可以访问上级作用域的变量。
原型链
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。原型链的末尾就是Object对象。
防抖节流
防抖节流其实简单来说就是限制请求和函数的执行频率,让其在非常短的时间内达到只执行一次的目的,避免重复操作来浪费资源。
常见的就是使用定时器和时间戳来进行一个处理。
网友评论