JavaScript 基础面试题(1)

1. 图片优化(懒加载/预加载)

一、使用base_64编码图片或SVG图片代替原始的png与jpeg图片,再像素要求不高的状况下使用jpeg图片代替png图片vue

二、图片懒加载,在页面上的未可视区域能够添加一个滚动条事件,判断图片位置与浏览器顶端 的距离与页面的距离,若是前者小于后者,优先加载。jquery

- 原生JavaScript实现图片的懒加载

- jQuery插件 jquery.lazy 

- vue中使用 vue-lazyload

- mint-ui 插件内置懒加载组件
复制代码

三、图片的预加载,若是为幻灯片、相册等,可使用图片预加载技术,将当前展现图片的前一张和后一张优先 下载。初始化的时候得到图片的src以后为每个元素提早添加图片的地址路径。保证再第二张图片显示的时候已经加载到页面当中浏览器

实现方法:循环图片数据,实例化对象的方式建立图片元素 new image() 动态绑定每个image的src属性,并追加到DOM流中
复制代码

2.数据类型种类

  • JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。bash

  • 基本类型有六种: null,undefined,boolean,number,string,symbol。闭包

  • 对象(Object)是引用类型,在使用过程当中会遇到浅拷贝和深拷贝的问题。app

let a = { name: 'FE' }
let b = a
b.name = 'EF'
console.log(a.name) // EF
复制代码

三、typeof

  • typeof 对于基本类型,除了 null 均可以显示正确的类型模块化

  • 想得到一个变量的正确类型,能够经过 Object.prototype.toString.call(xx)函数

四、 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
}
复制代码

五、instanceof操做符

判断对象属于某一个类,回去查找对象的constructor的prototype
复制代码

六、this 环境上下文对象

function foo() {
	console.log(this.a)
}
var a = 1
foo()

var obj = {
	a: 2,
	foo: foo
}
obj.foo()
复制代码

以上二者状况 this 只依赖于调用函数前的对象,优先级是第二个状况大于第一个状况优化

如下状况是优先级最高的,this 只会绑定在 c 上,不会被任何方式修改 this 指向ui

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.做用域/做用域链

一、做用域

  • 种类:JS中有三种做用域,全局做用域,函数做用域,ES6新推出块级做用域

  • 概念:一个变量的可访问规则,再函数建立的时候就已经定义好做用域,整个的JS文件执行有一个最外层的全局做用域(window)

  • 使用: 本做用域内部的全部变量均可已再本做用域内部访问,外部没法访问。内部可访问上级做用域变量,本做用于内部所用使用var声明的变量会有一个做用域提高的过程,let与const声明的变量没有变量提高

二、做用域链

  • 一个变量的访问规则的链式操做

  • 能够把它理解成包含自身变量对象和上级变量对象的列表,经过 [[Scope]] 属性查找上级变量

  • 当访问一个变量的时候,先在本做用域内部进行查找,若是没有去上级做用域进行查找,直到全局做用域window下面,都没有,返回undefined

8.闭包(closure)

一、特色:

  • 内层做用域能够访问外层做用域的变量

  • 闭包就是可以读取其余函数内部变量的函数

  • 函数 A 返回了一个函数 B,而且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

  • 闭包函数引用的变量是存储在堆上的,因此说,当闭包函数弹出调用栈以后,闭包返回的函数依然能调用到闭包函数的变量

二、优势:

  • 使用闭包能够造成独立的空间,延长变量的生命周期,保存中间状态值

  • 能够封装一些私有变量,外部没法进行直接访问(例如用户登录状态计数器)建立当即执行函数(闭包)实现JS模块化封装

  • 解决var声明的循环语句变量没法长久保存的问题

三、缺点:

  • 滥用闭包函数会形成内存泄露,由于闭包中引用到的包裹函数中定义的变量都 永远不会被释放,因此咱们应该在必要的时候,及时释放这个闭包函数,将再也不使用的闭包引用设置为null;

  • 因为函数内部的变量都被保存在内存中, 会致使内存消耗大;

四、相关代码:

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)
}
复制代码
相关文章
相关标签/搜索