闭包-定时器-BOM
题目1: 下面的代码输出多少?修改代码让 fnArri 输出 i。使用 两种以上的方法
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return fnArr.index;
};
}
console.log( fnArr[3]() ); //10
方法一:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
(function(i){
fnArr[i] = function(){
return i;
}
})(i);
}
console.log( fnArr[3]() ); //3
方法二:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = (function(i){ //IIFE & 闭包
return function(){
return i;
}
})(i);
}
console.log( fnArr[3]() ); //3
方法三:
var fnArr = [];
for (let i = 0; i < 10; i ++) { //使用ES6: let
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() );
题目2: 封装一个汽车对象,可以通过如下方式获取汽车状态
var Car = (function(){
var speed = 0;
function setSpeed(s){
speed = s;
}
function getSpeed(){
console.log(speed) ;
}
function accelerate(){
speed+=10;
}
function decelerate(){
if(speed>10){
speed-=10;
}else {
speed = 0;
}
}
function getStatus(){
if(speed>0){
console.log( "running");
}else{
console.log("stop") ;
}
}
return {
setSpeed: setSpeed,
getSpeed:getSpeed,
accelerate:accelerate,
decelerate:decelerate,
getStatus:getStatus
}
})()
Car.setSpeed(30);//
Car.getSpeed(); //30
Car.accelerate();//
Car.getSpeed(); //40
Car.decelerate();//
Car.decelerate();//
Car.getSpeed(); //20
Car.getStatus(); // 'running'
Car.decelerate(); //
Car.decelerate();//
Car.getStatus(); //'stop'
Car.speed; //error
题目3:下面这段代码输出结果是? 为什么?
var a = 1;
setTimeout(function(){
a = 2;
console.log(a);
}, 0);
var a ;
console.log(a);
a = 3;
console.log(a);
输出1 3 2,那是因为setTimeout函数的运行机制是,将制定的代码移出本次执行,等到下一轮EventLoop时,再检查时间,执行代码。这意味着,先console.log(1),再console.log(3),本次代码执行完后再检查时间,执行console.log(2)
题目4:下面这段代码输出结果是? 为什么?
var flag = true;
setTimeout(function(){
flag = false;
},0)
while(flag){}
console.log(flag);
浏览器会陷入while死循环。因为setTimeout函数的运行机制是,将制定的代码移出本次执行,等到下一轮EventLoop时,再检查时间,执行代码。所以,while循环将一直循环下去,本次EventLoop无法结束,无法进入setTimeout。
题目5: 下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)
for(var i=0;i<5;i++){
setTimeout(function(i){
console.log('delayer:' + i );
}, 0);
console.log(i);
}
修改后:
for(var i=0;i<5;i++){
!function(i){
setTimeout(function(){
console.log('delayer:' + i );
}, 0);
}(i)
}
题目6: 如何获取元素的真实宽高
function getCss(curEle,attr){
return window.getComputedStyle ? window.getComputedStyle(curEle,null)[attr] : curEle.currentStyle[attr];
}
getCss(ele,'width')//宽度
getCss(ele,'height')//高度
题目7: URL 如何编码解码?为什么要编码?
编码原因:
- Url参数字符串中使用key=value键值对这样的形式来传参,键值对之间以&符号分隔,如/s?q=abc&ie=utf-8。如果你的value字符串中包含了=或者&,那么势必会造成接收Url的服务器解析错误,因此必须将引起歧义的&和=符号进行转义,也就是对其进行编码。
- Url的编码格式采用的是ASCII码,而不是Unicode,这也就是说你不能在Url中包含任何非ASCII字符,例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下,中文可能会造成问题。
ps:URI是统一资源标识的意思,通常我们所说的URL只是URI的一种。典型URL的格式如下所示。下面提到的URL编码,实际上应该指的是URI编码。
Paste_Image.pngUrl编码的原则就是使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。
解决办法:
三个编码的函数——escape,encodeURI,encodeURIComponent——都是用于将不安全不合法的Url字符转换为合法的Url字符表示,它们有以下几个不同点。
安全字符不同:
下面列出了这三个函数的安全字符(即函数不会对这些字符进行编码)
- escape(69个):*/@+-._0-9a-zA-Z
- encodeURI(82个):!#$&'()*+,/:;=?@-._~0-9a-zA-Z
- encodeURIComponent(71个):!'()*-._~0-9a-zA-Z
兼容性不同:escape函数是从Javascript 1.0的时候就存在了,其他两个函数是在Javascript 1.5才引入的。但是由于Javascript 1.5已经非常普及了,所以实际上使用encodeURI和encodeURIComponent并不会有什么兼容性问题。
对Unicode字符的编码方式不同:这三个函数对于ASCII字符的编码方式相同,均是使用百分号+两位十六进制字符来表示。但是对于Unicode字符,escape的编码方式是%uxxxx,其中的xxxx是用来表示unicode字符的4位十六进制字符。这种方式已经被W3C废弃了。但是在ECMA-262标准中仍然保留着escape的这种编码语法。encodeURI和encodeURIComponent则使用UTF-8对非ASCII字符进行编码,然后再进行百分号编码。这是RFC推荐的。因此建议尽可能的使用这两个函数替代escape进行编码。
适用场合不同:encodeURI被用作对一个完整的URI进行编码,而encodeURIComponent被用作对URI的一个组件进行编码。从上面提到的安全字符范围表格来看,我们会发现,encodeURIComponent编码的字符范围要比encodeURI的大。我们上面提到过,保留字符一般是用来分隔URI组件(一个URI可以被切割成多个组件,参考预备知识一节)或者子组件(如URI中查询参数的分隔符),如:号用于分隔scheme和主机,?号用于分隔主机和路径。由于encodeURI操纵的对象是一个完整的的URI,这些字符在URI中本来就有特殊用途,因此这些保留字符不会被encodeURI编码,否则意义就变了。
题目8: 补全如下函数,判断用户的浏览器类型
function isAndroid(){
return /android/i.test(navigator.userAgent);
}
function isIphone(){
return /iphone/i.test(navigator.userAgent);
}
function isIpad(){
return /ipad/i.test(navigator.userAgent);
}
function isIOS(){
return /iphone|ipad/i.test(navigator.userAgent);
}