前言
本文主要摘录《js高级程序设计》,也就是我们常说的红宝书,其中一些比较少见的知识点,处理技巧。
知识点列表
理解内存回收机制要点 (gc)
- 浏览器的gc机制并不是实时回收的,而是定时回收的,只是间隔时间很短。
- 回收的原理是:每次去检查定义好的变量包括基本变量以及函数、对象,如果发现未被引用,就会回收。
- 手动回收内存:当你不需要某变量时,从优化内存的角度,可以将其定义为null
- 当你定义一个定时器或者逻辑死循环时,这部分是非常耗费内存的,甚至会导致页面崩溃,需要尽量避免
为什么说eval是性能低下的
因为默认的js是运行于浏览器的,而且其是在浏览器端编译后运行的,而不是和java一样编译好之后直接用class文件,所以为了解决这个性,我们只要处理自己时区的时间就可以,数据库存取的也是固定的一种时间,但是有些时候前端在读取以及新建今天或者某些非精准日期对象的时候,会因为数据库时间与当前客户端时间不一致导致各种问题。那么在解决这个问题之前,我们需要先了解下如何获取当前时间的时区。
.getTimezoneOffset()能问题,js的解析器会进行语法优化,包括对你的词法分析,逻辑分析等,然后会进行一些优化,包括我们熟知的变量申明提前、重复语法声明等。
而eval我们知道的是会自己创建解析环境,所以js解析器不会对其进行解析优化,所以其是低效的。
document.domain
- domain 属性可返回下载当前文档的服务器域名,domain 属性可以解决因同源安全策略带来的不同文档的属性共享问题。
- domain只能设置为其当前域名或者其父级域名,不能设置为子级域名
函数参数是为了使用方便
我们知道一般定义函数的时候都会定义几个函数需要的形参,然后就在函数体内部就可以使用这个参数。但是呢,可能大多数人并不知道,即使我们不写形参,也可以通过arguments[index]的方式拿到对应位置的参数,如果这个参数没有传入,那么直接调用,其会是undefined.比如我们写一个加法函数:
function add(){
}
时间对象的时区问题
一般情况下,我们只要处理自己时区的时间就可以,数据库存取的也是固定的一种时间,但是有些时候前端在读取以及新建今天或者某些非精准日期对象的时候,会因为数据库时间与当前客户端时间不一致导致各种问题。那么在解决这个问题之前,我们需要先了解下如何获取当前时间的时区。
date.getTimezoneOffset()/60,这个函数会返回当前时区的一个整形数字,然后我们可以根据当前的时间,以及数据库的时区,做转换以及对应关系,避免时区误差。
作为常识,大家要知道北京的时区是-8区,那么对应的策略是什么呢? 首先,对应的问题有哪些呢? 1 产品需要确定数据库存储的时间时区是否是服务器所在时区的,还是存储的是用户所在时区的。如果是,又该如何显示,如何给用户解释这种时区误差。 2 用户端在新建或者操作时间的时候,是否在源头控制时间,控制的话,让其输入的是本地时间还是服务器时间。 3 服务器以及用户端对应的时区辨别要正确,精准,如果出现误差,其误差策略是什么。
String 的substring()与substr() 方法区别
一般情况下,我们很少会用到substr的方法,但是作为常识还是要清楚的知道两个的用途以及区别。
substring(index1,index2) 可以得到从第一个指针到第二个指针的截取字符串,如果第二个比第一个小,两个指针会换顺序,如果第二个是负数,其会换成0,然后和前面的换位置。(不包括尾指针;如果超出尾部指针,最多截取到尾部)
而subbstr(index,num)指的是从某个指针开始截取num的字符串。如果num为负数,肯定不返回的。
Array的sort匿名方法
一般情况下数组的简单排序我们可以通过默认的sort无参方法直接排序(如果省略,则根据每个元素的字符串转换,根据每个字符的Unicode代码点值对数组进行排序。),但是有时候如果我们想排序的内容 是字符串性质的数字和数字都有的,其会按照字母的编码排序,从而不能得到我们想要的结果。这个适合就需要在sort方法里,传入我们需要的排序函数。
比如数组的从大到小(内容是数字或者数字的字符串),那么我们的sort匿名函数是这样写的:
let arr = ['30',15,'100','92']
let arr2 = arr.sort(function(a,b){
return a-b
})
console.log(arr2)//从小到大排序
//如果我们希望是其他的排序规则 比如说偶数在前 奇数在后
其中排序的具体规则是这样的:
如果compareFunction(a, b)小于0,则排序a到低于的索引b,即排a在第一位。 如果compareFunction(a, b)返回0,离开a,并b相对于彼此不变,但对于所有不同的元素进行排序。注意:ECMAscript标准不保证这种行为,因此并非所有浏览器(例如,至少可以追溯到2003年的Mozilla版本)都尊重这一点。 如果compareFunction(a, b)大于0,则排序b到低于的索引a,即b先到达。 compareFunction(a, b)当给定一对特定的元素a和b作为其两个参数时,必须始终返回相同的值。如果返回不一致的结果,那么排序顺序是未定义的。
再写一个案例 ,按照字符串的长短
let arr = ['30',15,'100','92']
let arr2 = arr.sort(function(a,b){
let len = a.toString().length-b.toString().length
if(len=0){
return len
}else {
return a-b
}
})
console.log(arr2)//字符串长度排序,从短到长;一样长度的用大小排序
备注与拓展:在自定义函数中可以随便定义自己想要的排序规则,包括自己想对比的是属性还是方法,对比的原则是什么,都可以进行排序,这比我们进行自己写方法然后再空数组中push我们排序的部分要简洁、专业。
switch 执行逻辑
作为常识,大家都知道switch作为分支语句,其每个条件的运行结果是不一样的,并且在每个执行条件之后,都会写break,以提高代码的执行效率,那么如果没有break,程序会如何执行呢?我们写个例子测试下。
其执行结果也许稍微和我们想的有点差异,首先其没有执行case 1的可以理解,但是不能理解的也许是其虽然不符合case 3,但是会执行其之后的switch分支语句的。
let switchFn = function(i) {
let result = 0 ;
switch(i){
case 1 :result = result + i;
case 2 :result = result + 2*i;
case 3 :result = result + 3*i;
}
return result
}
console.log(switchFn(2))//10
数组fill方法
在开发当中经常会遇到将某些数组的值进行初始化,一般我们是建立一个空数组,然后手动复制粘贴若干一样的值,或者将其用循环若干次push实现,如今有fill方法可以实现我们这样的需求。
你以前可能是这样写的:
let arr = [
{
imgUrl: '',
categoryName: '',
groupId: ''
},
{
imgUrl: '',
categoryName: '',
groupId: ''
},
...
]
语法内容:arr.fill(value[, start[, end]])
如果我们需要实现一个长度为3的空数组,里面存放的均为obj :{url:'',size:200},那么这样写即可。
let imgArr = Array(3).fill({url:'',size:200})
那么需要提醒大家的是:
-
默认的新建数组如果不填充任何值,其填充的为empty ,用map进行赋值的时候导致无法赋值,所以如果你一定要用这个的话,需要用apply方法传入null在进行。 Array.apply(null, Array(2)).map(()=>4)
-
fill还可以支持指定位置的填充,其是半封闭,如果不填尾部结束,那么默认的填充到尾部,不包括尾部指针。
-
如果你填充的是非基础数据类型的数据,那么建议使用
Array.apply(null, Array(2)).map(()=>Object.assign({},obj)),这样就不会被影响。
为什么基本的数据类型变量具有相应的方法和属性可以使用
知识储备:
- 作为常识我们知道js的数据类型是5+1,其中5个基础数据类型是null,undefined,string,boolean,number,和一个复杂类型,object,用typeof 就可以返回对应的基础类型。
- 对于基本的数据类型除了null和undefined,存在3个封装对象,分别是String,Number,Boolean.
- 变量本身肯定不能调用方法,但是对象是有对应的属性以及方法的
- js解释器在执行的时候会逐行代码分析,当其解析到.或者 []的时候,会认为其是一个对象,然后调用其对象的属性和方法
那么重点来了,当发现其不是对象类型的时候,是怎么操作的呢?当然是基于变量包装一个对象然后使用这个包装对象的属性和方法,在使用后马上销毁。
对于第一点,我们代码书写中就已经体会到了,比如可以直接针对字符串用字符串的方法,比如分割,长度,查找等,对数字可以使用toFiexed,上下取整等。那么即时的创建和销毁怎么理解呢?我们可以用下面的代码验证下。
let str = 'abc'
str.length = 1000
console.log(str.length)//这里还是3
//解析:虽然你在上一行修改了这个变量的属性,但之后还会再次封装这个变量的临时对象,然后得到其长度为3