1. 图片优化(懒加载/预加载)
1、使用base_64编码图片或SVG图片代替原始的png与jpeg图片,再像素要求不高的情况下使用jpeg图片代替png图片
2、图片懒加载,在页面上的未可视区域可以添加一个滚动条事件,判断图片位置与浏览器顶端 的距离与页面的距离,如果前者小于后者,优先加载。
- 原生JavaScript实现图片的懒加载
- jQuery插件 jquery.lazy
- vue中使用 vue-lazyload
- mint-ui 插件内置懒加载组件
3、图片的预加载,如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先 下载。初始化的时候获得图片的src之后为每一个元素提前添加图片的地址路径。保证再第二张图片显示的时候已经加载到页面当中
实现方法:循环图片数据,实例化对象的方式创建图片元素 new image() 动态绑定每一个image的src属性,并追加到DOM流中
2.数据类型种类
-
JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。
-
基本类型有六种: null,undefined,boolean,number,string,symbol。
-
对象(Object)是引用类型,在使用过程中会遇到浅拷贝和深拷贝的问题。
let a = { name: 'FE' }
let b = a
b.name = 'EF'
console.log(a.name) // EF
3、typeof
-
typeof 对于基本类型,除了 null 都可以显示正确的类型
-
想获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)
4、 new 操作符的作用
- 新生成了一个对象
- 链接到原型
- 绑定this
- 返回新对象
function create() {
// 创建一个空的对象
let obj = new Object()
// 获得构造函数
let Con = [].shift.call(arguments)
// 链接到原型
obj.__proto__ = Con.prototype
// 绑定 this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result === 'object' ? result : obj
}
5、instanceof操作符
判断对象属于某一个类,回去查找对象的constructor的prototype
6、this 环境上下文对象
function foo() {
console.log(this.a)
}
var a = 1
foo()
var obj = {
a: 2,
foo: foo
}
obj.foo()
以上两者情况 this
只依赖于调用函数前的对象,优先级是第二个情况大于第一个情况
以下情况是优先级最高的,this
只会绑定在 c
上,不会被任何方式修改 this
指向
var c = new foo()
c.a = 3
console.log(c.a)
还有种就是利用 call,apply,bind 改变 this,这个优先级仅次于 new
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())
箭头函数其实是没有 this 的,这个函数中的 this 只取决于他外面的第一个不是箭头函数的函数的 this。在这个例子中,因为调用 a 符合前面代码中的第一个情况,所以 this 是 window。并且 this 一旦绑定了上下文,就不会被任何代码改变
7.作用域/作用域链
1、作用域
-
种类:JS中有三种作用域,全局作用域,函数作用域,ES6新推出块级作用域
-
概念:一个变量的可访问规则,再函数创建的时候就已经定义好作用域,整个的JS文件执行有一个最外层的全局作用域(window)
-
使用: 本作用域内部的所有变量都可已再本作用域内部访问,外部无法访问。内部可访问上级作用域变量,本作用于内部所用使用var声明的变量会有一个作用域提升的过程,let与const声明的变量没有变量提升
2、作用域链
-
一个变量的访问规则的链式操作
-
可以把它理解成包含自身变量对象和上级变量对象的列表,通过 [[Scope]] 属性查找上级变量
-
当访问一个变量的时候,先在本作用域内部进行查找,如果没有去上级作用域进行查找,直到全局作用域window下面,都没有,返回undefined
8.闭包(closure)
1、特点:
-
内层作用域可以访问外层作用域的变量
-
闭包就是能够读取其他函数内部变量的函数
-
函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。
-
闭包函数引用的变量是存储在堆上的,所以说,当闭包函数弹出调用栈之后,闭包返回的函数依然能调用到闭包函数的变量
2、优点:
-
使用闭包可以形成独立的空间,延长变量的生命周期,保存中间状态值
-
可以封装一些私有变量,外部无法进行直接访问(例如用户登陆状态计数器)创建立即执行函数(闭包)实现JS模块化封装
-
解决var声明的循环语句变量无法长久保存的问题
3、缺点:
-
滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都 永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数,将不再使用的闭包引用设置为null;
-
由于函数内部的变量都被保存在内存中, 会导致内存消耗大;
4、相关代码:
for ( var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
// 每次循环都会输出 5 无法保存变量
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
}
// 创建立即执行函数,形成闭包,保存每一次循环的变量
// 解决下列调用打印每次都是5的问题
var arr = []
for (var i = 0; i < 5; i++) {
arr.push(function() { console.log(i) })
}
// 使用闭包的方式
for (var i = 0; i < 5; i++) {
(function(i) {
arr.push(function() {
console.log(i)
})
})(i)
}
// 使用ES6的let创建块级作用域
for (let i = 0; i < 5; i++) {
arr.push(function() {
console.log(i)
})
}
// 使用setTimeout的第三个参数
for (let i = 0; i < 5; i++) {
setTimeout(function() {
arr.push(function() {
console.log(i)
})
}, 0,i)
}