- 在制作一个Web应用或Web站点的过程中,你是如何考虑它的UI、安全性、高性能、SEO、可维护性以及技术因素的?
(如果问我这个问题,我会很兴奋的,因为可以说半个小时。)
- 谈谈你喜欢的开发环境。(例如操作系统,编辑器,浏览器,工具等等。)
(有两套开发环境,一套是用来平时团队项目的开发,我的jdk、tomcat、photoshop等等都部署安装在wins系统上面;另外一套是用来“装逼”的,呃,对于我这种选择困难症病人,纠结了一下最后决定说说“装逼”的那套开发环境)
操作系统用的是linux的ubuntu,能够是我接触到linux常用命令、下载安装、转移新增删除文件都很方便(面试官会问到哪些指令吗?)
编辑器是brackets,作为免费、开源且跨平台的 HTML/CSS/JavaScript 前端 WEB 集成开发环境,简约、优雅、快捷!
浏览器是chrome,内部提供的开发工具很丰富,例如单步调试、模拟不同像素设备、能够显示较多css3属性等。
- *你最熟悉哪一套版本控制系统?
(这个问题,用过git,用过myeclipse里的svn,用过tortoiseSVN将代码上传到sinaapp服务器,但是都不是很熟悉,只好翻了一下《Pro.Git-zh_CN》)
在Git 中的绝大多数操作都只需要访问本地文件和资源,不用连网。对于任何一个文件,在Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。
基本的Git 工作流程如下所示:
1. 在工作目录中修改某些文件。
2. 对这些修改了的文件作快照,并保存到暂存区域。
3. 提交更新,将保存在暂存区域的文件快照转储到git 目录中。
常用命令:
//用git 把Git 项目仓库克隆到本地,以便日后随时更新: $ git clone git://git.kernel.org/pub/scm/git/git.git //git add 命令告诉Git 开始对 这些文件进行跟踪,然后提交: $ git add filenme.html //每次准备提交前,先用git status 看下,是不是都已暂存起来了,然后再运行提交命令 $ git commit -m 'initial project version' // 把本地仓库提交到远程仓库的master分支中 $ git push origin master
- 你能描述一下当你制作一个网页的工作流程吗?
1)根据需求,确定主题。透彻深入所做网站的核心功能和关键。
2)收集资料。从对比相同类型的网站(惯用而熟悉的样式,用户更乐意接受),参照别人可行的实现方法。
3)规划网站。抽离出类似的模块和可重用的部件。如果是响应式网站就需要设定断点,根据不同宽度屏幕设定样式。
4)设计数据库。
5)搭建基本的框架。引入重置样式表reset.css和字体样式表font.css,风格统一的图标还有后台需要用到的包。
6)编码和调试。注意统一命名和编码规范。当多人开发时,还需要制定规范文档。
7)上传测试。利用FTP工具,把网站发布到自己申请的主页存放服务器上。网站上传以后,你要在浏览器中打开自己的网站,逐页逐个链接的进行测试,发现问题,及时修改,然后再上传测试。
8)推广宣传 。不断宣传,提高网站的访问率和知名度。推广的方法有很多,例如到搜索引擎上注册、与别的网站交换链接、加入广告链等。
9)维护更新 。网站要注意经常维护更新内容,保持内容的新鲜,不要一做好就放在那儿不变了,只有不断地给它补充新的内容,才能够吸引住浏览者
(具体还需要集合我的实际经验:http://www.cnblogs.com/0603ljx/p/4284521.html)
- 你能描述一下渐进增强和优雅降级之间的不同吗?
它们是看待同种事物的两种观点,它们关注在同一个网站同一功能在不同设备不同浏览器下的表现:
渐进增强,一开始值构建站点的最小特性,然后不断针对个浏览器追加功能,性能越好的设备能够显示更加出众的效果。
优雅降级,一开始就构造站点的完整功能,然后针对浏览器测试和修复。
web标准对可访问性做了如下定义:web内容对于残障用户或者普通的可阅读和可理解性。无论用户是否残障,都得通过用户代理(User Agent)来访问Web内容。因此要提高可访问性,首先得考虑各种用户代理 :桌面浏览器、语音浏览器、移动电话、车载个人电脑等等。还得考虑用户访问Web内容时的环境限制 。比如:我们真的要考虑浏览器禁用JavaScript/CSS的情形吗?我的理解是,要考虑的其实不是禁用了JavaScript/CSS的浏览器,而是那些对JavaScript/CSS不支持或支持不好的用户代理。比如语音阅读器,手机浏览器等,JavaScript提供的是一层可访问性,不能代替内容本身。
当然,从渐进增强的角度讲,鼓励使用高级特性,只是同时要做到优雅降级,让低端用户代理上,也能保留低保真的体验。(除了用户代理,还有什么方法检测客户端设备?特性检测,css3媒体查询)
(讲讲我在平时项目中,在“渐进增强”和“优雅降级”的努力)
- 如果提到了特性检测,可以加分。
- 假若你有5个不同的 CSS 文件, 加载进页面的最好方式是?
文件拼合,减少http请求。
用一个大的CSS文件替代多个小体积的CSS文件这是一个很好的实践,可以获得更好的可维护性,但是在网站性能方面会产生一定的影响(这里指的是随着文件体积的增大,随之消耗服务器的内存也会增加)。尽管你应该把CSS文件拆分成小块,但是当浏览器请求这些文件时,会产生同等数量的http请求。每个http请求都会产生一次从你的浏览器到服务器端网络往返过程,并且导致推迟到达服务器端和返回浏览器端的时间,我们称之为延迟。因此,如果你有4个Javascript和3个css文件在页面中被加载,你浪费掉了7次因网络往返过程产生的时间。在美国,延迟平均是70毫秒,这样你就浪费了7*70 = 490毫秒,大致延迟了半秒的时间。在美国之外的国家访问你的页面,平均延迟大约是200毫秒,这意味着你的页面有1400毫秒的时间是在等待中度过。浏览器在你的CSS完全加载完成之前是不能很好的渲染你的页面的。因此越多的延迟让你的页面载入越慢。
- 请解释一下什么是“语义化的 HTML”
分离结构和表现的另一个重要方式是使用语义化的标记来构造文档内容。一个XHTML元素的存在意味着被标记内容有相应的结构化意义,例如<p>是用来标记段落<h1>标记标题<ul><li>标记列表,不能过分使用<div>
语义化的标签往往与默认样式有所联系,像是Hx系列 表示标题,会被赋予默认的块级加粗居中样式;<strong>,<em>用来区别于其他文字,起到了强调的作用。用来明确告诉你它们的用途。
语义化标签让大家更直观认识标签和属性的用途。语义化的网页,对搜索引擎友好,更容易被搜索引擎抓取,有利于推广。
- *你如何对网站的文件和资源进行优化?
- 期待的解决方案包括:
- 文件合并(同上题“假若你有5个不同的 CSS 文件, 加载进页面的最好方式是?”)
减少调用其他页面、文件的数量。一般我们为了让页面生动活泼会大量使用background来加载背景图,而每个 background的图像都会产生1次HTTP请求,要改善这个状况,可以采用css的1个有用的background-position属 性来加载背景图,我们将需要频繁加载的多个图片合成为1个单独的图片,需要加载时可以采用:background:url(....) no-repeat x-offset y-offset;的形式加载即可将这部分图片加载的HTTP请求缩减为1个。
- 文件最小化/文件压缩
即将需要传输的内容压缩后传输到客户端再解压,这样在网络上传输的 数据量就会大幅减小。通常在服务器上的Apache、Nginx可以直接开启这个设置,也可以从代码角度直接设置传输文件头,增加gzip的设置,也可以 从 负载均衡设备直接设置。不过需要留意的是,这个设置会略微增加服务器的负担。建议服务器性能不是很好的网站,要慎重考虑。
- 使用 CDN 托管
CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。
- 缓存的使用
Ajax调用都采用缓存调用方式,一般采用附加特征参数方式实现,注意其中的<script src=”xxx.js?{VERHASH}”,{VERHASH}就是特征参数,这个参数不变化就使用缓存文件,如果发生变化则重新下载新文件或更新信息。
- css文件放置在head,js放置在文档尾部
- 在服务器端配置control-cache last-modify-date
- 在服务器配置Entity-Tag if-none-match
闻东师兄说:
- 为什么利用多个域名来提供网站资源会更有效?
- 浏览器同一时间可以从一个域名下载多少资源?
即浏览器并发请求数。同一时间针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻止。(借用百度上的一张图片)
- 有什么例外吗?
- 加分项: 指出在手机端可能有负面影响 (http://www.mobify.com/blog/domain-sharding-bad-news-mobile-performance/)
- 加分项: HTTP2 / SPDY
- 请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)
关于实际加载时间,可以使用上题”你如何对网站的文件和资源进行优化?“方法。
关于感知时间,可以使用上题“编写代码的哪些方面能够使你兴奋或感兴趣?”答案。
- *如果你参与到一个项目中,发现他们使用 Tab 来缩进代码,但是你喜欢空格,你会怎么做?
- 建议这个项目使用像 EditorConfig (http://editorconfig.org/) 之类的规范
- 为了保持一致性,接受项目原有的风格
- 直接使用 VIM 的 retab 命令
- 请写一个简单的幻灯效果页面
- 如果不使用JS来完成,可以加分。
- *你都使用哪些工具来测试代码的性能?
- Profiler, JSPerf, Dromaeo
- 如果今年你打算熟练掌握一项新技术,那会是什么?
开发单页webapp的技术。
SAP能够是页面与页面之间无缝连接,避免出现白页,且带有动态效果,提高用户体验。同时SAP,有javascript渲染页面,然后在从服务器获取小量的数据显示,如此反复,请求的数据无需要服务器处理,减少服务器负荷。
SAP对技术要求高。要考虑首屏加载事件过长;动画效果要考虑低端手机;垃圾收集,需要自己释放资源,避免页面变卡。
- *Long-Polling, Websockets, SSE(Server-Sent Event) 之间有什么区别?
- 请谈一下你对网页标准和标准制定机构重要性的理解。
关于W3C标准,要求:
1)书写闭合,标签小写、不乱嵌套。有利于SEO
2)尽量使用外链的css和js脚本,结构行为表现分离。有利于页面加载速度加快。
3)样式和标签分离,使用更合理的语义化标签,内容被更多用户设备访问,维护成本也会降低。
指定标准,能够规避不同开发商开发出来不同的浏览器显示不一致问题,同时为
- *什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
某些页面在Windows 下的Internet Explorer出现一些奇怪的现象:以无样式显示页面内容的瞬间闪烁,这种现象称之为文档样式短暂失效(Flash of Unstyled Content),简称为FOUC.原因大致为: 1,使用import方法导入样式表。 2,将样式表放在页面底部 3,有几个样式表,放在html结构的不同位置。其实原理很清楚:当样式表晚于 结构性html 加载,当加载到此样式表时,页面将停止之前的渲染。此样式表被下载和解析后,将重新渲染页面,也就出现了短暂 的 花屏现象。
解决方法:使用LINK标签将样式表放在文档HEAD中更多
- 请尽可能完整得描述下从输入URL到整个网页加载完毕及显示在屏幕上的整个流程
1)用户输入网址
2)浏览器通过DNS获取网站的IP地址
3)浏览器尝试与服务器建立连接
4)服务器发送永久重定向
5)浏览器跟踪从定向地址
7)服务器处理请求
8)服务器发送HTML响应
9)浏览器开始显示HTML
10)浏览器发送获取嵌套在html中的元素
关于页面渲染过程:
1)解析HTML代码,生成一棵DOM树
2)解析CSS文件
3)生成渲染树(受样式影响,包含不可见元素)
4)渲染树中的节点
HTML相关问题:
- doctype(文档类型)的作用是什么?
位于html标签最前面,告诉浏览器以那种html和xhtml规范。分为标准模式和怪异模式、基于框架的HTML模式。假如浏览器不以doctype标准模式编写DTD,页面除了无法通过代码检验之外,还无法在浏览器中正确显示。
a.如果需要干净的标记,免于表现层的混乱,用XHTML Strict DTD类型。
b.Transitional DTD 可包含 W3C 所期望移入样式表的呈现属性和元素。如果用户使用了不支持层叠样式表(CSS)的浏览器以至于你不得不使用 HTML 的呈现特性时,用Transitional DTD 类型。
c.Frameset DTD 被用于带有框架的文档。除 frameset 元素取代了 body 元素之外,Frameset DTD 等同于 Transitional DTD
- 浏览器标准模式和怪异模式之间的区别是什么?
当浏览器厂商开始创建与标准兼容的浏览器时,他们希望确保向后兼容性。为了实现这一目的,他们创建了两种呈现模式,标准和混杂模式。在标准模式中,浏览器会根据规范呈现页面;在混杂模式中。页面会以一种相对宽松的向后兼容方式显示。混杂模式常用于模拟老式浏览器的行为,以防止老站点无法工作。
他们最大的不同是对盒模型的解析。
如:在strict mode中 :width是内容宽度 ,也就是说,元素真正的宽度 = margin-left + border-left-width + padding-left + width + padding-right + border-right- width + margin-right;
在quirks mode中 :width则是元素的实际宽度 ,内容宽度 = width - (margin-left + margin-right + padding-left + padding-right + border-left-width + border-right-width)
使用 document.compatMode来判断浏览器的解析方式。
- 使用 XHTML 的局限有哪些?
xhtml要求严格:放弃了一些语义不好的标签,必须有head、body,每个dom必须要闭合。一些老的浏览器并不兼容。
- 如果页面使用 'application/xhtml+xml' 会有什么问题吗?
为contentType属性值,IE不支持application/xhtml+xml类型,支持text/html
- 如果网页内容需要支持多语言,你会怎么做?
使用统一的UTF-8编码
- 在设计和开发多语言网站时,有哪些问题你必须要考虑?
1)制图时,应该讲图形的图像层与文本层分离,这样在重新绘制改图形时只需对文本进行翻译。
2)设置控件属性应考虑到各种语言版本的文本显示,尽可能为翻译预留足够的空间。同时也应该保持不同语言界面的统一性,避免过多的差异。
3)编码注意代码复用,将多个模块的共用信息存放在共通的文件中便于全局管理。
页面请求的过程可描述如下:
1)用户在终端选择自己所偏好的语言,并通过浏览器向服务器发送页面请求。
2)模板界面接收到语言选项后,从资源文件中读取相应区域的资源。
3)在响应用户的页面请求时,系统将根据检索到的语言选项,动态的加载相关区域的JS文件和CSS文件,为不同区域初始化不同的样式。
4)数据库接口接收到语言选项后,将其作为一个SQL参数传入数据库,检索相应区域的数据。
5)模板界面将接收到的各种信息,组织成Html代码,再发送给浏览器,显示给终端用户。
该架构的核心是模板界面,它主要负责将接收到的各类信息组织成Html代码。
- data-属性的作用是什么?
data-是HTML5为前端开发者提供自定义的属性,这些属性集可以通过对象的dataset属性获取,不支持该属性的浏览器可以通过 getAttribute方法获取。
- 如果把 HTML5 看作做一个开放平台,那它的构建模块有哪些?
1)Web Storage API
2)基于位置服务LBS
3)无插件播放音频视频
4)调用相机和GPU图像处理单元等硬件设备
5)拖拽和Form API
- *请描述一下 cookies,sessionStorage 和 localStorage 的区别?
共同点:都是保存在浏览器端,且同源的。
区别:
1)cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
2)cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
3)sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
4)作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。
sessionStorage 和 localStorage 是HTML5 Web Storage API 提供的,可以方便的在web请求之间保存数据。有了本地数据,就可以避免数据在浏览器和服务器间不必要地来回传递。
sessionStorage、localStorage、cookie都是在浏览器端存储的数据。
其中sessionStorage的概念很特别,引入了一个“浏览器窗口”的概念。sessionStorage是在同源的同窗口(或tab)中,始终存在的数据。也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在。关闭窗口后,sessionStorage即被销毁。同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的。
Web Storage带来的好处:
1)减少网络流量:一旦数据保存在本地后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要地来回传递。
2)快速显示数据:性能好,从本地读数据比通过网络从服务器获得数据快得多,本地数据可以即时获得。再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示。
3)临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便。
浏览器本地存储与服务器端存储之间的区别其实数据既可以在浏览器本地存储,也可以在服务器端存储。
浏览器端可以保存一些数据,需要的时候直接从本地获取,sessionStorage、localStorage和cookie都由浏览器存储在本地的数据。
服务器端也可以保存所有用户的所有数据,但需要的时候浏览器要向服务器请求数据。
1.服务器端可以保存用户的持久数据,如数据库和云存储将用户的大量数据保存在服务器端。
2.服务器端也可以保存用户的临时会话数据。服务器端的session机制,如jsp的 session 对象,数据保存在服务器上。实现上,服务器和浏览器之间仅需传递session id即可,服务器根据session id找到对应用户的session对象。会话数据仅在一段时间内有效,这个时间就是server端设置的session有效期。
服务器端保存所有的用户的数据,所以服务器端的开销较大,而浏览器端保存则把不同用户需要的数据分布保存在用户各自的浏览器中。浏览器端一般只用来存储小数据,而服务器可以存储大数据或小数据。服务器存储数据安全一些,浏览器只适合存储一般数据。
- 请描述一下 GET 和 POST 的区别?
get是从服务器上获取数据,post是向服务器传送数据。
get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程
get形式的url对搜索引擎更加友好,可以提高搜索引擎排名。Post使用的url有时候会阻止爬虫和搜索引擎的访问。其他网站和用户可以链接到get形式的url,无论用户的访问,还是搜索引擎的收录而相应提高了页面排名,能够直接或间接提高网站浏览。同时,get形式的url这种表示法是可以缓存的,显著提升了客户端和服务端的性能。
而不安全操作,如确定订购、下订单、达成协议和删除页面等,应该通过post执行,避免没有显式用户请求和同一的情况下发生意外的操作。例如搜索引擎删除整个页面,只因为抓取了一个链接。很多不希望用户浏览器遵循页面链接的各种完整,这些情况下,应该要求用户登录并且足够的权限才能执行某些危险操作。
若符合下列任一情况,则用POST方法:
* 请求的结果有持续性的副作用,例如,数据库内添加新的数据行。
* 若使用GET方法,则表单上收集的数据可能让URL过长。
* 要传送的数据不是采用7位的ASCII编码。
若符合下列任一情况,则用GET方法:
* 请求是为了查找资源,HTML表单数据仅用来帮助搜索。
* 请求结果无持续性的副作用。
* 收集的数据及HTML表单内的输入字段名称的总长不超过1024个字符。
(目测还会问到“同步和异步的区别?”)
同步:脚本会停留并等待服务器发送回复然后再继续。提交请求->等待服务器处理->处理完毕返回,这个期间客户端浏览器不能干任何事。
异步:脚本允许页面继续其进程并处理可能的回复。请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
若要在使用ajax请求后处理发送请求返回的结果,最好使用同步请求。
CSS 相关问题:
- CSS 中类(classes)和 ID 的区别。
1、在CSS文件里书写时,ID加前缀"#";CLASS用"."
2、id一个页面只可以使用一次;class可以多次引用。
3、ID是一个标签,用于区分不同的结构和内容,就象名字,如果一个屋子有2个人同名,就会出现混淆;class是一个样式,可以套在任何结构和内容上,就象一件衣服;
4、从概念上说就是不一样的:id是先找到结构/内容,再给它定义样式;class是先定义好一种样式,再套给多个结构/内容。
目前的浏览器还都允许用多个相同ID,一般情况下也能正常显示,不过当你需要用JavaScript通过id来控制div时就会出现错误。
- 描述下 “reset” CSS 文件的作用和使用它的好处。
reset.css能够重置浏览器的默认属性。不同的浏览器具有不同的样式,重置能够使其统一。比如说ie浏览器和FF浏览器下button显示不同,通过reset能够统一样式,显示相同的想过。但是很多reset是没必要的,多写了会增加浏览器在渲染页面的负担。
比如说,
1)我们不应该对行内元素设置无效的属性,对span设置width和height,margin都不会生效的。
2)对于absolute和fixed定位的固定尺寸(设置了width和height属性),如果设置了top和left属性,那么bottom和right,margin和float就没有作用。
3)后面设置的属性将会覆盖前面重复设置的属性。
- 期待能够指出它的负面影响,或者提到它的一个更好的替换者"normalize"
normalize.css是一个可以定制的css文件,它让不同的浏览器在渲染元素时形式更统一。
- 解释下浮动和它的工作原理。
问题成因:在一个容器中,有两个浮动的子元素,会造成显示结果意想不到的问题。在CSS规范中,浮动定位不属于正常的页面流,而是独立定位的。
关于css的定位机制:普通流,浮动,绝对定位(position:fixed是position:absolute的一个子类)。浮动的框可以左右移动,直到它的外边缘遇到包含框或者另一个浮动框的边缘,所以才说浮动定位不属于正常的页面流。文档中的普通流就会表现得和浮动框不存在一样,当浮动框高度超出包含框的时候,就会出现包含框不会自动伸缩高度类笔盒浮动元素。所以,只含有浮动元素的父容器在显示时不需要考虑子元素的位置,就造成显示父容器像空容器一样。
解决浮动:
1)添加额外标签
在浮动元素末尾添加一个空的标签例如 <div style=”clear:both”></div>。
缺点:可以想象通过此方法,会添加多少无意义的空标签,有违结构与表现的分离,在后期维护中将是噩梦。
2)使用 br标签和其自身的 html属性 <br clear="all" />
优点:比空标签方式语义稍强,代码量较少
缺点:同样有违结构与表现的分离,不推荐使用
3)父元素设置 overflow:hidden
通过设置父元素overflow值设置为hidden;在IE6中还需要触发 hasLayout ,例如 zoom:1。<div class="warp" id="float3" style="overflow:hidden; *zoom:1;">
优点:不存在结构和语义化问题,代码量极少
缺点:内容增多时候容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素;overflow:hidden会导致中键失效。
4)父元素设置 overflow:auto 属性。同样IE6需要触发hasLayout,演示和3差不多
优点:不存在结构和语义化问题,代码量极少
缺点:多个嵌套后,firefox某些情况会造成内容全选;IE中 mouseover 造成宽度改变时会出现最外层模块有滚动条等,firefox早期版本会无故产生focus等。
5)使用:after 伪元素
需要注意的是 :after是伪元素(Pseudo-Element),不是伪类(某些CSS手册里面称之为“伪对象”),很多清除浮动大全之类的文章都称之为伪类,不过csser要严谨一点,这是一种态度。由于IE6-7不支持:after,使用 zoom:1触发 hasLayout。
.clearfix { *zoom:1; }
优点:结构和语义化完全正确,代码量居中
缺点:复用方式不当会造成代码量增加
- 描述z-index和叠加上下文是如何形成的。
z-index就是控制元素在页面的中的叠加顺序,z-index值高的元素显示在z-index值低的前面。z-index的使用条件:只对有 position 属性的且值不为static的元素才有效。叠加上下文和“堆栈上下文”有关,一组具有共同双亲的元素,按照堆栈顺序一起向前或向后移动构成了所谓的堆栈上下文。
一个元素的堆叠顺序,不仅仅取决于它自身的z-index,更要看它所处在的堆栈上下文,如果所处的上下文的层级很低,即使他本身的z-index设置的很高,也无法实现你的要求。
z-index解析规则都是基于标准的符合w3c规范的浏览器,但IE系列的浏览器总是让你要多费一番功夫。
IE中z-index跟标准浏览器中的解析有一个小小的区别,那就是上面说的产生堆栈上下文中的三个条件中,对第二个条件的支持的区别,在标准浏览器中元素必须是有z-index值的同时要有position属性,且值不为static,满足这两个条件,才会产生一个新的堆栈上下文,但低版本的IE中就不管这么多了,只要你设置了position值不为static,他就会生成一个新的堆栈上下文。
- 列举不同的清除浮动的技巧,并指出它们各自适用的使用场景。
答案为可参考上题“解释下浮动和它的工作原理”
- 解释下 CSS sprites,以及你要如何在页面或网站中实现它。
CSS sprites其实就通过将多个图片融合到一副图里面,然后通过CSS的技术布局到页面上。这样做的好处是,减少图片数量,将会减少http的请求,提升网站性能。
1)在photoshop新建背景透明的画板,将小图片依次摆放在画板中,调整小图片为适当大小。
2)通过标尺记录图片的横坐标纵坐标。
3)编写css代码background:url(....) no-repeat x-offset y-offset;同时设定元素固定高度和宽度,overflow:hidden
- 你最喜欢的图片替换方法是什么,你如何选择使用。
不论是对浏览者还是对搜索引擎,文字都是最佳的页面内容展示方式,但是,由于字体等原因的限制,纯文字的展示渐渐无法满足爱美的设计师的要求。
于是,出现了通过CSS来实现用图片替换文字的方法,这种方式既能实现页面上各种丰富的效果,又能满足搜索引擎优化的需要。
- Fahrner Image Replacement (FIR)
- Phark 的方法
- Gilder/Levin 的方法 (推荐)
Fahrner Image Replacement (FIR)
这是最早出现的图文替换技术,是由 Todd Fahrner 提出的,非常容易理解:
<h2><span>Hello World</span></h2>
h2 { background:url(hello_world.gif) no-repeat; 150px; height: 35px; } span { display: none; }
代码非常明白:先将图片应用在 H2 的背景中,然后将 SPAN 的标签隐藏。但是这种方式有个问题,就是当图片无法显示时,将导致这个区域没有任何内容。同时,使用 display:none 的方式隐藏的内容,将被许多主流屏幕阅读器忽略,从而造成可用性问题,因此,应该尽量避免使用。
Phark 的方法
<h2> Hello World </h2>
h2 { text-indent: -5000px; background:url(hello_world.gif) no-repeat; 150px;height:35px; }
代码也非常简单,通过文本缩进,将文字隐藏,但是,当图片无法显示时,依然存在 FIR 的问题。
Gilder/Levin 的方法
<h2><span></span>Hello World </h2>
h2 { 150px;height: 35px; position: relative; } h2 span { background: url(hello_world.gif) no-repeat; position: absolute; 100%; height: 100%; }
首先,将 H2 的 position 设为 relative ,这样将使 H2 里面的元素定位以 H2 为参照,然后将 SPAN 元素绝对定位,撑满整个 H2 区域,同时将背景图应用在 SPAN 标签里面;这种方法的原理是将 SPAN 标签覆盖在文字内容上面,一旦 SPAN 里面的背景图无法显示,将显示下层的文字内容,不影响正常使用。但是,此方法也有一个缺陷,就是背景图不能透明,否则将透出下面的文字。
- 讨论CSS hacks,条件引用或者其他。
hacks
_width针对于ie6。*width,+width针对于ie6,7。
color: red9;/*IE8以及以下版本浏览器*/(但是测试可以兼容到ie10。
*+html与*html是IE特有的标签, firefox暂不支持.而*+html又为IE7特有标签(但是测试*html兼容ie6-10。*+兼容ie7-10)。
!important 在IE中会被忽视,ie6,7,8不识别,ie9+(包括ie9)是识别的。
条件引用
<!--[if !IE]><!--> 除IE外都可识别 <!--<![endif]--> <!--[if IE]> 所有的IE可识别 <![endif]--> <!--[if IE 6]> 仅IE6可识别 <![endif]--> <!--[if lt IE 6]> IE6以及IE6以下版本可识别 <![endif]--> <!--[if gte IE 6]> IE6以及IE6以上版本可识别 <![endif]--> <!--[if IE 7]> 仅IE7可识别 <![endif]--> <!--[if lt IE 7]> IE7以及IE7以下版本可识别 <![endif]--> <!--[if gte IE 7]> IE7以及IE7以上版本可识别 <![endif]--> <!--[if IE 8]> 仅IE8可识别 <![endif]--> <!--[if IE 9]> 仅IE9可识别 <![endif]-->
- 如何为有功能限制的浏览器提供网页?
1)对于那些可以手动开启的功能,可以在页面上增设“用户使用指导”或“帮助手册”,提示用户如何开启相关的功能。(如果你不介意,还可以完全禁掉页面,强制用户使用固定设备,升级版本;哈哈,当年我做的BMS就是这样做)
例如,针对使用IE浏览器自带的功能可以限制对网页的浏览,比如activeX或者脚本,我们检测到它不可用时,提示用户启用的操作方式。
2)尽量避免当js或者css3失效时,页面不可用的动画效果。
例如,http://www.rippletec.net/网站为了营造一种当页面加载完毕,不同模块滚动到固定位置的绚丽动画效果。应该避免类似的效果,一方面产生繁琐的重绘过程,会消耗浏览器内存,对性能一般的设备可能因为压力过大,卡机或者无法渲染;另外一方面是网站当网站的js不可用时,模块滚动到固定位置的事件没有被触发,用户看到的将会是动画产生之前,最原始的页面状态,无法经行下一步操作。
(首次接触“优雅降级”这个词汇是在《jQuery基础教程(第4版)》,不过那时候已经是一年多以前,现在已经记不清当时书上举得例子了,记性差~真心抱歉)
3)应该为绑定异步的元素,设置herf属性。
例如,用户要执行查询某书本详细信息操作,点击“查询”按钮,通过js触发查询该条目的事件,然后采用jQuery异步执行操作,在页面固定位置加载相关书本的详细内容。$(".delete").click(function(){$.ajax(//..)}),但是一旦js不可用,或者jQuery无发加载的时候,用户将无法顺利执行操作。因此,可以为该操作设置herf属性,当$.ajax()可用时阻止直接跳转,而使用异步;当$.ajax()不可用时,直接跳转到详细信息的页面。
4)避免依赖脚本验证表单。服务器的表单验证不可避免。
5)部分浏览器不支持html5新标签,因此,可以用js创建相关标签,然后给它们的css赋予相关属性。
6)因为iPhone并没有鼠标指针,所以没有hover事件。那么CSS :hover伪类就没用了。但是iPhone有Touch事件,onTouchStart 类似 onMouseOver,onTouchEnd 类似 onMouseOut。所以我们可以用它来模拟hover。使用Javascript:
var myLinks = document.getElementsByTagName('a'); for(var i = 0; i < myLinks.length; i++){ myLinks[i].addEventListener(’touchstart’, function() {
this.className = “hover”;}, false); myLinks[i].addEventListener(’touchend’, function(){this.className = “”;}, false); }
然后用CSS增加hover效果:
a:hover, a.hover { /* 你的hover效果 */ }
- 你会使用哪些技术和处理方法?
- 有哪些的隐藏内容的方法(如果同时还要保证屏幕阅读器可用呢?)
需要隐藏内容的几种可能性:
1)对文本的隐藏
2)隐藏超链接(另类黑链)
3)对统计代码隐藏
4)隐藏超出图片
5)css隐藏滚动条
6)css隐藏div层
具体实现:
1、css隐藏DIV及内容,完全隐藏内容与布局。display:none或者visibility:hidden
(面试官也许会问到:关于display:none和visible:hidden区别)
display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别:
display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就是看不见也摸不到。
visible:hidden--- 使对象在网页上不可见,但该对象在网页上所占的空间没有改变,通俗来说就是看不见但摸得到。
2、通过对象盒子设置缩进样式(text-indent:-9999px)方法可以隐藏超链接文本内容
同样道理,可以用来隐藏图片上方文字。此类问题我们常见于LOGO处使用,我们想让图片作为背景,而图片上方放A链接文字内容,但html锚文本功能仍然正常也能鼠标点击使用。图片作为背景而html代码内看不到图片,但文字也存在,却是文字隐藏图片显示出,鼠标也能点击指向。
3、overflow: hidden 隐藏溢出DIV内容或图片
4、css隐藏滚动条
使用overflow-y:hidden;和overflow-x:hidden来隐藏或显示对应横或竖方向的滚动条。
- 你用过栅格系统吗?如果使用过,你最喜欢哪种?
“网格系统”,运用固定的格子设计版面布局,其风格工整简洁。
“使用栅格系统的网页设计,非常的有条理性;看上去也很舒服。最重要的是,它给整个网站的页面结构定义了一个标准。对于视觉设计师来说,他们不用再为设计一个网站每个页面都要想一个宽度或高度而烦恼了。对于前端开发工程师来说,页面的布局设计将完全是规范的和可重用的,这将大大节约了开发成本。对于内 容编辑或广告销售来说,所有的广告都是规则的,通用的,他们再也不用做出一套N张不同尺寸的广告图了”
Bootstrap内置了一套响应式、移动设备优先的流式栅格系统,随着屏幕设备或视口(viewport)尺寸的增加,系统会自动分为最多12列。它包含了易于使用的预定义classe,还有强大的mixin用于生成更具语义的布局。
- 你用过媒体查询,或针对移动端的布局/CSS 吗?
针对http://topview123.sinaapp.com/细说
设备宽度(device-width)未必是布局宽度(width),为了让非适应性布局与手机相适应,我们跟关心视图宽度,因此需要一种方式来设定宽度,这样可以使用媒体查询检测。
让视图的宽度和设备宽度一致
<meta element = "viewport" content = "width=device initial-scale = 1" >
每种布局,都应该根据目标设备指定固定宽度设计
@media screen and (max-320px){}
为移动设备调整网页图像。在最基本的页面,一个移动优化的网站就是其布局、内容、互动都经过调整,以适应移动环境。最常见的做法是使用css媒体查询的功能为不同大小的屏幕提供不同的风格;为较小的屏幕优化布局,可以通过针对移动设备的模块服务。
不同设备的分离设计->根据监视屏幕大小进行设计->(媒体查询,灵活排版,图像结合)
- 如何优化网页的打印样式?
http://www.jb51.net/web/70358.html
- 在书写高效 CSS 时会有哪些问题需要考虑?
1)reset。参照上题“描述下 “reset” CSS 文件的作用和使用它的好处”的答案。
2)规范命名。尤其对于没有语义化的html标签,例如div,所赋予的class值要特别注意。
2)抽取可重用的部件,注意层叠样式表的“优先级”。
- 使用 CSS 预处理器的优缺点有哪些?(SASS,Compass,Stylus,LESS)
(这里我会实话实说)过去一直没有机会接触“预处理器”,缺的不是学习的热情和动力,而是一种会使用到这门高深技术的需求,希望日后参与的项目将会用到这门技术,能够将学习揉入实际开发中。关于CSS 预处理器,我知道是一种语言用来为 CSS 增加一些编程的的特性,无需考虑浏览器的兼容性问题,例如你可以在 CSS 中使用变量、简单的程序逻辑、函数等等在编程语言中的一些基本技巧,可以让你的 CSS 更见简洁,适应性更强,代码更直观等诸多好处。
- 描述下你曾经使用过的 CSS 预处理的优缺点。
- 如果设计中使用了非标准的字体,你该如何去实现?
1)图片替代
2)好是跟产品沟通,尽量使用默认就有的字体。虽然我们可以用webfonts,但它在页面加载的时候会将整个字体包都下载下来,这对于手机端网页来说无疑是致命的。如果产品一定要用非标准字体,可用这个软件FontCreator,可以从一个字体包中将你这个页面需要的那几个字提取出来,打成一个新的字体包,这样会节省很多流量
- Webfonts (字体服务例如:Google Webfonts,Typekit 等等。)
- 解释下浏览器是如何判断元素是否匹配某个 CSS 选择器?
浏览器会根据css rules 与dom tree 生成render tree。浏览器先产生一个元素集合,这个集合往往由最后一个部分的索引产生(如果没有索引就是所有元素的集合)。然后向上匹配,如果不符合上一个部分,就把元素从集合中删除,直到真个选择器都匹配完,还在集合中的元素就匹配这个选择器了。
举个例子,有选择器:
body.ready #wrapper > .lol233
先把所有 class 中有 lol233 的元素拿出来组成一个集合,然后上一层,对每一个集合中的元素,如果元素的 parent id 不为 #wrapper 则把元素从集合中删去。 再向上,从这个元素的父元素开始向上找,没有找到一个 tagName 为 body 且 class 中有 ready 的元素,就把原来的元素从集合中删去。
至此这个选择器匹配结束,所有还在集合中的元素满足。
大体就是这样,不过浏览器还会有一些奇怪的优化。为什么从后往前匹配因为效率和文档流的解析方向。
1)效率,找元素的父亲和之前的兄弟比遍历所有儿子快而且方便。
2)关于文档流的解析方向,是因为现在的 CSS,一个元素只要确定了这个元素在文档流之前出现过的所有元素,就能确定他的匹配情况。应用在即使 html 没有载入完成,浏览器也能根据已经载入的这一部分信息完全确定出现过的元素的属性。
为什么是用集合主要也还是效率。基于 CSS Rule 数量远远小于元素数量的假设和索引的运用,遍历每一条 CSS Rule 通过集合筛选,比遍历每一个元素再遍历每一条 Rule 匹配要快得多。
- 解释一下你对盒模型的理解,以及如何在 CSS 中告诉浏览器使用不同的盒模型来渲染你的布局。
网页设计中常听的属性名:内容(content)、填充(padding)、边框(border)、边界(margin),CSS盒子模式都具备这些属性。
每个盒子都有:边界、边框、填充、内容四个属性;
每个属性都包括四个部分:上、右、下、左;这四部分可同时设置,也可分别设置;
- 请解释一下 * { box-sizing: border-box; } 的作用, 并且说明使用它有什么好处?
说到 IE 的 bug,在 IE6以前的版本中,IE对盒模型的解析出现一些问题,跟其它浏览器不同,将 border 与 padding 都包含在 width 之内。而另外一些浏览器则与它相反,是不包括border和padding的。对于IE浏览器,当我们设置 box-sizing: content-box; 时,浏览器对盒模型的解释遵从我们之前认识到的 W3C 标准,当它定义width和height时,它的宽度不包括border和padding;对于非IE浏览器,当我们设置box-sizing: border-box; 时,浏览器对盒模型的解释与 IE6之前的版本相同,当它定义width和height时,border和padding则是被包含在宽高之内的。内容的宽和高可以通过定义的“width”和 “height”减去相应方向的“padding”和“border”的宽度得到。内容的宽和高必须保证不能为负,必要时将自动增大该元素border box的尺寸以使其内容的宽或高最小为0。
使用 * { box-sizing: border-box; }能够统一IE和非IE浏览器之间的差异。
- 请罗列出你所知道的 display 属性的全部值
display 属性规定元素应该生成的框的类型。
- 请解释一下 inline 和 inline-block,block 的区别?
都是display 属性规定元素应该生成的框的类型。但是block代表块级元素,元素前后都有换行符;inline是默认的样式,表示该元素被显示为内联元素,元素前后没有换行符号。也就是说,block元素通常被现实为独立的一块,会单独换一行;inline元素则前后不会产生换行,一系列inline元素都在一行内显示,直到该行排满。而inline-block代表行内块元素(css2.0新增)。
display:block
1)block元素会独占一行,多个block元素会各自新起一行。默认情况下,block元素宽度自动填满其父元素宽度。
2)block元素可以设置width,height属性。块级元素即使设置了宽度,仍然是独占一行。
3)block元素可以设置margin和padding属性。
display:inline
1)inline元素不会独占一行,多个相邻的行内元素会排列在同一行里,直到一行排列不下,才会新换一行,其宽度随元素的内容而变化。
2)inline元素设置width,height属性无效。
3)inline元素的margin和padding属性,水平方向的padding-left, padding-right, margin-left, margin-right都产生边距效果;但竖直方向的padding-top, padding-bottom, margin-top, margin-bottom不会产生边距效果。
display:inline-block
简单来说就是将对象呈现为inline对象,但是对象的内容作为block对象呈现。之后的内联对象会被排列在同一行内。比如我们可以给一个link(a元素)inline-block属性值,使其既具有block的宽度高度特性又具有inline的同行特性。
- 请解释一下 relative、fixed、absolute 和 static 元素的区别
在用CSS+DIV进行布局的时候,一直对position的四个属性值relative,absolute,static,fixed分的不是很清楚,以致经常会出现让人很郁闷的结果。今天研究了一下,总算有所了解。在此总结一下:
先看下各个属性值的定义:
1、static:默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
2、relative:生成相对定位的元素,通过top,bottom,left,right的设置相对于其正常位置进行定位。可通过z-index进行层次分级。
3、absolute:生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。
4、fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。可通过z-index进行层次分级。
static与fixed的定位方式较好理解,在此不做分析。下面对应用的较多的relative和absolute进行分析:
1、relative。定位为relative的元素脱离正常的文本流中,但其在文本流中的位置依然存在。
黄色背景的层定位为relative,红色边框区域为其在正常流中的位置。在通过top、left对其定位后,从灰色背景层的位置可以看出其正常位置依然存在。
2、absolute。定位为absolute的层脱离正常文本流,但与relative的区别是其在正常流中的位置不在存在。在将黄色背景层定位为absolute后,灰色背景层自动补上。
3、relative与absolute的主要区别:
首先,是上面已经提到过的在正常流中的位置存在与否。
其次,relative定位的层总是相对于其最近的父元素,无论其父元素是何种定位方式。红色背景层为relative定位,其直接父元素绿色背景层为默认的static定位。红色背景层的位置为相对绿色背景层top、left个20元素。而如果红色背景层定位为absolute。红色背景层依然定义top:20px;left:20px;但其相对 的元素变为定位方式为absolute或relative的黄色背景层。因此,对于absolute定位的层总是相对于其最近的定义为absolute或 relative的父层,而这个父层并不一定是其直接父层。如果其父层中都未定义absolute或relative,则其将相对body进行定位。
除top、left、right、bottom定位外,margin属性值的定义也符合上述规则。
static与定位用的比较少,也比较简单,在此不做分析。
下面对应用的较多的relative和absolute与fixed进行分析:
relative定位的层总是相对于其最近的父元素,无论其父元素是何种定位方式。
absolute定位的层总是相对于其最近的定义为absolute或relative的父层,而这个父层并不一定是其直接父层。如果其父层中都未定义absolute或relative,则其将相对body进行定位,
fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。
- 你目前在使用哪一套CSS框架,或者在产品线上使用过哪一套?(Bootstrap, PureCSS, Foundation 等等)
- 如果有,请问是哪一套?如果可以,你如何改善CSS框架?
- 请问你有使用过 CSS Flexbox 或者 Grid specs 吗?
http://www.w3cplus.com/css3/a-guide-to-flexbox.html
http://zh.learnlayout.com/flexbox.html
- 如果有,请问在性能和效率的方面你是怎么看的?
- 为什么响应式设计(responsive design)和自适应设计(adaptive design)不同?
自适应布局(Adaptive Layout)
自适应布局(Adaptive)的特点是分别为不同的屏幕分辨率定义布局。布局切换时页面元素发生改变,但在每个布局中,页面元素不随窗口大小的调整发生变化。就是说你看到的页面,里面元素的位置会变化而大小不会变化;
你可以把自适应布局看作是静态布局的一个系列。
流式布局(Liquid Layout)
流式布局(Liquid)的特点(也叫"Fluid") 是页面元素的宽度按照屏幕进行适配调整,主要的问题是如果屏幕尺度跨度太大,那么在相对其原始设计而言过小或过大的屏幕上不能正常显示。
响应式布局(Responsive Layout)
分别为不同的屏幕分辨率定义布局,同时,在每个布局中,应用流式布局的理念,即页面元素宽度随着窗口调整而自动适配。
可以把响应式布局看作是流式布局和自适应布局设计理念的融合。
JS相关问题:
- 解释下事件代理。
在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器。然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越大。JavaScript事件代理则是一种简单的技巧,通过它你可以把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。
事件代理用到了两个在JavaSciprt事件中常被忽略的特性:事件冒泡以及目标元素。当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层。任何一个事件的目标元素都是最开始的那个元素,在我们的这个例子中也就是按钮,并且它在我们的元素对象中以属性的形式出现。使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。
1 // 获取父节点,并为它添加一个click事件 2 document.getElementById("parent-list").addEventListener("click",function(e) { 3 // 检查事件源e.targe是否为Li 4 if(e.target && e.target.nodeName.toUpperCase == "LI") { 5 // 真正的处理过程在这里 6 console.log("List item ",e.target.id.replace("post-")," was clicked!"); 7 } 8 });
这样做的好处:那些需要创建的以及驻留在内存中的事件处理器少了,这样我们就提高了性能,并降低了崩溃的风险。在DOM更新后无须重新绑定事件处理器了。如果你的页面是动态生成的,比如说通过Ajax,你不再需要在元素被载入或者卸载的时候来添加或者删除事件处理器了。
- 解释下 JavaScript 中 this 是如何工作的。
this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。匿名函数或不处于任何对象中的函数指向 window 。函数中的this的值取决于函数调用的模式:
方法调用模式
当函数被保存为对象的一个属性时,成该函数为该对象的方法。函数中this的值为该对象。
var foo = { name: 'fooname', getName: function (){ return this.name } } foo.getName(); // this => foo
函数调用模式
当函数并不是对象的属性。函数中this的值为全局对象
note:某个方法中的内部函数中的this的值也是全局对象,而非外部函数的this
function foo(){ this.name = 'fooname'; } foo(); // this => window
构造器调用模式
即使用new调用的函数,则其中this将会被绑定到那个新构造的对象。构造器调用将一个全新的对象作为this变量的值,并隐式返回这个新对象作为调用结果。
function Foo(){ this.name = 'fooname'; } var foo = new Foo(); // this => foo
如果你不是使用new来调用构造器,那其实你就是在使用一个实函数。因此this就不会是你预期的值。在Sloppy模式中,this 指向的就是window 而你将会创建全局变量。不过如果使用的是strict模式,那你还是会得到警告(this===undefined)。
使用apply或call调用模式
该模式调用时,函数中this被绑定到apply或call方法调用时接受的第一个参数。
function getName(name){ this.name = name; } var foo = {}; getName.call(foo, name); // this =>foo
在方法中this 的用法更倾向于传统的面向对象语言:this 指向的接收方,也就是包含有这个方法的对象。
箭头函数就是没有自己的this 的函数。在这样的函数中你可以随便使用this,也不用担心有没有隐式的存在。下面提供了三种思路来解决这个问题:
1)that=this,将this 赋值到一个变量上,这样就把this 显性地表现出来了(除了that,self 也是个很常见的用于存放this的变量名),之后就使用那个变量。
2)bind()。使用bind()来创建一个函数,这个函数的this 总是存有你想要传递的值(下面这个例子中,方法的this):
this.friends.forEach(function (friend) { console.log(this.name+' knows '+friend); }.bind(this));
3)用forEach的第二个参数。forEach的第二个参数会被传入回调函数中,作为回调函数的this 来使用。
this.friends.forEach(function (friend) { console.log(this.name+' knows '+friend); }, this);
- 解释下原型继承的原理。
在javascript中,类(定义类是模块开发和重用代码的有效方式之一)的实现是基于其原型继承机制的。如果两个实例都从一个原型对象上继承了属性,我们说它们是同一个类的实例。如果两个对象继承自同一个原型,往往意味着(但不是绝对)它们是由同一个构造函数创建并初始化的。
1)类和对象
在javascript中,类的所有实例对象都从一个类型对象上继承属性。因此,原型对象是类的核心。
2)类和构造函数
构造函数是用来初始化和创建对象的。使用new关键字来调用构造函数,创建一个新对象。调用构造函数的一个重要特征是,构造函数的prototype属性被用做新对象的原型(var object.prototype = new Object())。这意味着通过同一个构造函数创建的对象都是继承自一个相同的对象,因此它们都是一个类的成员。
javascript中的类牵扯三种不同的对象,三种对象的属性的行为和下面三种类成员非常相似:
构造函数对象
Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,判断一个函数F是否是Object对象的实例:F.prototype instanceof Object //->true
原型对象属性被类的所有实例所继承,如果原型对象的属性值是函数的话,这个函数就作为类的实例方法来调用
实例对象,类的每个实例对象都是一个独立的对象,直接 给这个实例定义的属性是不会为所有实例对象锁共享的。定义在实例上的非函数属性,实际上是实例的字段。
在javascript中定义类的步奏可以缩减为一个分三步的算法。第一步,先定义一个构造函数,并设置初始化新对象的实例属性。第二步,给构造函数的prototype对象定义实例的方法。第三步:给构造函数定义类字段和类属性。
(面试官可能会问到“javascript继承和其他语言继承的区别”,可以从基于对象和访问修饰符分析)
javascript中基于原型的继承机制是动态的:对象从其原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。这意味着我们可以通过给原型对象添加新的方法来扩充javascript类。
- 你是如何测试 JavaScript 代码的?
1)使用浏览器自带的控制台调试,详细可参照“使用console进行 性能测试 和 计算代码运行时间”
2)chrome的单步调试功能
JavaScript 断点设置和调试功能和java编辑工具的调试方法类似
- *AMD vs. CommonJS?
CommonJs 是服务器端模块的规范,Node.js采用了这个规范。根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。
//require方法默认读取js文件,所以可以省略js后缀 var test = require('./boobar').foobar; //test为boobar文件中的foobar对象的实例 test.bar(); //调用方法bar()
CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Node.js主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。
AMD CMD 采用异步模式,方便浏览器环境要从服务器加载模块。AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。AMD异步加载模块。它的模块支持对象、函数、构造器、字符串、JSON等各种类型的模块。适用AMD规范适用define方法定义模块。
//通过数组引入依赖 ,回调函数通过形参传入依赖 define(['someModule1', ‘someModule2’], function (someModule1, someModule2) { function foo () { /// something someModule1.test(); } return {foo: foo} });
本题内容整理自:http://my.oschina.net/felumanman/blog/263330?p=1
- 什么是哈希表?
类比数组,数组是编程上的哈希表,哈希表是一种数据结构,关键点就是用一个key值来取对应数据,就像数组的下标。
https://github.com/floraLam/dailyLearn/blob/master/dataStructure/31哈希表.html
- 解释下为什么接下来这段代码不是 IIFE(立即调用的函数表达式):function foo(){ }();.
而函数定义(语句以function关键字开始)是不能被立即执行的,这无疑会导致语法的错误(SyntaxError)。当函数定义代码段包裹在括号内,使解析器可以将之识别为函数表达式,然后调用。IIFE:(function foo(){})()
之前面试,遇到问题,区分(function(){})();和(function(){}());其实两者实现效果一样。
函数字面量:首先声明一个函数对象,然后执行它。(function () { alert(1); })(); 优先表达式:由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数。(function () { alert(2); }());
- 描述以下变量的区别:null,undefined 或 undeclared?
'undefined'是未定义,在变量没有赋值的时候的值即为undefined。"缺少值",就是此处应该有一个值,但是还没有定义。
'underclared'即为被污染的命名,访问没有被声明的变量,会抛出异常,终止执行。
'null'是一个空的对象引用。"没有对象",即该处不应该有值
undefined和null在if语句中,都会被自动转为false,相等运算符甚至直接报告两者相等。typeof undefined会返回undefined ,而typeof null 总返回 object(typeof有六种可能:"number"、"string"、"boolean"、"object"、"function"、"undefined")
false == undefined;//false false == null;//false null == undefined;//true
- 什么是闭包,如何使用它,为什么要使用它?
当某个函数调用时会创建一个执行环境以及作用域链,然后根据arguments和其它命名参数初始化形成活动对象。在外部函数调用结束后,其执行环境与作用域链被销毁,但是其活动对象保存在了闭包之中,最后在闭包函数调用结束后才销毁。简单的说,闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
注意:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
用法
//第1种写法 :这种写法没什么特别的,只是给函数添加一些属性。 function Circle(r) { this.r = r; } Circle.PI = 3.14159; Circle.prototype.area = function() { return Circle.PI * this.r * this.r; } var c = new Circle(1.0); alert(c.area()); //第2种写法 :这种写法是声明一个变量,将一个函数当作值赋给变量。 var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); //第3种写法 :这种方法最好理解,就是new 一个对象,然后给对象添加属性和方法。 var Circle = new Object(); Circle.PI = 3.14159; Circle.Area = function( r ) { return this.PI * r * r; } alert( Circle.Area( 1.0 ) ); //第4种写法 :这种方法使用较多,也最为方便。var obj = {}就是声明一个空的对象。 var Circle={ "PI":3.14159, "area":function(r){ return this.PI * r * r; } }; alert( Circle.area(1.0) );
闭包的用途
事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。
1)匿名自执行函数
全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。
除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,我们可以使用闭包。
我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象。
2)结果缓存
我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
3)封装
4)实现类和继承
- 你喜欢的使用闭包的模式是什么?两种模式用在不同场合。参见jQuery源码,立即调用模式,把$的jQuery源码放在了全局作用域下。返回函数类型的,制作一个随时可以使用的函数。
- 请举出一个匿名函数的典型用例?
$.("input").each(function(e){this.val('OK')});
- ------------------------------解释 “JavaScript 模块模式” 以及你在何时使用它。
我们在做radf库的时候,把所有的函数写在var function = radf(){}里,为的是在全局作用域下,只有一个radf对象,所有的属性和方法全在radf命名空间下面。这样就是一个无污染的环境。
- 如果有提到无污染的命名空间,可以考虑加分。
- 如果你的模块没有自己的命名空间会怎么样?
- 与其它库或内容造成冲突。
- 如果有提到无污染的命名空间,可以考虑加分。
- 如果你的模块没有自己的命名空间会怎么样?
- 你是如何组织自己的代码?是使用模块模式,还是使用经典继承的方法?
在模块模式中使用继承。例如我们的库中有pannel布局型组件和data型组件,其余都依照这两个基本组件继承而来。
具体可以参考 ExtJS4 便捷三层开发模式
- 请指出 JavaScript 宿主对象和原生对象的区别?
原生对象,独立于宿主环境的 ECMAScript 实现提供的对象。为array obj regexp date function等可以new实例化的对象。
内置对象为gload Math 等,开发者不必明确实例化内置对象,它已被实例化了。类似于isNaN()、parseInt()和parseFloat()方法等,看起来都是函数,而实际上,它们都是Global对象的方法。具体可以参考 JavaScript 全局对象
宿主对象。即由 ECMAScript 实现的宿主环境(操作系统和浏览器)提供的对象。所有的BOM和DOM对象都是宿主对象。因为其对于不同的“宿主”环境所展示的内容不同(这就是兼容性和特性检测的缘由)。ECMAScript官方未定义的对象都属于宿主对象。
- 指出下列代码的区别:
function Person(){}
var person = Person();
var person = new Person();
1、定义一个函数为Person()
2、定义一个匿名函数指向person
3、实例化一个person、原型来自于函数Person
- .call 和 .apply 的区别是什么?
call和apply都是调用一个对象的一个方法,以另一个对象替换当前对象。它们都属于Function.prototype的一个方法,所以每个function实例都有call和apply属性。这两个方法可以用来代替另一个对象调用一个方法,可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
区别在于,两者传递的参数不同,虽然函数第一个参数都是要传入给当前对象的对象,但是,apply的第二个参数是一个参数数组,将多个参数组合成为一个数组传入;而call第二个参数则是直接的参数列表。
- 请解释 Function.prototype.bind?
Function.prototype.bind()其实就是函数绑定。函数的接收者取决于他是如何被调用,可以通过调用.bind()给函数绑定作用域上下文,即函数的接收者。
var foo = { x: 3} var bar = function(){console.log(this.x);} bar(); // undefined var boundFunc = bar.bind(foo);//隐式看作是在foo作用域里调用bar方法 boundFunc(); // 3
我们创建了一个新的函数,当它被执行的时候,它的 this 会被设置成 foo —— 而不是像我们调用 bar() 时的全局作用域。
对于改变上下文作用域(具体可以查看上题“解释下 JavaScript 中 this 是如何工作的”),可以将this设置到一个变量上,这样改变了上下文之后继续引用到它。同时可以选择 self, _this 或者 context 作为变量名称(也有人使用 that)。
.bind()创建了一个函数,当这个函数在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)也就是我们传入想要的上下文。
简单的用法:
关于 Function.prototype.bind() 内部,这里有个非常简单的例子:
Function.prototype.bind = function (scope) { var fn = this; return function () { return fn.apply(scope);//使用call效果一样 }; }
- 你何时优化自己的代码?
优化代码是在不改变程序行为的基础上进行小的改动,是代码逐渐改善的过程。移除长期累积下来的烂码,以得到更清晰和更容易维护,除错以及添加新功能的代码,这做法不能单纯只出现在编码的后期,甚至是你意识到你的代码已经无从再下手非重写不可的时候,而是从开始开发起,逐渐积累,逐渐修改。以前因为日常编码的随意性,导致问题日益积累,逐步扩散,最后只能推倒重来。如果时间经受不起推倒重来,你别无选择,唯一实现的选择就是重构。整体的优化设计虽然惹人注目令人难忘,但没有平日的积累,何以收获庞大的成就?你的目标应该是让代码每天都有新变化。坚持几个月,我相信我们都能拥有骄傲地,清晰代码。
- 在什么时候你会使用 document.write()?
记住,在载入页面后,浏览器输出流自动关闭。在此之后,任何一个对当前页面进行操作的document.write()方法将打开—个新的输出流,它将清除当前页面内容(包括源文档的任何变量或值)。因此,假如希望用脚本生成的HTML替换当前页面,就必须把HTML内容连接起来赋给一个变量,使用一个document.write()方法完成写操作。不必清除文档并打开一个新数据流,一个document.write()调用就可完成所有的操作。
关于document.write()方法还有一点要说明的是它的相关方法document.close()。脚本向窗口(不管是本窗口或其他窗口)写完内容后,必须关闭输出流。在延时脚本的最后一个document.write()方法后面,必须确保含有document.close()方法,不这样做就不能显示图像和表单。并且,任何后面调用的document.write()方法只会把内容追加到页面后,而不会清除现有内容来写入新值。为了演示document.write()方法,我们提供了同一个应用程序的两个版本。
- 大多数生成的广告代码依旧使用 document.write(),虽然这种用法会让人很不爽。
- 请指出浏览器特性检测,特性推断和浏览器 UA 字符串嗅探的区别?
检测浏览器的特殊名称和版本(用户代理检测)即浏览器UA字符串嗅探。浏览器嗅探技术可以快捷的将代码进行分支,以便针对不同的浏览器应用不同的指令;针对特定浏览器的特定版本,超出范围之外都是不可靠的
if (navigator.userAgent.indexOf("MSIE 7") > -1){
//do something
}
var sUserAgent = navigator.userAgent; //检测Opera、KHTML var isOpera = sUserAgent.indexOf(“Opera”) > -1; var isKHTML = sUserAgent.indexOf(“KHTML”) > -1 || sUserAgent.indexOf(“Konqueror”) > -1 || sUserAgent.indexOf(“AppleWebKit”) > -1; //检测IE、Mozilla var isIE = sUserAgent.indexOf(“compatible”) > -1 && sUserAgent.indexOf(“MSIE”) > -1 && !isOpera; var isMoz = sUserAgent.indexOf(“Gecko”) > -1 && !isKHTML; //检测操作系统 var isWin = (navigator.platform == “Win32″) || (navigator.platform == “Windows”); var isMac = (navigator.platform == “Mac68K”) || (navigator.platform == “MacPPC”) || (navigator.platform == “Macintosh”); var isUnix = (navigator.platform == “X11″) && !isWin && !isMac;
检测浏览器的特性(特性检测)
if(document.all){
//do something
}
另外IE独有children,parentElement,innerText,outerText,outerHTML,FF没有;
直接进行特性检测是个很好的方法,并且大部分情况下能满足需求。一般只要在检测前知道这个特性是否被实现即可,而不会去考虑它们之间的关系。
另外,针对CSS3中新特性@font-face、border-radius、 border-image、box-shadow、rgba() 等,HTML5的特性——比如audio、video、本地储存、和新的 <input>标签的类型和属性等,必要时要进行优雅降级。
- 请尽可能详尽的解释 AJAX 的工作原理。
非ajax是把要提交的内容放在submit里面,浏览器刷新提交数据。ajax即异步数据刷新,将要提交的数据与服务器接口交换数据,将得到的数据返回用于重组dom元素,以及改变一些页面效果。
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。
XMLHttpRequest是ajax的核心机制,它是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是javascript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
简单地说,我们可以把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,可以是Html,可以是Javascript代码,也可以只是一个字符串。这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,客户端在异步获取这个结果后,不是直接显示在页面,而是先由javascript来处理,然后再显示在页面。
- 请解释 JSONP 的工作原理,以及它为什么不是真正的 AJAX。
JSONP动态创建script标签,回调函数。Ajax是页面无刷新请求数据操作
动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了。当GET请求从被调用页面返回时,可以返回一段JavaScript代码,这段代码会自动调用主页面中的一个callback函数。
Jsonp优点不受同源策略的影响,它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果
Jsonp缺点,它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
- 你使用过 JavaScript 模板系统吗?
没用过,但是知道:在生成各种页面内容结合javascript模板技术,能让逻辑和数据之间更加清晰。逻辑是写在"<%"与"%>"之间,如果是注释,则用"<%#"与"%>",后台传过来的变量使用@来标记。
- 如有使用过,请谈谈你都使用过哪些库,比如 Mustache.js,Handlebars 等等。
- 请解释变量声明提升。
javascript不支持块级作用域,即变量定义的作用域并不是离其最近的封闭语句或代码块,而是包含它的函数:
var foo = 1; function bar() { if (!foo) {var foo = 10;} alert(foo);//10 } bar();
var a = 1; function b() {a = 10;return;function a() {}} b();alert(a);//1
对于被函数作用域包围的变量的作用域为函数,函数内部访问变量,将会返回函数体内最近的变量值;函数外部访问变量将会函数体外所声明的变量值。
也但是,对于被if语句包裹的代码段,不能看作是另外一个独立的作用域,也就是说,对于被非函数的{}所包围的代码段内所定义的变量,变量的声明将会提升到{}所在的作用域。
function f(){{var x =0;}}等同于function f(){var x ;{x =0;}}
function foo() {bar();var x = 1;}会被解释为function foo() {var x;bar();x = 1;}
变量赋值并没有被提升,只是声明被提升了。但是,函数的声明有点不一样,函数体也会一同被提升。但是请注意,函数的声明有两种方式:
function test() { foo(); // TypeError "foo is not a function" bar(); // "this will run!" var foo = function () { // 变量指向函数表达式 alert("this won't run!"); } function bar() { // 函数声明 函数名为bar alert("this will run!"); } } test();
对于var a=1; function a(){ } alert(a);function a(){ } var a=1; alert(a);都是会打印出1
对于全局作用于范围的变量,var与不var是有区别的. 没有var的写法,其变量不会被提升。比如下面的程序会报错:alert(a);a=1;
eval中创建的局部变量是不会被提升var a = 1;function t(){console.info(a);eval('var a = 2');console.info(a);}t();console.info(a);结果按照顺序为1,2,1
- 请描述下事件冒泡机制。
从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。
- "attribute" 和 "property" 的区别是什么?
DOM元素的attribute和property两者是不同的东西。attribute翻译为“特性”,property翻译为“属性”。
attribute是一个特性节点,每个DOM元素都有一个对应的attributes属性来存放所有的attribute节点,attributes是一个类数组的容器,说得准确点就是NameNodeMap,不继承于Array.prototype,不能直接调用Array的方法。attributes的每个数字索引以名值对(name=”value”)的形式存放了一个attribute节点。<div class="box" id="box" gameid="880">hello</div>
property就是一个属性,如果把DOM元素看成是一个普通的Object对象,那么property就是一个以名值对(name=”value”)的形式存放在Object中的属性。要添加和删除property和普通的对象类似。
很多attribute节点还有一个相对应的property属性,比如上面的div元素的id和class既是attribute,也有对应的property,不管使用哪种方法都可以访问和修改。
总之,attribute节点都是在HTML代码中可见的,而property只是一个普通的名值对属性。
- 为什么扩展 JavaScript 内置对象不是好的做法?
因为你不知道哪一天浏览器或javascript本身就会实现这个方法,而且和你扩展的实现有不一致的表现。到时候你的javascript代码可能已经在无数个页面中执行了数年,而浏览器的实现导致所有使用扩展原型的代码都崩溃了。
需要给Array原型添加一个distinct的方法,最好检查是否存在同名的方法,避免自定义方法覆盖原生方法:
Arrray.prototype.distinct = Arrray.prototype.distinct || function(){/*.....*/}
- 请指出 document load 和 document ready 两个事件的区别。
document.ready和onload的区别——JavaScript文档加载完成事件。页面加载完成有两种事件,一是ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件),二是onload,指示页面包含图片等文件在内的所有元素都加载完成。
jQuery中$(function(){/* do something*/});他的作用或者意义就是:在DOM加载完成后就可以可以对DOM进行操作。一般情况先一个页面响应加载的顺序是,域名解析-加载html-加载js和css-加载图片等其他信息。
- == 和 === 有什么不同?
”==”:判断值是否相等。应用一套难以理解的隐式强制转换规则。
”===”判断值及类型是否完全相等。读者不需要涉及任何的隐式转换。
注意:
1)如果两个值的类型不同,它们就不相同。
2)如果两个值是数字,而且值相同,那么除非其中一个或两个都是NaN(这种情况它们不是等同的),否则它们是等同的。值NaN永远不会与其他任何值等同,包括它自身(奇怪的家伙),要检测一个值是否是NaN,可以使用全局函数isNaN()。
3)如果两个值都是字符串,而且在串中同一位置上的字符完全相同,那么它们就完全等同。如果字符串的长度或内容不同,它们就不是等同的。
4)如果两个值都是布尔型true,或者两个值都是布尔型false,那么它们等同。
5)如果两个值引用的是同一个对象、数组或函数,那么它们完全等同。如果它们引用的是不同的对象(数组或函数),它们就不完全等同,即使这两个对象具有完全相同的属性,或两个数组具有完全相同的元素。
6)如果两个值都是null或都是undefined,“==”返回true,“===”返回false。
- 请解释一下 JavaScript 的同源策略。
同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。所谓同源是指,域名,协议,端口相同。如果我们又想利用XMLHTTP的无刷新异步交互能力,又不愿意公然突破Javascript的安全策略,可以选择的方案就是给XMLHTTP加上严格的同源限制。
同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
处理跨域方法:
1)document.domain+iframe的设置
2)动态创建script
3)利用iframe和location.hash
4)window.name实现的跨域数据传输
5)使用HTML5 postMessage
- 如何实现下列代码:
[1,2,3,4,5].duplicator(); // [1,2,3,4,5,1,2,3,4,5]
Array.prototype.duplicator = function(){
var l = this.length,i;
for(i=0;i<l;i++){
this.push(this[i])
}
}
- 什么是三元表达式?“三元” 表示什么意思?
三元运算符需要三个操作数。
语法是 条件 ? 结果1 : 结果2;. 这里你把条件写在问号(?)的前面后面跟着用冒号(:)分隔的结果1和结果2。满足条件时结果1否则结果2。
- 什么是 "use strict"; ? 使用它的好处和坏处分别是什么?
在所有的函数 (或者所有最外层函数) 的开始处加入 "use strict"; 指令启动严格模式。
"严格模式"有两种调用方法
1)将"use strict"放在脚本文件的第一行,则整个脚本都将以"严格模式"运行。如果这行语句不在第一行,则无效,整个脚本以"正常模式"运行。如果不同模式的代码文件合并成一个文件,这一点需要特别注意。
2)将整个脚本文件放在一个立即执行的匿名函数之中。
好处
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
坏处
同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行
jQuery 相关问题:
- 解释"chaining"。
Chaining 允许我们在一条语句中允许多个 jQuery 方法(在相同的元素上)。这样的话,浏览器就不必多次查找相同的元素。链式调用,这是因为jQuery内部在方法调用之后,都返回本身(在无状态的方法中返回新对象来支持方法链,有状态的方法中返回this来支持方法链)。虽然如此,但是如果直接把全部代码都写在一行,可读性会变差,不利于维护,因此要加上必要的缩进和换行。
$("#p1").css("color","red") .slideUp(2000) .slideDown(2000);
- 解释"deferreds"。
deferred对象就是jQuery的回调函数解决方案。deferred对象的含义就是"延迟"到未来某个点再执行。
对于那些某些耗时很长的javascript操作比如异步的操作(比如ajax读取服务器数据),和同步的操作(比如遍历一个大型数组),并不是马上能够得到结果,因此,为它们指定回调函数(callback)。
$.ajax("test.html").done(function(){ alert("成功!"); }).fail(function(){ alert("出错!"); });同时回调函数可以添加任意多个,它们按照添加顺序执行。
- 你知道哪些针对 jQuery 的优化方法。
1)总是从ID选择器开始继承
在jQuery中最快的选择器是ID选择器,因为它直接来自于JavaScript的getElementById()方法。当然 这只是对于单一的元素来讲。如果你需要选择多个元素,这必然会涉及到 DOM遍历和循环,为了提高性能,建议从最近的ID开始继承。如下所示:var traffic_lights = $(“#traffic_light input”)
可以使用console测试程序性能,比较id选择器和class选择器的效率。
2)在class前使用tag(标签名)
在jQuery中第二快的选择器是tag(标签)选择器( 比如:$(“head”) ),因为它来自原生的getElementsByTagName() 方法。
在使用tag来修饰class的时候,我们需要注意以下几点:
(1) 不要使用tag来修饰ID,如下所示:var content = $(“div#content”);这样一来,选择器会先遍历所有的div元素,然后匹配#content。
(2)不要使用ID来修饰ID,如下所示:var traffic_light = $(“#content #traffic_light”);
3)将jQuery对象缓存起来
把jQuery对象缓存起来,不要让相同的选择器在你的代码里出现多次。
注意:(1)为了区分普通的JavaScript对象和jQuery对象,可以在变量首字母前加上 $ 符号。
(2)代码可以使用jQuery的链式操作加以改善。
4)对直接的DOM操作进行限制
这里的基本思想是在内存中建立你确实想要的东西,然后更新DOM ,因为直接的DOM操作速度很慢。例如,动态的创建一组列表元素,尽量不要在循环中,调用append:
for (var i=0, l=top_100_list.length; i<l; i++){ $mylist.append("<li>" + top_100_list[i] + "</li>");}
而应该将整套元素字符串创建完毕后,再在插入进dom中
for (var i=0, l=top_100_list.length; i<l; i++){top_100_li += "<li>" + top_100_list[i] + "</li>";} $mylist.html(top_100_li);
5)冒泡
除非在特殊情况下, 否则每一个js事件(例如:click, mouseover等.)都会冒泡到父级节点。当我们需要给多个元素调用同个函数时这点会很有用。代替这种效率很差的多元素事件监听的方法就是, 你只需向它们的父节点绑定一次。
$("#entryform").bind("focus", function(e){//非单独获取#entryform中的input var $cell = $(e.target); // e.target 捕捉到触发的目标元素 $cell.addClass("selected"); }).bind("blur", function(e){ var $cell = $(e.target); $cell.removeClass("selected"); });
6)推迟到 $(window).load
$(document).rady 确实很有用, 它可以在页面渲染时,其它元素还没下载完成就执行。其实可以通过将jQuery函数绑定到$(window).load 事件的方法来减少页面载入时的cpu使用率。它会在所有的html(包括iframe)被下载完成后执行。一些特效的功能,例如拖放, 视觉特效和动画, 预载入隐藏图像等等,都是适合这种技术的场合。
7)压缩JavaScript
压缩之前,请保证你的代码的规范性(语句执行结束后添加分号),否则可能失败,导致Js错误。
8)给选择器一个上下文
jQuery选择器中有一个这样的选择器,它能指定上下文。jQuery( expression, context );
通过它,能缩小选择器在DOM中搜索的范围,达到节省时间,提高效率。
普通方式:$(‘.myDiv’)改进方式:$(‘.myDiv’ , $(“#listItem”) )
- 请解释 .end() 的用途。
end() 方法结束当前链条中的最近的筛选操作,并将匹配元素集还原为之前的状态。
大多数 jQuery 的遍历方法会操作一个 jQuery 对象实例,并生成一个匹配不同 DOM 元素集的新对象。当发生这种情况时,应该会把新的元素集推入维持在对象中的堆栈内。每次成功的筛选方法调用都会把新元素推入堆栈中。如果我们需要老的元素集,可以使用 end() 从堆栈中弹出新集合。但由于进行了额外的调用,会有一点点性能损失。
- 你如何给一个事件处理函数命名空间,为什么要这样做?
用 .bind('click.myCustomRoutine',function(){...}); 把匿名函数绑定到 click 事件(使用命名空间多次绑定不同的行为方法);使用.unbind('click.myCustomRoutine') 即可 释放所有绑定到 .myCustomRoutine 命名空间的 click 事件,而不会解除其他通过 .bind('click') 或另外的命名 空间所绑定的事件行为。
但是,考虑一种情况就是:需要在运行时根据用户交互的结果进行不同click事件处理逻辑的绑定,因而理论 上会无数次对某一个事件进行 bind / unbind 操作。但又希望 unbind 的时候只把自己绑上去的处理逻辑给释放掉而不是所有其他地方有 可能的额外的同一事件绑定逻辑。
这时候如果直接用 .click() / .bind('click') 加 上 .unbind('click') 来进行重复绑定的话,被unbind 掉的将是所有绑定在元素上的 click 处理逻辑,潜在会影响到该元素 其他第三方的行为。
对于这种问题,jQuery的解决方案是使用事件绑定的命名空间。即在事件名称后添加.something 来区分自己这部分行为逻辑范围。
- 请说出你可以传递给 jQuery 方法的四种不同值。
选择器(字符串),HTML(字符串),回调函数,HTML元素,对象,数组,元素数组,jQuery对象等。
- 什么是效果队列?
jQuery中有个动画队列的机制。当对一个对象添加多次动画效果时后添加的动作就会被放入这个动画队列中,等前面的动画完成后再开始执行。可是用户的操作往往都比动画快,如果用户对一个对象频繁操作时不处理动画队列就会造成队列堆积,影响到效果。
jQuery中有stop这个方法可以停止当前执行的动画,并且它有两个布尔参数,默认值都为false。第一个参数为true时会清空动画队列,第二个参数为true时会瞬间完成掉当前动画。;第二个参数为true,把当前在执行的动画跳转到完成状态。这时第一个参数如果也为true,后面的队列就会被清空。
- 请指出 .get(),[],eq() 的区别。
eq返回的是一个jquery对象 get返回的是一个html 对象数组。
进一步说,返回的是jQuery对象,就可以继续调用其他方法,返回的是html数组就不能调用jQuery的其他方法,例如:
$("ul li").eq(1).css("color", "red"); //这个是正确的
$("ul li").get(1).css("color", "red"); //这个是错误的
当$()所获取的对象不存在,即为[]时,get()返回undefined,而eq()返回m.fn.init[0],jQuery文档对象。
- 请指出 .bind(),.live() 和 .delegate() 的区别。
对于bind():$('a').bind('click',function(){alert('That tickles!');})jQuery扫描文档找出所有的$(‘a')元素,并把alert函数绑定到每个元素的click事件上。
对于live():$('a').live('click',function(){alert('That tickles!')})jQuery把alert函数绑定到$(document)元素上,并使用'click'和'a'作为参数。任何时候只要有事件冒泡到document节点上,它就查看该事件是否是一个click事件,以及该事件的目标元素与'a'这一CSS选择器是否匹配,如果都是的话,则执行函数。
对于.delegate() :$('#container').delegate('a','click',function(){alert('That tickles!')})jQuery扫描文档查找$('#container'),并使用click事件和'a'这一CSS选择器作为参数把alert函数绑定到$('#container')上。任何时候只要有事件冒泡到$('#container')上,它就查看该事件是否是click事件,以及该事件的目标元素是否与CSS选择器相匹配。如果两种检查的结果都为真的话,它就执行函数。
bind看上去更加明确直接,但是delegate和live执行的效率会更高。
bind首先要扫描整个的文档查找所有的$(‘a')元素,把它们存成jQuery对象。尽管live函数仅需要把'a'作为串参数传递以用做之后的判断,但是$()函数并未“知道”被链接的方法将会是.live()。
delegate方法仅需要查找并存储$(document)元素。 一种寻求避开这一问题的方法是调用在$(document).ready()之外绑定的live,这样它就会立即执行。在这种方式下,其会在DOM获得填充之前运行,因此就不会查找元素或是创建jQuery对象了。
- 请指出 $ 和 $.fn 的区别,或者说出 $.fn 的用途。
jQuery对方法的拓展,从调用声明创建方法的方式来看,可以归结为两类:一类直接由$符调用;另一类由$("")来调用。$拓展的方法是静态方法,可以使用$直接调用,其拓展的方式一般使用$.extend({});;而$.fn拓展的方法是实例方法,必须由“对象”$("")来调用,一般使用$.fn.extend({ })。
$.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效。 如扩展$.fn.abc() ;使用:$("#div").abc(); 。
- 请优化下列选择器:
$(".foo div#bar:eq(0)")->$(".foo #bar:first-child")
代码相关的问题:
modulo(12, 5) // 2
问题:实现满足上述结果的modulo函数
1 (function module(a,b){ 2 var r; 3 if( !isNaN(a) && !isNaN(b)){ 4 (a>b)?(r= a%b):(r= b%a); 5 return r; 6 }else{ 7 throw new Error("arguments are not numbers"); 8 } 9 })(12,5);
实际上就是求模运算。注意:检查参数的合理性(数字且长度为2)否则抛出异常
"i'm a lasagna hog".split("").reverse().join("");
问题:上面的语句的返回值是什么? 答案:"goh angasal a m'i"
这道题目提醒了一点:"i'm a lasagna hog"不继承于Array.prototype不能直接调用Array的reverse()方法。因此先要使用split("")将字符串转变为数组,最后使用join("")将已经逆序的结果转换为字符串。
博主想补充一点是:通过dom操作(ducument.getElementByTayName和document.getByClassName)获取的NodeList和函数中的arguments对象都是伪数组,不能不继承Array.prototype,不能直接调用Array的方法。可以使用遍历,将伪数组中的元素push到新数组中或使用[].slice.call(arguments)将伪数组转换为数组。
( window.foo || ( window.foo = "bar" ) );
问题:window.foo 的值是什么? 答案:"bar" 只有 window.foo 为假(定义的值类型转换为false或者没定义,即为undefined)时的才是上面答案,否则就是它本身的值(提前声明定义的值)。
var foo = "Hello"; (function() { var bar = " World"; alert(foo + bar); })(); alert(foo + bar);
问题:上面两个 alert 的结果是什么 答案: "Hello World" 和 ReferenceError: bar is not defined
var foo = "Hello"; (function() { var bar = " World"; console.info(foo + bar); //代码段包裹在“立即调用函数”中,获取全局的foo和函数内的bar })(); console.info(foo + bar);//“立即调用函数”执行完毕后,外部无法访问其内部的局部变量,因此,在此作用域内的bar未定义
var foo = [];
foo.push(1);
foo.push(2);
问题:foo.length 的值是什么? 答案:2
个人感觉这道题目考得太简单了,最后,大家思考一下这道题目:
var array1 = [1,2]; var array2 = array1; array1[0] = array2[1]; array2.push(3); console.log(array1); console.log(array2);
array2 = array1将array2和array1引用同一片存储区域,对其中一个变量进行赋值和修改操作都会影响到另外一个变量的值。
因此答案是:Array1的值为[2,2,3];Array2的值为[2,2,3]