1.如何安全的获取undefined
因为undefined是一个标识符,所以可以当作变量赋值,但会影响undefined的判断
1.通过void 0 来获取undefined
let a = void 0
console.log(a == undefined);//true
注:无论void
后的表达式是什么,都会返回undefined
2.传入一个为赋值的形参
function(_undefined){
//函数体中不给_undefined赋值,形参_undefined的值就是undefined,在这个函数用就可以使用_undefined
}
2.如何将js脚本文件延后执行
1.defer /async属性
在script标签中添加该属性
<script defer/async></script>
defer:js脚本会延迟到整个页面解析完毕再执行、只适用于外部脚本文件
async:不让页面等待脚本下载和执行,从而异步加载页面其他内容,只适用于外部脚本文件
缺点:不能保证加载的顺序
2.让js文件最后加载
将脚本元素放在文档体的底端(</body>标签前面),只有在所有HTML DOM加载完成后才开始脚本的加载/解析过程,会带来性能消耗
3.setTimeout延时加载
4.动态创建dom
5.jquery的getScript()方法
getScript() 方法通过 HTTP GET 请求载入并执行 JavaScript 文件。
语法:jQuery.getScript(url,success(response,status))
3.css的优化及性能提升
1.内联首屏关键CSS
2.异步加载CSS
使用javascript将link标签插到head标签最后
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
3.通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。加载完成之后,将rel设回stylesheet
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
4.资源压缩
利用webpack
、gulp/grunt
、rollup
等模块化工具,将css
代码进行压缩,使文件变小
5.合理使用选择器
6.不要使用@import
4.js如何避免回流与重绘
基本概念
重绘:当页面元素样式改变不影响元素在文档流中的位置时(如background-color,border-color,visibility),浏览器只会将新样式赋予元素并进行重新绘制操作。
回流:当渲染树render tree中的一部分或全部因为元素的规模尺寸、布局、隐藏等改变时,浏览器重新渲染部分DOM或全部DOM的过程
回流必将引起重绘,而重绘不一定会引起回流。
方式:
- 避免使用table布局。
- 尽可能在DOM树的最末端改变class。
- 避免设置多层内联样式。
- 将动画效果应用到position属性为absolute或fixed的元素上
- 避免使用CSS表达式(例如:calc())
- CSS3硬件加速(GPU加速)
5.vue代码编写可以做哪些性能优化
函数型组件------在模板上声明functional
属性
子组件拆分--------将复杂的耗时计算处理放在子组件中进行处理
局部变量
活用v-show,减少v-if -------对于需要频繁切换的视图来说,使用v-show
比v-if
更加节约性能,因为v-show
可以避免dom节点的销毁和重建
使用keep-alive --------保留组件状态并且避免重新渲染。
活用延迟加载(defer)
分批处理 (time slicing)
非响应式模式 (non-reactive)
6.js深拷贝与浅拷贝
浅拷贝:复制一个对象的地址,没有开辟新的栈,则两个对象共用一个地址,默认情况下,引用类型(object)都是浅拷贝,修改任意属性值,两个对象属性都会发生改变
深拷贝:开辟新的栈,两个对象获得两个新的地址,修改一个对象属性另一个不会变化
数组实现深拷贝
let box = list.slice();//方案一
let box = [].concat(list); //方案二
let box = [...list];//方案三
let box = Array.from(list);//方案四
Object.assign() // Object.assign({},Obj)得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的
对象实现深拷贝
1.使用 JSON.stringify
用 JSON.stringify
把对象转换成字符串,再用JSON.parse
把字符串转换成新的对象
如 let A = JSON.parse(JSON.stringify(B)
)
注: 对象中含有function 或 RegExp 则不能使用该方法
2.lodash.cloneDeep()
实现深拷贝
3.递归遍历所有层级,实现深拷贝
利用for ... in 获取oldobj中的属性值,赋值给item , 再判断是否为数组,如果为数组,则在调用该函数重新获取值,直到遍历完所有对象或数组
// 1. 使用递归的方式实现深拷贝
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组(首先判断数组是因为数组也属于对象)
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item);
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item);
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
};
deepCopy(o, obj);
o.msg.age = 20;
console.log(o);
console.log(obj); // obj.msg.age 还是等于 18 没有改变
var arr = [];
console.log(arr instanceof Object); // true 数组也是对象