js在面试中会遇到的几个问题(下)
1.iframe的优缺点
首先要知道普通方法加载iframe,它没有浏览器的兼容性问题。
<iframe src="/path/to/file" frameborder="0" width="728" height="90" scrolling="auto"></iframe>
使用这种加载方法会在各浏览器中有如下表现:
- iframe会在主页面的onload之前加载
- iframe会在所有iframe的内容都加载完毕之后触发iframe的onload
- 主页面的onload会在iframes的onload触发之后触发,所以iframe会阻塞主页面的加载。
- 当iframe在加载的过程中,浏览器会标识正在加载东西,处于忙碌状态。
iframe的好处
- 代码重复:
因为公司业务以及领导的要求现在的醒目都用的iframe,主要为了代码的重复,导航,底部啊,这样可以不用
每一个页面重复写导航和底部,当改起来的时候也方便。
- iframes异步加载技术:
加载第三方的内容、广告或者插件经常会使用iframe。使用iframe是因为他可以和主页面并行加载,不会阻塞主页面.iframe采用的是异步加载。
iframe的坏处
- 性能之阻塞主页面的onLoad事件:
iframe虽然是异步加载不会阻塞主页面的加载,但是iframe会阻塞主页面的onload事件的加载。但是很多的事件都在onLoad事件里,iframe阻塞了主页面的onLoad的事件的加载,就会带来不好的用户体验。
- 性能之和主页面公用一个连接池:
- seo:
搜索引擎的蜘蛛不会识别在iframe中被调用的图片、文本、url等内容的,因为该内容不属于该页面,只是访问的时候被临时的调用,而且在SEO建议中也有提到:“frame/frameset/iframee标签,会导致百度spider的抓取困难,建议不要使用”这样更能证明其弊!
2.Ajax的原生写法
- 创建ajax对象XMLHttpRequest
- 连接到服务器
- 发送请求
- 接收返回值
var XHR=null;
if (window.XMLHttpRequest) {
// 非IE内核
XHR = new XMLHttpRequest();
} else if (window.ActiveXObject) {
// IE内核,这里早期IE的版本写法不同,具体可以查询下
XHR = new ActiveXObject("Microsoft.XMLHTTP");
} else {
XHR = null;
}
if(XHR){
XHR.open("GET", "ajaxServer.action");
XHR.onreadystatechange = function () {
// readyState值说明
// 0,初始化,XHR对象已经创建,还未执行open
// 1,请求已经建立,但是还没有发送,已经调用open方法,但是还没发送请求,没有调用send()
// 2,请求已发送,正在处理中(通常现在可以从响应中获取内容头)。
// 3,请求在处理中;通常响应中已有部分数据可用了,但是服务器还没有完成响应的生成
// 4,响应已完成;您可以获取并使用服务器的响应了。
// status值说明
// 200表示成功
// 202表示请求被接受,但尚未成功
// 400错误的请求
// 404文件未找到
// 500内部服务器错误
if (XHR.readyState == 4 && XHR.status == 200) {
// 这里可以对返回的内容做处理
// 一般会返回JSON或XML数据格式
console.log(XHR.responseText);
// 主动释放,JS本身也会回收的
XHR = null;
}
};
XHR.send();
}
3.为什么会有同源策略?
同源策略浅谈:只有在浏览器(js)中会有同源策略,若是只通过用户登录进网站,就可以做任何操作,那么浏览器中的js可以获取登陆的cookies,携带这些cookies去访问不同源的网站就可能泄漏用户的信息。
比如,一个用户登录了a网站,那么就会在浏览器上产生cookies,一个坏人做了一个网站b,那个用户不小心点进去b了,b会携带刚才登录的那个cookies去请求用户的其他的信息,或者访问a网站的api做一下敏感的操作。
所以要有同源策略的限制。
什么是同源策略?
- 首先来看一下什么是源? 源: 源(origin)就是协议、域名和端口号。
- 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。
- 不受同源策略限制的:
1)、页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
2)、跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的
<script src="..."></script>,<img>,<link>,<iframe>
跨域
既然有了同源策略就正好也去收集一下跨域的知识点。
1. jsonP
2. CORS
3. window.name+iframe
4. window.postMessage()
5. 修改document.domain跨子域
6. WebSocket
jsonp
概念:根据 XmlHttpRequest 对象受到同源策略的影响,而利用 <script>
元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析
工作原理:就是利用<script>
标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。
实现方式:JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据(因此叫做json padding ),这样客户端就可以随意定制自
己的函数来自动处理返回数据了基本实例请查看菜鸟教程
缺点:只能发起get请求,不能注册success,error函数,不能确保jsonp的请求成功
CORS(跨域资源共享)
判断两个对象是否相等
首先要认识到,“==”和“===”的区别:
“===”是全等运算符,严格运算符,规则如下:
- 不同类型值的做比较,直接返回false.
- 同一类型的原始类型值作比较(布尔,数字,字符串),值相等就true,值不等就false
- 同一类型的引用类型的值做比较,会比较引用类型的指针(内存地址)是否相同。相同就为true,不同就为false.
- undefined和null,不相等
undefined===undefind//true
null===null//true
0===-0//true
“==”相等运算符,相同类型的的数据的比较和“===”一样,不同类型的作比较的时候会自动的做类型转换,再去作比较,有以下几个规则
- 原始类型的值中,布尔值和字符串都会转换为数字类型,然后再去比较值是都相同,若相同则true。不同为false;
- 对象(这里指的是特别的对象,数值或者函数)和原始类型值比较,对象会转化成原始类型的值比较,
var x = 1;
,这里总结一下,能转化成原始类型的对象就转化成原始类型去比较,不能转化的就直接是false;
var obj = {valueOf: function(){ x = 2; return 0 }}
console.log(obj == 0, x) - undefined和null
undefined==undefined//true
undefined==null//true
null==null//true
有了前面的基础,然后再去看看对象“{ }”的相等的比较。
function isObjectValueEqual(a, b) {
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// 如果属性的个数不一样就不相等
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
if (a[propName] !== b[propName]) {
return false;
}
}
return true;
}
var obj1 = {
name: "wjq",
sex : "female"
};
var obj2 = {
name: "wjq",
sex : "female"
};
// true
console.log(isObjectValueEqual(obj1, obj2));
对于那些复杂的对象比如属性的值还是一个对象,这个就不适用了
因为js中全是对象,对于两个不知道是什么数据类型的对象的比较如下方法。
function isEqual(a,b){
//如果a和b本来就全等
if(a===b){
//判断是否为0和-0//0===-0为true;
return 1/a ===1/b;//(a !== 0 || 1/a ===1/b)原来的作者加了这句我觉得这样不对,于是更改了
}
//判断是否为null和undefined
if(a==null||b==null){//这里用的“==”比“===”代码精简了,所以说并不是“===”是最好的选择。
return a===b;
}
//接下来判断a和b的数据类型
var classNameA=toString.call(a),
classNameB=toString.call(b);
//如果数据类型不相等,则返回false
if(classNameA !== classNameB){
return false;
}
//如果数据类型相等,再根据不同数据类型分别判断
switch(classNameA){
case '[object RegExp]':
case '[object String]':
//进行字符串转换比较
return '' + a ==='' + b;
case '[object Number]':
//进行数字转换比较,判断是否为NaN
if(+a !== +a){
return +b !== +b;
}
//判断是否为0或-0
return +a === 0?1/ +a === 1/b : +a === +b;
case '[object Date]':
case '[object Boolean]':
return +a === +b;
}
//如果是对象类型
if(classNameA == '[object Object]'){
//获取a和b的属性长度
var propsA = Object.getOwnPropertyNames(a),
propsB = Object.getOwnPropertyNames(b);
if(propsA.length != propsB.length){
return false;
}
for(var i=0;i<propsA.length;i++){
var propName=propsA[i];
//如果对应属性对应值不相等,则返回false
if(a[propName] !== b[propName]){
return false;
}
}
return true;
}
//如果是数组类型
if(classNameA == '[object Array]'){
if(a.toString() == b.toString()){
return true;
}
return false;
}
}
推荐阅读