- 跨域问题:
5大方法:
(1) CORS(cross origin resources sharing跨域资源共享):ajax请求采用绝对路径,在服务器端设置Access-Control-Allow-Origin来进行。
(2) JSONP: 主要采用的是js的引入可以跨域共享,通过callback来载入其他域的资源,形式是:callback({数据名:数据值}),但是需要后台支持,并且只支持get方式,但基本没有兼容问题,老浏览器也很支持
(3) window.domain:通过在两个页面中设置相同的window.domain,但是window.domain只能设置成自身或者更高一级的父域,所以只能解决的是不同子域的问题,也就是主域一定要相同。
(4) window.name: 在一个窗口(window)的生命周期中,窗口载入的所有的页面都是共享一个window.name。(不是很理解跟跨域有什么关系)
(5) window.postMessage(message,targetOrigin)(HTML5的方法:IE8+,FireFox.Chrome,Opera等):可以用这个向其他的window对象发送消息,无论这个window对象是否属于同源或不同源。
答:什么是跨域?
概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。
URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js 同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js 同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js 同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js 域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js 主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js 不同域名 不允许
对于端口和协议的不同,只能通过后台来解决。
跨域资源共享(CORS)
CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.open("GET", "/trigkit4",true);
xhr.send();
</script>
以上的trigkit4是相对路径,如果我们要使用CORS,相关Ajax代码可能如下所示:
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://segmentfault.com/u/trigkit4/",true);
xhr.send();
</script>
代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
要解决跨域的问题,我们可以使用以下几种方法:
通过jsonp跨域
现在问题来了?什么是jsonp?维基百科的定义是:JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。
JSONP也叫填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON,例如:
callback({"name","trigkit4"});
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。 例如:
<script type="text/javascript">
function dosomething(jsondata){
//处理获得的json数据
}
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>
js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。
<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>
最终,输出结果为:dosomething(['a','b','c']);
如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。
<script type="text/javascript">
$.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
//处理获得的json数据
});
</script>
jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
JSONP的优缺点
JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
CORS和JSONP对比
CORS与JSONP相比,无疑更为先进、方便和可靠。
1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS)。
通过修改document.domain来跨子域
浏览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的。
不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:
<script type="text/javascript">
function test(){
var iframe = document.getElementById('ifame');
var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
var doc = win.document;//这里获取不到iframe里的document对象
var name = win.name;//这里同样获取不到window对象的name属性
}
</script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html 和http://example.com/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。
1.在页面 http://www.example.com/a.html 中设置document.domain:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
document.domain = 'example.com';//设置成主域
function test(){
alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
}
</script>
2.在页面 http://example.com/b.html 中也设置document.domain:
<script type="text/javascript">
document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>
修改document.domain的方法只适用于不同子域的框架间的交互。
使用window.name来进行跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的
使用HTML5的window.postMessage方法跨域
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
- 块状元素,内联元素,显示上的区别和举例有哪些元素?
答:
块状元素
一般是其他元素的容器,可容纳内联元素和其他块状元素,块状元素排斥其他元素与其位于同一行,宽度(width)高度(height)起作用。常见块状元素为div和p、h1~h6,hr,pre,table、ul、ol、li等
内联元素
内联元素不能设置宽高,竖直方向上不能设置margin和padding。但水平方向上可以设置margin和padding。
内联元素只能容纳文本或者其他内联元素,它允许其他内联元素与其位于同一行,但宽度(width)高度(height)不起作用。常见内联元素为“a”、big、em、span、strong、img、textarea、label、input等
- 块状元素的水平、垂直居中显示如何实现?
答: 让div内的内容(包括文字及图片)垂直居中: vertical-align的值是middle,水平居中:center.
关于居中使用css为:position:fixed;left:50%;top:50%;margin-left:width/2;
margin-top:height/2; 对于ie6,只能把position:改成absolute;(在其他浏览器换成absolute也没什么问题,因为fixed与absolute定位元素是一样的)
- Position
答:position:absolute和float会隐式地改变display类型,不论之前什么类型的元素(display:none除外),只要设置了position:absolute、float:left或float:right中任意一个,都会让元素以display:inline-block的方式显示。
- cmd和amd模块化,requirejs等。。还有MVC模式
答 :
1.对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
2. CMD 推崇依赖就近,AMD 推崇依赖前置。
3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
- 变量声明提前
答:
javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面。
先看一段代码
1 2 3 4 5 |
var v = "hello"; (function(){ console.log(v); var v = "world"; })(); |
这段代码运行的结果是什么呢?
答案是:undefined
这段代码说明了两个问题,
第一,function作用域里的变量v遮盖了上层作用域变量v。代码做少些变动
1 2 3 4 5 |
var v = "hello"; if(true){ console.log(v); var v = "world"; } |
输出结果为"hello",说明javascript是没有块级作用域的。函数是JavaScript中唯一拥有自身作用域的结构。
第二,在function作用域内,变量v的声明被提升了。所以最初的代码相当于:
1 2 3 4 5 6 |
var v = "hello"; (function(){ var v; //declaration hoisting console.log(v); v = "world"; })(); |
声明、定义与初始化
声明宣称一个名字的存在,定义则为这个名字分配存储空间,而初始化则是为名字分配的存储空间赋初值。
用C++来表述这三个概念
1 2 3 |
extern int i;//这是声明,表明名字i在某处已经存在了 int i;//这是声明并定义名字i,为i分配存储空间 i = 0;//这是初始化名字i,为其赋初值为0 |
javascript中则是这样
1 2 |
var v;//声明变量v v = "hello";//(定义并)初始化变量v |
因为javascript为动态语言,其变量并没有固定的类型,其存储空间大小会随初始化与赋值而变化,所以其变量的“定义”就不像传统的静态语言一样了,其定义显得无关紧要。
声明提升
当前作用域内的声明都会提升到作用域的最前面,包括变量和函数的声明
1 2 3 4 5 6 |
(function(){ var a = "1"; var f = function(){}; var b = "2"; var c = "3"; })(); |
变量a,f,b,c的声明会被提升到函数作用域的最前面,类似如下:
1 2 3 4 5 6 7 |
(function(){ var a,f,b,c; a = "1"; f = function(){}; b = "2"; c = "3"; })(); |
请注意函数表达式并没有被提升,这也是函数表达式与函数声明的区别。进一步看二者的区别:
1 2 3 4 5 6 7 8 9 |
(function(){ //var f1,function f2(){}; //hoisting,被隐式提升的声明
f1(); //ReferenceError: f1 is not defined f2();
var f1 = function(){}; function f2(){} })(); |
上面代码中函数声明f2被提升,所以在前面调用f2是没问题的。虽然变量f1也被提升,但f1提升后的值为undefined,其真正的初始值是在执行到函数表达式处被赋予的。所以只有声明是被提升的。
名字解析顺序
javascript中一个名字(name)以四种方式进入作用域(scope),其优先级顺序如下:
1、语言内置:所有的作用域中都有 this 和 arguments 关键字
2、形式参数:函数的参数在函数作用域中都是有效的
3、函数声明:形如function
foo() {}
4、变量声明:形如var bar;
名字声明的优先级如上所示,也就是说如果一个变量的名字与函数的名字相同,那么函数的名字会覆盖变量的名字,无论其在代码中的顺序如何。但名字的初始化却是按其在代码中书写的顺序进行的,不受以上优先级的影响。看代码:
1 2 3 4 5 6 7 8 9 |
(function(){ var foo; console.log(typeof foo); //function
function foo(){}
foo = "foo"; console.log(typeof foo); //string })(); |
如果形式参数中有多个同名变量,那么最后一个同名参数会覆盖其他同名参数,即使最后一个同名参数并没有定义。
以上的名字解析优先级存在例外,比如可以覆盖语言内置的名字arguments。
命名函数表达式
可以像函数声明一样为函数表达式指定一个名字,但这并不会使函数表达式成为函数声明。命名函数表达式的名字不会进入名字空间,也不会被提升。
1 2 3 4 5 |
f();//TypeError: f is not a function foo();//ReferenceError: foo is not defined var f = function foo(){console.log(typeof foo);}; f();//function foo();//ReferenceError: foo is not defined |
命名函数表达式的名字只在该函数的作用域内部有效。
- 数组去重(看来是百度的常见问题,在其他人的总结中看到了答案)
答:方法一:(这个方法通过两层嵌套,实现查找,效率较低。总体思路是把数组元素逐个搬运到另一个数组,搬运的过程中检查这个元素是否有重复,如果有就直接丢掉。)
function unique(arr) {
var result = [], isRepeated;
for (var i = 0, len = arr.length; i < len; i++) {
isRepeated = false;
for (var j = 0, len = result.length; j < len; j++) {
if (arr[i] == result[j]) {
isRepeated = true;
break;
}
}
if (!isRepeated) {
result.push(arr[i]);
}
}
return result;
}
方法二:(这个方法是利用hash表中(的key值存不存在的方法实现,也可以说是map、reduce的方法))
function unique(arr) {
var result = [], hash = {};
for (var i = 0, elem; (elem = arr[i]) != null; i++) {
if (!hash[elem]) {
result.push(elem);
hash[elem] = true;
}
}
return result;
//http://www.cnblogs.com/sosoft/
}
- Jquery的defered实现原理
- 继承
- 除去字符串中的空格
答:1.s.replace(" ","");
2.text.replace(/\s/ig,'');
- 闭包
答:闭包的形式是function a中return function b,b中会用到a 中的局部变量,也可能用到函数a的外部变量,根据js内存回收机制,一旦function a执行完成,a中定义的局部变量就会被回收清除,采用闭包以后就会将function b所用到的所有变量跟b绑在一起,只要function b不被清除,这些变量就不会被回收和清除。闭包容易产生内存泄露,要注意在不用b时,手动的清除b。
(实际上任何函数都是全局作用域的内部函数,都能访问全局变量,所以都是window的闭包)
闭包的用处:闭包可以将函数中的局部变量给以保存下来,作用:
- 匿名函数自执行(而且这种机制不会污染对象)
- 缓存,再来看一个例子,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,
那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,
然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,
从而函数内部的值可以得以保留。 - 实现封装
- 闭包的另一个重要用途是实现面向对象中的对象,传统的对象语言都提供类的模板机制,
这样不同的对象(类的实例)拥有独立的成员及状态,互不干涉。虽然JavaScript中没有类这样的机制,但是通过使用闭包,
我们可以模拟出这样的机制。
- 前端优化
答:答案同网易面试题
- css文件引入的方法,import和link方法的区别
答
:
(
1)
link属于
HTML
标签,而
@import是
CSS
提供的
;
(
2)
页面被加载的时,
link会同时被加载,而
@import引用的
CSS
会等到页面被加载完再加载
;
(
3) import
只在
IE5
以上才能识别,而
link是
HTML
标签,无兼容问题
;
(
4)
link方式的样式的权重
高于
@import的权重
.
答:有4种,分别是行内式、内嵌式、链接式和导入式。
- 行内式:直接在html标签中用style设定css
- 嵌入式:采用<style>标签, 缺点是对于一个包含很多网页的网站,在每个网页中使用嵌入式,进行修改样式时非常麻烦。单一网页可以考虑使用嵌入式
3.导入式: 将一个独立的.css文件引入HTML文件中,导入式使用CSS规则引入外部CSS文件,<style>标记也是写在<head>标记中,使用的语法如下:
<style type="text/css">
@import"mystyle.css"; 此处要注意.css文件的路径
</style>
缺陷: 导入式会在整个网页装载完后再装载CSS文件,因此这就导致了一个问题,如果网页比较大则会儿出现先显示无样式的页面,闪烁一下之后,再出现网页的样式。这是导入式固有的一个缺陷。
4.链接式: 也是将一个.css文件引入到HTML文件中,但它与导入式不同的是链接式使用HTML规则引入外部CSS文件,它在网页的<head></head>标签对中使用<link>标记来引入外部样式表文件,使用语法如下:
<link href="mystyle.css" rel="stylesheet" type="text/css"/>
使用链接式时与导入式不同的是它会以网页文件主体装载前装载CSS文件,因此显示出来的网页从一开始就是带样式的效果的,它不会象导入式那样先显示无样式的网页,然后再显示有样式的网页,这是链接式的优点。
总结:一般来说,做网站时把样式多写在多个样式表文件中,因此我们先用链接式引入一个总的CSS文件,然后在这个CSS文件中在使用导入式来引入其他的CSS文件。但如果通过JavaScrip来动态引入CSS文件则只能使用链接式。
- 事件冒泡及其应用
答:事件发生的顺序是:先是事件捕获阶段:根节点逐级送到子节点。
然后是冒泡过程是:子节点到根节点往下冒。
应用是事件代理。事件代理好处:减少事件绑定的对象的内存。
其他人补充:
- 淘宝为何将图片放在另一个域中,实现跨域加载?
答:对于这道题,我是这么想的:不同的域名经过dns(域名解析系统)解析以后,映射到的是不同的ip地址,不同的ip地址对应的就是不同的服务器存储地址,所以淘宝将图片放在另一个域中,主要考虑的应该是服务的存储方面。而且将图片放在其他服务器上,减少主服务的存储压力,可以减少IO口的压力,加快速度。
- display的几种方式,具体区别?
答: 主要说一下display为inline-block和display为inline-table的区别,
这是别人的测试成果:(原文地址:http://blog.csdn.net/yenange/article/details/7520789)
IE6/7(IE_Test) | IE8(xp/2003) | IE9 | Chrome 18.0.1025.162 m | Firefox 12.0 | |
inline | √ | √ | √ | X | √ |
inline-block | X | √ | ? | √ | √ |
inline-table | X | √ | √ | √ | √ |
该博主得出的结论是:
所以在一般情况下, 希望并排, 最好是用 inline , 判断一下是Chrome则用 inline-table
var display= navigator.userAgent.indexOf("Chrome") > -1 ? "inline-table" : "inline";
我觉得inline-block和inline-table最大的区别是都是行内块级元素,(具体差别下次再整理,找不到好的博文)