一、html+css部分、
(1)css盒模型,可能会要求手写一个布局,这个布局基本上用到的css是margin的负值,boxing-sizing:border-box,布局尽量往这方面想。浏览器布局的基本元素是盒,在w3c的标准模式下,width=width,但是在怪异模式下,width=border*2+padding*2+width;其中后代元素的width:100%;参照的是右边的那个width,
(2)html5的新特性
1、标签语义化,比如header,footer,nav,aside,article,section等,新增了很多表单元素,入email,url等,除去了center等样式标签,还有除去了有性能问题的frame,frameset等标签
2、音视频元素,video,audio的增加使得我们不需要在依赖外部的插件就可以往网页中加入音视频元素。
3、新增很多api,比如获取用户地理位置的window.navigator.geoloaction,
4、websocket
websocket是一种协议,可以让我们建立客户端到服务器端的全双工通信,这就意味着服务器端可以主动推送数据到客户端,
5、webstorage,webstorage是本地存储,存储在客户端,包括localeStorage和sessionStorage,localeStorage是持久化存储在客户端,只要用户不主动删除,就不会消失,sessionStorage也是存储在客户端,但是他的存在时间是一个回话,一旦浏览器的关于该回话的页面关闭了,sessionStorage就消失了,
6、缓存
html5允许我们自己控制哪些文件需要缓存,哪些不需要,具体的做法如下:
1、首先给html添加manifest属性,并赋值为cache.manifest 2、cache.manifest的内容为: CACHE MANIFEST #v1.2 CACHE : //表示需要缓存的文件 a.js b.js NETWORK: //表示只在用户在线的时候才需要的文件,不会缓存 c.js FALLBACK / /index.html //表示如果找不到第一个资源就用第二个资源代替
7、web worker,web worker是运行在浏览器后台的js程序,他不影响主程序的运行,是另开的一个js线程,可以用这个线程执行复杂的数据操作,然后把操作结果通过postMessage传递给主线程,这样在进行复杂且耗时的操作时就不会阻塞主线程了。
(3)对html5的语义话的理解
html5的语义化指的是用正确的标签包含正确的内容,比如nav标签,里面就应该包含导航条的内容,而不是用做其他的用途,标签语义化的好处就是结构良好,便于阅读,方便威化,也有利于爬虫的查找,提高搜索率。
(4)cookie,sessionStorage,localeStorage的区别
cookie是存储在浏览器端,并且随浏览器的请求一起发送到服务器端的,它有一定的过期时间,到了过期时间自动会消失。sessionStorage和localeStorage也是存储在客户端的,同属于web Storage,比cookie的存储大小要大有8m,cookie只有4kb,localeStorage是持久化的存储在客户端,如果用户不手动清除的话,不会自动消失,会一直存在,sessionStorage也是存储在客户端,但是它的存活时间是在一个回话期间,只要浏览器的回话关闭了就会自动消失。
(5)多个页面之间如何进行通信
使用cookie,使用web worker,使用localeStorage和sessionStorage
(6)浏览器的渲染过程
1、首先获取html,然后构建dom树
2、其次根据css构建render树,render树中不包含定位和几何信息
3、最后构建布局数,布局是含有元素的定位和几何信息
(7)重构、回流
浏览器的重构指的是改变每个元素外观时所触发的浏览器行为,比如颜色,背景等样式发生了改变而进行的重新构造新外观的过程。重构不会引发页面的重新布局,不一定伴随着回流,
回流指的是浏览器为了重新渲染页面的需要而进行的重新计算元素的几何大小和位置的,他的开销是非常大的,回流可以理解为渲染树需要重新进行计算,一般最好触发元素的重构,避免元素的回流;比如通过通过添加类来添加css样式,而不是直接在DOM上设置,当需要操作某一块元素时候,最好使其脱离文档流,这样就不会引起回流了,比如设置position:absolute或者fixed,或者display:none,等操作结束后在显示。
二、JavaScript部分
(1)JavaScript的数据类型
基本数据类型:Number,String,Boolean,Undefined,Null
复杂数据类型:Object,Array,Function,RegExp,Date,Error
全局数据类型:Math
(2)JavaScript的闭包
闭包简单的说就是一个函数能访问外部函数的变量,这就是闭包,比如说:
function a(x){ var tem=3; function b(y){ console.log(x+y+(++tem)); } }
a函数中的b函数就是闭包了,b函数可以使用a函数的局部变量,参数,最典型的闭包应该是下面这样,将定义在函数中的函数作为返回值
function a(x){ var tem=3; function b(y){ console.log(x+y+(++tem)); } return b; }
闭包的另一种作用是隔离作用域,请看下面这段代码
for(var i=0;i<2;i++){ setTimeout(function(){ console.log(i); },0); }
上面这段代码的执行结果是2,2而不是0,1,因为等for循环出来后,执行setTimeout中的函数时,i的值已经变成了2,这就是没有隔离作用域所造成的,请看下面代码
for(var i=0;i<2;i++){ (function(i){ setTimeout(function(){ console.log(i); },0) })(i); }
这样就会输出0,1,我们的立即执行函数创建了一个作用域,隔离了外界的作用域,闭包的缺点是,因为内部闭包函数可以访问外部函数的变量,所以外部函数的变量不能被释放,如果闭包嵌套过多,会导致内存占用大,要合理使用闭包。
(3)new 操作符到底做了什么
首先,new操作符为我们创建一个新的空对象,然后this变量指向该对象,
其次,空对象的原型执行函数的原型,
最后,改变构造函数内部的this的指向
代码如下:
var obj={}; obj.__proto__=fn.prototype; fn.call(obj);
(4)改变函数内部this指针的指向函数
call和apply,假设要改变fn函数内部的this的指向,指向obj,那么可以fn.call(obj);或者fn.apply(obj);那么问题来了,call和apply的区别是什么,其是call和apply的区别在于参数,他们两个的第一个参数都是一样的,表示调用该函数的对象,apply的第二个参数是数组,是[arg1,arg2,arg3]这种形式,而call是arg1,arg2,arg3这样的形式。还有一个bind函数,
var bar=fn.bind(obj);那么fn中的this就指向obj对象了,bind函数返回新的函数,这个函数内的this指针指向obj对象。
(5)JavaScript的作用域和作用域链
JavaScript的作用域指的是变量的作用范围,内部作用域由函数的形参,实参,局部变量,函数构成,内部作用域和外部的作用域一层层的链接起来形成作用域链,当在在函数内部要访问一个变量的时候,首先查找自己的内部作用域有没有这个变量,如果没有就到这个对象的原型对象中去查找,还是没有的话,就到该作用域所在的作用域中找,直到到window所在的作用域,每个函数在声明的时候就默认有一个外部作用域的存在了,比如:
var t=4;function foo(){ var tem=12; funciton bar(){ var temo=34; console.log(t+" "+tem+" "+temo); } }
bar找t变量的过程就是,先到自己的内部作用域中找,发现没有找到,然后到bar所在的最近的外部变量中找,也就是foo的内部作用域,还是没有找到,再到window的作用域中找,结果找到了
(6)JavaScript的继承
function A(name){ this.name=name; } A.prototype.sayName=function(){ console.log(this.name); } function B(age){ this.age=age; }
原型继承
B.prototype=new A("mbj"); //被B的实例共享 var foo=new B(18);foo.age; //18,age是本身携带的属性 foo.name; //mbj,等价于foo.__proto__.name foo.sayName(); //mbj,等价于foo.__proto__.proto__.sayName() foo.toString(); //"[object Object]",等价于foo.__proto__.__proto__.__proto__.toString();
这样B通过原型继承了A,在new B的时候,foo中有个隐藏的属性__proto__指向构造函数的prototype对象,在这里是A对象实例,A对象里面也有一个隐藏的属性__proto__,指向A构造函数的prototype对象,这个对象里面又有一个__proto__指向Object的prototype
这种方式的缺第一个缺点是所有子类共享父类实例,如果某一个子类修改了父类,其他的子类在继承的时候,会造成意想不到的后果。第二个缺点是在构造子类实例的时候,不能给父类传递参数。
构造函数继承
function B(age,name){ this.age=age;A.call(this,name); } var foo=new B(18,"wmy"); foo.name; //wmy foo.age; //18 foo.sayName(); //undefined
采用这种方式继承是把A中的属性加到this上面,这样name相当于就是B的属性,sayName不在A的构造函数中,所以访问不到sayName。这种方法的缺点是父类的prototype中的函数不能复用。
原型继承+构造函数继承
function B(age,name){ this.age=age;A.call(this,name); } B.prototype=new A("mbj"); var foo=new B(18,"wmy"); foo.name; //wmy foo.age; //18 foo.sayName(); //wmy
这样就可以成功访问sayName函数了,结合了上述两种方式的优点,但是这种方式也有缺点,那就是占用的空间更大了。