哪些操作会造成内存泄漏?

相关知识点:

  • 1.意外的全局变量
  • 2.被遗忘的计时器或回调函数
  • 3.脱离 DOM 的引用
  • 4.闭包

回答:

第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。

第二种情况是我们设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留
在内存中,而无法被回收。

第三种情况是我们获取一个 DOM 元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回
收。

第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。

详细资料可以参考:
《JavaScript 内存泄漏教程》
《4 类 JavaScript 内存泄漏及如何避免》
《杜绝 js 中四种内存泄漏类型的发生》
《javascript 典型内存泄漏及 chrome 的排查方法》

需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案?

通过使用 pushState + ajax 实现浏览器无刷新前进后退,当一次 ajax 调用成功后我们将一条 state 记录加入到 history
对象中。一条 state 记录包含了 url、title 和 content 属性,在 popstate 事件中可以获取到这个 state 对象,我们可
以使用 content 来传递数据。最后我们通过对 window.onpopstate 事件监听来响应浏览器的前进后退操作。

使用 pushState 来实现有两个问题,一个是打开首页时没有记录,我们可以使用 replaceState 来将首页的记录替换,另一个问
题是当一个页面刷新的时候,仍然会向服务器端请求数据,因此如果请求的 url 需要后端的配合将其重定向到一个页面。

详细资料可以参考:
《pushState + ajax 实现浏览器无刷新前进后退》
《Manipulating the browser history》

如何判断当前脚本运行在浏览器还是 node 环境中?(阿里)

typeof window === 'undefined' ? 'node' : 'browser';

通过判断当前环境的 window 对象类型是否为 undefined,如果是undefined,则说明当前脚本运行在node环境,否则说明运行在window环境。

把 script 标签放在页面的最底部的 body 封闭之前和封闭之后有什么区别?浏览器会如何解析它们?

详细资料可以参考:
《为什么把 script 标签放在 body 结束标签之后 html 结束标签之前?》
《从 Chrome 源码看浏览器如何加载资源》

移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时?

移动端点击有 300ms 的延迟是因为移动端会有双击缩放的这个操作,因此浏览器在 click 之后要等待 300ms,看用户有没有下一次点击,来判断这次操作是不是双击。

有三种办法来解决这个问题:

  • 1.通过 meta 标签禁用网页的缩放。
  • 2.通过 meta 标签将网页的 viewport 设置为 ideal viewport。
  • 3.调用一些 js 库,比如 FastClick
click 延时问题还可能引起点击穿透的问题,就是如果我们在一个元素上注册了 touchStart 的监听事件,这个事件会将这个元素隐藏掉,我们发现当这个元素隐藏后,触发了这个元素下的一个元素的点击事件,这就是点击穿透。

详细资料可以参考:
《移动端 300ms 点击延迟和点击穿透》

什么是“前端路由”?什么时候适合使用“前端路由”?“前端路由”有哪些优点和缺点?

(1)什么是前端路由?

前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的。

(2)什么时候使用前端路由?

在单页面应用,大部分页面结构不变,只改变部分内容的使用

(3)前端路由有什么优点和缺点?

优点:用户体验好,不需要每次都从服务器全部获取,快速展现给用户

缺点:单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置

前端路由一共有两种实现方式,一种是通过 hash 的方式,一种是通过使用 pushState 的方式。

详细资料可以参考:
《什么是“前端路由”》
《浅谈前端路由》
《前端路由是什么东西?》

如何测试前端代码么? 知道 BDD, TDD, Unit Test 么? 知道怎么测试你的前端工程么(mocha, sinon, jasmin, qUnit..)?

详细资料可以参考:
《浅谈前端单元测试》

检测浏览器版本版本有哪些方式?

检测浏览器版本一共有两种方式:

一种是检测 window.navigator.userAgent 的值,但这种方式很不可靠,因为 userAgent 可以被改写,并且早期的浏览器如 ie,会通过伪装自己的 userAgent 的值为 Mozilla 来躲过服务器的检测。

第二种方式是功能检测,根据每个浏览器独有的特性来进行判断,如 ie 下独有的 ActiveXObject。

详细资料可以参考:
《JavaScript 判断浏览器类型》

什么是 Polyfill ?

Polyfill 指的是用于实现浏览器并不支持的原生 API 的代码。

比如说 querySelectorAll 是很多现代浏览器都支持的原生 Web API,但是有些古老的浏览器并不支持,那么假设有人写了一段代码来实现这个功能使这些浏览器也支持了这个功能,那么这就可以成为一个 Polyfill。

一个 shim 是一个库,有自己的 API,而不是单纯实现原生不支持的 API。

详细资料可以参考:
《Web 开发中的“黑话”》
《Polyfill 为何物》

使用 JS 实现获取文件扩展名?

// String.lastIndexOf() 方法返回指定值(本例中的'.')在调用该方法的字符串中最后出现的位置,如果没找到则返回 -1。

// 对于 'filename' 和 '.hiddenfile' ,lastIndexOf 的返回值分别为 0 和 -1 无符号右移操作符(>>>) 将 -1 转换为 4294967295 ,将 -2 转换为 4294967294 ,这个方法可以保证边缘情况时文件名不变。

// String.prototype.slice() 从上面计算的索引处提取文件的扩展名。如果索引比文件名的长度大,结果为""。
function getFileExtension(filename) {
return filename.slice(((filename.lastIndexOf(".") - 1) >>> 0) + 2);
}

详细资料可以参考:
《如何更有效的获取文件扩展名》