重绘、回流(重排)
当render tree(DOM tree和样式结构体cssom结合后构建呈现树render tree)中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建,这就成为回流。每个也没面至少需要一次回流,就是在页面第一次加载的时候。
当reder trr中的一些元素需要更新属性,而这些属性只是影响元素的外观、风格,而不会影响布局的,比如background-color,则就成为重绘
重绘
只改变自身样式,不会影响其他元素
元素样式的改变(宽高、大小、位置不变)
如visibily、color、background-color等
回流
元素的大小或者位置发生改变,触发了重新布局导致渲染树重新计算布局和渲染
如添加和删除可见的DOM元素
元素的位置、尺寸发生改变
内容发生变化(如文本变化或图片被另一个不同尺寸的图片所代替)
页面一开始渲染的时候(无法避免)
回流是根据视口大小来计算元素的位置和大小的,所以浏览器窗口尺寸变化也会引起回流
造成回流的条件:
1,页面初始渲染
2,改变字体,改变元素尺寸(宽、高、内边距、边框、改变元素位置等),注意:修改属性不影响布局则不会发生回流
3,改变元素内容(文本或图片等或比如用户在input中输入文字)
4,添加、删除可见的DOM元素
5,fixed定位的元素,在拖动滚动条的时候会一直回流
6,调整窗口大小
7,计算offsetWidth、offsetHeight属性
注:回流一定会触发重绘,重绘不一定会回流
2, 预解析常见面试题
1,首先把函数声明和变量声明,提升到当前作用域最前面,因为JS是一个解释执行的脚本语言,从上到下执行,如果函数调用出现在函数定义之前,就会导致失败
2,变量提升的是声明并不是赋值,函数只提升声明并不调用
3,函数在JS里属于一级公民,如果变量名和函数冲突,则会优先执行函数
1,alert(a)
console.log(a) // a is not defined
2,console.log(a) // undefined
var a = 0
console.log(a) // 0
3,console.log(a) // a() {console.log('我是函数')} 函数和带var的变量重名,var变量被忽略
var a = '我是变量'
function a() {
console.log('我是函数')
}
console.log(a) // 我是变量
4,console.log(a) // a () {console.log('我是函数')}
a++
console.log(a) // NaN
var a = '我是变量'
function a() {
console.log('我是函数')
}
console.log(a) // 我是变量
5,console.log(a) // undefined
var a = 0
console.log(a) // 0
function fn() {
console.log(a) // undefined
var a = 1
console.log(a) // 1
}
fn()
console.log(a) // 0 因为函数中的a带var,所以没有影响外面的a,如果函数里的a没有带var,运行结果就不一样了
6,console.log(a) // undefined
var a = 0;
console.log(a) // 0
function fn() {
console.log(a) // 0 不带var没有提升,函数内没有a,沿着作用域链向上找,找到全局里的a
a = 1;
console.log(a) // 1
}
fn()
console.log(a) // 1 函数里的a没有带var,此时先看有没有形参,如果有,相当于在函数里var一个a,如果没有,看全局有没有a,如果有就是修改全局的a,如果全局没有a,就在全局增加一个a,这里就是修改全局的a
7,console.log(a) // undefined
var a = 0
console.log(a) // 0
function fn () {
console.log(a)
a = 1
console.log(a)
} // 函数在预解析提升时,如果函数重名,下面的会覆盖上面的,所以这函数失效
fn()
function fn () {
console.log(a) // undefined
var a = 2
console.log(a++) // 2 ++在前,先赋值后运算。++在后,先运算再赋值
// i++和++i都等同于 i = i + 1
// 但是一般情况下他们都跟赋值联系在一起,比如
// var a
// a = i++ 将i赋值给a,即a = i,之后再执行 i = i + 1
// a = ++i 将i + 1赋值给a, 即 a = i + 1,再执行 i = i + 1
// 总结:
// 后置++,是将自身的值赋值给变量,再自身加1
// 前置++,是将自身+1后的值赋值给变量,同时自身加1
}
console.log(a) // 0 函数里的a带var,不影响全局的
8,console.log(a) // undefined
var a = 1
console.log(a) // 1
function a () {
console.log(2)
} // 函数重名,此函数失效
console.log(a) // 1
var a = 3 // 预解析时,变量名和函数名重名,预解析时的var a = undefined会被忽略,执行时的 a = 3不受影响
console.log(a) // 3
function a () {
console.log(4) // 函数始终没有被调用,这里应该是一个幌子
}
console.log(a) // 3
9, f1()
console.log(c) // 10
console.log(b) // 10
console.log(a) // a is not defined
function f1 () {
var a = b = c = 10
console.log(a)
console.log(b)
console.log(c)
}
10,f1()
console.log(a) // a is not defined 由于JS报错,后面的代码都不执行,导致bc都没有打印
console.log(b)
console.log(c)
function f1 () {
var a = b = c = 10
console.log(a) // 10
console.log(b) // 10
console.log(c) // 10
}
11,myFun(10, 20) // myFun is not a function
var myFun = function (a, b) {
return a + b
}
// 这个函数定义的方式是:函数表达式定义,在预解析时这个函数不会整体提升,只是提升了var myFun = undefined,此时当函数调用,肯定就会报错
12,var i = 1
i = i++ // 本来i在运算之后应该变为2的,但是=左边是给i本身赋值,所以i = 1
var j = i++ // ++在后,先运算,j=1,后赋值 i = 2
var k = i + ++i * i++ // k = 2 + 3 * 3, 此时i = 4
console.log(i, j, k) // 4 1 11
var k = i++ + i++ * i++ // k = 4 + 5 * 6, 此时i变成7
console.log(i, j, k) // 7 1 34
网友评论