-
px、em 和 rem 的区别
- px 表示像素 (计算机屏幕上的一个点:1px = 1/96in),是绝对单位,不会因为其他元素的尺寸变化而变化;
- em 表示相对于父元素的字体大小。em 是相对单位,没有一个固定的度量值,而是由其他元素尺寸来决定的相对值。
-
rem:相对单位,可理解为”root em”, 相对根节点 html 的字体大小来计算,CSS3 新加属性,chrome/firefox/IE9+ 支持。
任意浏览器的默认字体高都是 16px。所以未经调整的浏览器都符合: 1em=16px。那么 12px=0.75em, 10px=0.625em。为了简化计算,在 css 中的 body 选择器中声明 Font-size=62.5%,这就使 em 值变为 16px*62.5%=10px, 这样 12px=1.2em, 10px=1em, 也就是说只需要将你的原来的 px 数值除以 10,然后换上 em 作为单位就行了。
-
优雅降级和渐进增强
- 渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
- 优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
-
eval()的作用
eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
语法:eval(string)
-
JS 哪些操作会造成内存泄露
JS 的回收机制:
找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔, 周期性的执行。
垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:“标记清除”和“引用计数”。引用计数不太常用,标记清除较为常用。
1、标记清除
这是 javascript 中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
* 关于这一块,建议读读,关于作用域链的一些知识详解,读完差不多就知道了,哪些变量会被做标记。function test(){ var a=10;// 被标记,进入环境 var b=20;// 被标记,进入环境 } test();// 执行完毕之后 a、b 又被标记离开环境,被回收
2、引用计数
另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减 1。当这个引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为 0 的值所占的内存。function test(){var a={};// a 的引用次数为 0 var b=a;// a 的引用次数加 1,为 1 var c=a;// a 的引用次数加 1,为 2 var b={};// a 的引用次数减 1,为 1}
哪些操作会造成内存泄露:
1. 意外的全局变量引起的内存泄露,一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window,也就是说:function foo(arg) {bar = "aaaaa";} // 实际上等价于 function foo(arg) {window.bar = "aaaaa";} // 类似的 function foo() {this.variable = "qqqqq";} //this 指向全局对象(window)foo();
2. 闭包引起的内存泄露
function fn1(){ var n=1; function fn2(){// 在加一个 fn2 当他的子集 alert(n); } return fn2(); //return 出来后 他就给 window 了所以一直存在内存中。因为一直在内存中,在 IE 里容易造成内存泄漏 } fn1();
3.dom 清空或删除时,事件未清除导致的内存泄漏
var elements={button: document.getElementById("button"), image: document.getElementById("image"), text: document.getElementById("text") }; function doStuff(){ image.src="http://some.url/image"; button.click(): console.log(text.innerHTML) } function removeButton(){document.body.removeChild(document.getElementById('button')) }
4. 循环引用
function leakMemory() {var el = document.getElementById('el'); var o = {'el': el}; el.o = o; }
5. 定时器 setTimeout 和 setInterval:当不需要 setInterval 或者 setTimeout 时,定时器没有被 clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。比如:vue 使用了定时器,需要在 beforeDestroy 中做对应销毁处理。js 也是一样的。
clearTimeout(***) clearInterval(***)
6. 如果在 mounted/created 钩子中使用了 $on,需要在 beforeDestroy 中做对应解绑 ($off) 处理
beforeDestroy() {this.bus.$off('****'); }
7. 死循环
while(1){a++;}
8. 给 DOM 对象添加的属性是一个对象的引用
var testObject = {}; document.getElementById('idname').property = testObject; // 如果 DOM 不被消除,则 testObject 会一直存在,造成内存泄漏
-
bootstrap 响应式实现的原理
百分比布局 + 媒体查询
-
CSS 样式覆盖规则
- 规则一:由于继承而发生样式冲突时,最近祖先获胜。
- 规则二:继承的样式和直接指定的样式冲突时,直接指定的样式获胜
-
规则三:直接指定的样式发生冲突时,样式权值高者获胜。
样式的权值取决于样式的选择器,权值定义如下表: ``` CSS 选择器 权值 标签选择器 1 类选择器 10 ID 选择器 100 内联样式 1000 伪元素(:first-child) 1 伪类(:link) 10 ``` 可以看到,内联样式的权值 >>ID 选择器 >> 类选择器 >> 标签选择器,除此以外,后代选择器的权值为每项权值之和,比如”#nav .current a”的权值为 100 + 10 + 1 = 111。
-
规则四:样式权值相同时,后者获胜。
- 规则五:!important 的样式属性不被覆盖。
-
position 的值,relative 和 absolute 分别是相对于谁进行定位的
- absolute: 生成绝对定位的元素,相对于最近一级的定位不是 static 的父元素来进行定位(相对于最近的已经定位,即 position 为 absolute 或者 relative 的元素的祖先元素)。
- fixed(老 IE 不支持)生成绝对定位的元素,通常相对于浏览器窗口或 frame 进行定位。
- relative 生成相对定位的元素,相对于其在普通流中的位置进行定位(相对于本元素原始位置进行定位)。
- static 默认值。没有定位,元素出现在正常的流中
- sticky 生成粘性定位的元素,容器的位置根据正常文档流计算得出
-
解释下 CSSsprites,以及你要如何在页面或网站中使用它
CSS Sprites 其实就是把网页中一些背景图片整合到一张图片文件中,再利用 CSS 的“background-image”,“background-repeat”,“background-position”的组合进行背景定位,background-position 可以用数字能精确的定位出背景图片的位置
-
怎样添加、移除、移动、复制、创建和查找节点?
1)创建新节点 createDocumentFragment() // 创建一个 DOM 片段 createElement() // 创建一个具体的元素 createTextNode() // 创建一个文本节点 2)添加、移除、替换、插入 appendChild() // 添加 removeChild() // 移除 replaceChild() // 替换 insertBefore() // 插入 3)查找 getElementsByTagName() // 通过标签名称 getElementsByName() // 通过元素的 Name 属性的值 getElementById() // 通过元素 Id,唯一性
-
浏览器的内核分别是什么?
- IE: trident 内核
- Firefox:gecko 内核
- Safari:webkit 内核
- Opera:以前是 presto 内核,Opera 现已改用 Google Chrome 的 Blink 内核
- Chrome:Blink(基于 webkit,Google 与 Opera Software 共同开发)
-
请解释 JSONP 的工作原理,以及它为什么不是真正的 AJAX。
JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML 中的 script 标签可以加载并执行其他域的 javascript,于是我们可以通过 script 标记来动态加载其他域的资源。例如我要从域 A 的页面 pageA 加载域 B 的数据,那么在域 B 的页面 pageB 中我以 JavaScript 的形式声明 pageA 需要的数据,然后在 pageA 中用 script 标签把 pageB 加载进来,那么 pageB 中的脚本就会得以执行。JSONP 在此基础上加入了回调函数,pageB 加载完之后会执行 pageA 中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP 易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP 是非常合适的选择。
-
请解释一下 JavaScript 的同源策略。
在客户端编程语言中,如 javascript 和 ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。那么什么叫相同域,什么叫不同的域呢?当两个域具有相同的协议, 相同的端口,相同的 host,那么我们就可以认为它们是相同的域。同源策略还应该对一些特殊情况做处理,比如限制 file 协议下脚本的访问权限。本地的 HTML 文件在浏览器中是通过 file 协议打开的,如果脚本能通过 file 协议访问到硬盘上其它任意文件,就会出现安全隐患,目前 IE8 还有这样的隐患。
-
浏览器是如何渲染页面的?
- 解析 HTML 文件,创建 DOM 树。自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
- 解析 CSS。优先级:浏览器默认设置 < 用户设置 < 外部样式 < 内联样式 <HTML 中的 style 样式;
- 将 CSS 与 DOM 合并,构建渲染树(Render Tree)
- 布局和绘制,重绘(repaint)和重排(reflow)
-
对 <meta></meta> 标签有什么理解
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <meta name="author" content="w3school.com.cn"> <meta name="revised" content="David Yang,8/1/07"> <meta name="generator" content="Dreamweaver 8.0en"> </head> <body> <p> 本文档的 meta 属性标识了创作者和编辑软件。</p> </body> </html>
-
请写出你对闭包的理解,并列出简单的理解
使用闭包主要是为了设计私有的方法和变量。
闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
闭包有三个特性:
1. 函数嵌套函数
2. 函数内部可以引用外部的参数和变量
3. 参数和变量不会被垃圾回收机制回收 -
JavaScript 中如何检测一个变量是一个 String 类型?请写出函数实现
typeof(obj) === "string" typeof obj === "string" obj.constructor === String
- 判断一个字符串中出现次数最多的字符,统计这个次数
-
$(document).ready()方法和 window.onload 有什么区别?
- window.onload 方法是在网页中所有的元素 (包括元素的所有关联文件) 完全加载到浏览器后才执行的。
- $(document).ready()方法可以在 DOM 载入就绪时就对其进行操纵,并调用执行绑定的函数。
-
js 遍历
- for 循环
-
forEach 循环:forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。没有返回值。
array.forEach(function(currentValue[, index, arr), thisValue])
-
map()函数:map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
array.map(unction(currentValue,index,arr), thisValue)
-
filter 函数:方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
array.filter(function(currentValue[,index,arr), thisValue])
-
some 函数:some() 方法用于检测数组中的元素是否满足指定条件(函数提供),some() 方法会依次执行数组的每个元素:
array.some(function(currentValue[,index,arr),thisValue])
-
对象 in 方法
let obj ={a:'2',b:3,c:true}; for (var i in obj) {console.log(obj[i],i) } console.log(obj);
-
Object.keys(obj)和 Object.values(obj)函数
const obj = { id:1, name:'zhangsan', age:18 } console.log(Object.keys(obj)) console.log(Object.values(obj))
-
js 数组处理函数总结
- array.push():push() 向数组的末尾添加一个或更多元素,并返回新的长度。
- array.pop():删除并返回数组的最后一个元素
- array.unshift():向数组的开头添加一个或更多元素,并返回新的长度.
- array.shift():删除并返回数组的第一个元素
- array.reverse():方法将数组中元素的位置颠倒, 并返回该数组。该方法 会改变原数组。
- array.sort():方法用 原地算法 对数组的元素进行排序,并返回数组。排序算法现在是 稳定的。默认排序顺序是根据字符串 Unicode 码点。由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。原数组上原地排序,原数组改变。
- array.concat(array2):方法用于合并两个或多个数组。此方法 不会更改现有数组 ,而是返回一个 新数组。
-
array.join():creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator.
var arr = new Array(3) arr[0] = "George" arr[1] = "John" arr[2] = "Thomas" arr.join() // output: George,John,Thomas
-
string.slice(start,end):方法提取一个字符串的一部分,返回一个从原字符串中提取出来的新字符串。
// 语法: str.slice(beginSlice[, endSlice]) beginSlice: 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。endSlice: 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。// 实例: var arr = new Array(3) arr[0] = "George" arr[1] = "John" arr[2] = "Thomas" arr.slice(1) // output: John,Thomas
-
array.splice():方法通过删除或替换现有元素或者原地添加新的元素来修改数组, 并以数组形式返回被修改的内容。此方法会改变原数组。
// 语法: array.splice(startIndex,howmany[,item1,.....]) // 示例 1: 添加元素 var fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.splice(2,1,"Lemon","Kiwi"); // output: Banana,Orange,Lemon,Kiwi,Mango // 示例 2: 删除元素 var fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.splice(2,2); // output: Banana,Orange
- array.indexOf():返回数组对象的原始值
-
array.reduce(reducer):方法对数组中的每个元素执行一个由您提供的 reducer 函数 (升序执行),将其结果汇总为 单个返回值。
reducer 函数接收 4 个参数: 1 Accumulator (acc) (累计器) 2 Current Value (cur) (当前值) 3 Current Index (idx) (当前索引) 4 Source Array (src) (源数组)
- array.map():对数组的每一项应用回调函数,返回 新数组。
- array.some():数组中 只需有一项 满足给定条件则返回 true。
- array.filter():方法创建一个 新数组, 其包含通过所提供函数实现的测试的所有元素。
- array.every():数组的 每一项 都满足给定条件则返回 true。
- forEach:数组遍历,与 for 循环一样,没有返回。