精读JavaScript模式(二)
我在想知识点怎么去分类,原本计划一章节一篇,但这样会会显得长短不一。更主要的是看到哪写的哪更为随意。那么这一篇还是紧接第一篇进行知识梳理,上篇说到了更优化的for循环,现在继续聊聊其它的循环方式。
1.for-in循环
for-in循环又称之为枚举,常用于遍历非数组对象。虽然也可以用于遍历数组,但并不推荐这么去做,例如在for-in循环key值为数字的对象时,遍历顺序其实是不固定的,这点与for不同。
var obj = {
3:"echo",
2:"25",
1:"web",
4:'male'
}
//for-in
for(var key in obj){
console.log(key+':'+obj[key])//1:web 2:25 3:echo 4:male
};
当我们遍历对象时其实存在一个问题,我们都知道对象存在继承,那么在遍历过程中很有可能拿到你不是你定义的而是通过原型链继承而来外来属性,举个例子。
//假设其他人在原型上加添加了一个克隆方法
Object.prototype.clone = function () {}; //自己定义的对象
var man = {
hands:2,
legs:2,
heads:1
};
//我想遍历出自己定义man的所有属性
for(var i in man) {
console.log(man[i]);// 2 2 1 ƒ () {}
}
很明显clone方法并不是我们想要的,那怎么去除掉原型链继承而来的属性呢,这里就需要使用hasOwnProperty方法来对对象属性做一个判断。
hasOwnProperty()
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性---MDN了解更多
//假设其他人在原型上加添加了一个克隆方法
Object.prototype.clone = function () {}; //自己定义的对象
var man = {
hands:2,
legs:2,
heads:1
};
//我想遍历出自己定义man的所有属性
for(var i in man) {
//写法一,
if (man.hasOwnProperty(i)) {
console.log(man[i]);// 2 2 1
}
//写法二
if (Object.prototype.hasOwnProperty.call(man, i)) {
console.log(man[i]);// 2 2 1
}
}
方法二相对方法一的好处是,万一有人给man属性重定向了一个hasOwnProperty方法,则会让属性验证方法失效。
我们在这里提到hasOwnProperty方法只是更为保存的做法,如果你对于代码足够自信,即便省略掉这个判断也不是错误的,只是根据实情来使用。
2.尽量少的扩充内置原型(Object.prototype)
var obj = {};
console.log(obj);
//方法一
var obj = Object.create(null);
console.log(obj)//{} 真正的空对象 //方法二
var obj = {};
Object.setPrototypeOf(obj,null); //参数一 将被设置原型的对象. 参数二 该对象新的原型链
console.log(obj)//{} 真正的空对象
3.switch模式(switch case)
var a = 1,
result = '';
//if else写法
if(a === 1){
result = "a";
}else if (a === 2){
result = "b";
}else if (a ===3){
result = "c";
};
//switch case写法
switch (a) {
case 1 :
result = 'a';
break;
case 2 :
result = "b";
break;
case 3:
result = "c";
break;
default:
result = "unknown";
};
使用switch case还有一种场合,假设当a为1,2其中的一个时,我需要执行方法fn1,当a为3,4其中一个时,我需要调用方法fn2,如果都不是,那就执行方法fn3,这里用switch case看起来会更为整洁。
//方法一
if(a === 1 || a === 2){
fn1()//do something
}else if(a === 3 || a === 4) {
fn2()//do something
}else{
fn3()//do something
}
//方法二
switch (a) {
case 1 :
case 2 :
fn1();//do something
break;
case 3 :
case 4 :
fn2()//do something
break;
default:
fn3()//do something
};
4.避免隐式类型转换(===与==)
在javaScript的比较操作中会存在一些隐式的数据类型转换。例如false == 0 "" ==0的比较都会返回true;"2"-1 =1,"2"+1 = "21"等等。
在数据比较中,为了避免数据隐式转换造成的干扰,推荐使用===和!===运算符,它们相比== !==会比较值以外,还会比较数据的类型。
var a = 0;
a == "" ? console.log('请输入有效内容') : fn();//请输入有效内容 因为0 == ""为true
很明显,在这里假设用户输入了一个有效数字0,还是不会调用我们的方法,使用===和!===会更为严谨。
5.避免使用eval()
eval()
函数会将传入的字符串当做 JavaScript 代码进行执行。---MDN了解更多
var fn = "(function (){console.log(1)})()"
//即使fn存储了一个字符串的自调函数,eval也能运行
eval(fn)//
很显然,fn只是一个自调函数写法的字符串,但是用了eval却将这个字符串当方法执行了。
定时器大家都不会陌生,当我们在定时器中调用一个外部定义的方法其实有两种写法:
function fn() {
console.log(1);
};
//反模式
setInterval("fn()",1000);
//推荐
setInterval(fn,1000);
两种写法都会执行,有没有很奇怪,为什么第一种加了引号明明是个字符串,为什么还是会调用,因为这个写法和eval()原理类似,同样不推荐这种写法。
那如果我们真的要执行一段字符串怎么办呢?这里推荐使用new Function()或者自调函数来包裹原本的eval()方法。
var str1 = "var a = 1;console.log(a)";
eval(str1);
//使用new Function
var str2 = "var b = 2;console.log(b)";
new Function(str2)();//或者 Fcuntion(str2)()也可以
//使用自调函数包裹
var str3 = "var c = 3;console.log(c)";
(function (){eval(str3)})(); console.log(typeof a);//number
console.log(typeof b);//undefined
console.log(typeof c);//undefined
在上述代码中,字符串均可以被转化为代码执行,但是好处在于,new Function与自调函数的写法就像一个沙箱,它不会修改作用域链,并不会污染局部作用域,所以例子中除了a都不能被外部作用域使用。
6.字符串与数字的转换(parseInt)
parseInt:该可解析一个字符串,并返回一个整数。
parseFloat:该函数指定字符串中的首个字符是否是数字。如果是,则对字符串进行解析,直到到达数字的末端为止,然后以数字返回该数字,而不是作为字符串。
编程中将字符串转变为数字是很常见的,比如我们要将"100"转为数字100:
var str = "";
console.log(parseInt(str));//
console.log(parseFloat(str));//
console.log(+str);//
console.log(Number(str));//
这四种方法中使用+或者Number()会比parseInt以及parseFloat要更快,因为前者只是单纯的转换,而后者是在做字符串的解析。
不过,如果你要处理类似"100 echo"这样的字符串,就只能使用parseInt或者parseFloat方法了。
var str = "100 echo";
console.log(parseInt(str));//
console.log(parseFloat(str));//
console.log(+str);//NAN
console.log(Number(str));//NAN
如果是"100.11"带小数点的字符串,就不能使用parseInt()方法,因为当它遇到非数字就会停止解析,这样会截掉小数点后面的数字。
var str = "100.11";
console.log(parseInt(str));//
console.log(parseFloat(str));//100.11
console.log(+str);//100.11
console.log(Number(str));//100.11
到这里第二章一些挺实用,挺好玩的东西基本记录完成了,第三章也会继续写,可能要点时间,因为中途也要做一点别的东西,最近学习的效率很低,确实得反省自己,目标还很远,加油吧。
精读JavaScript模式(二)的更多相关文章
- 精读JavaScript模式(七),命名空间模式,私有成员与静态成员
一.前言 惰性十足,这篇2月19号就开始写了,拖到了现在,就是不愿意花时间把看过的东西整理一下,其它的任何事都比写博客要有吸引力,我要反省自己. 从这篇开始,是关于JS对象创建模式的探讨,JS语言简单 ...
- 精读JavaScript模式(一)
一.前言 为什么读这本书? 其实做前端开发,一个需求给不同工作经验的人去做,只要完工时间不算苛刻,大家都是能实现的.功能实现虽然大致相同,但当我们回归代码去看实现方式,代码书写的美观程度,以及实现的方 ...
- 精读JavaScript模式(八),JS类式继承
一.前言 这篇开始主要介绍代码复用模式(原书中的第六章),任何一位有理想的开发者都不愿意将同样的逻辑代码重写多次,复用也是提升自己开发能力中重要的一环,所以本篇也将从“继承”开始,聊聊开发中的各种代码 ...
- 精读JavaScript模式(三),new一个构造函数居然发生了什么?
一.前言 上个月底,爸爸因为事故突然离世,说心里话,现在看到'去世','爸爸'这样的字眼,眼泪都会忍不住在眼眶打转,还是需要时间治愈.最近也只是零碎的看了下东西,始终沉不下心去读书,直到今天还是决定捡 ...
- 精读JavaScript模式(六),Memoization模式与函数柯里化的应用
假期就这么结束了!十天假就有三天在路上,真的难受!想想假期除了看了两场电影貌似也没做什么深刻印象的事情.流浪地球,特效还是很赞,不过对于感情的描写还是逃不掉拖沓和尴尬的通病,对于国产科幻还是抱有支持的 ...
- 精读JavaScript模式(五),函数的回调、闭包与重写模式
一.前言 今天地铁上,看到很多拖着行李箱的路人,想回家了. 在上篇博客结尾,记录到了函数的几种创建方式,简单说了下创建差异,以及不同浏览器对于name属性的支持,这篇博客将从第四章函数的回调模式说起. ...
- 精读JavaScript模式(四),数组,对象与函数的几种创建方式
一.前言 放了个元旦,休息了三天,加上春运抢票一系列事情的冲击,我感觉我的心已经飞了.确实应该收收心,之前计划的学习任务也严重脱节了:我恨不得打死我自己. 在上篇博客中,笔记记录到了关于构造函数方面的 ...
- Javascript模式(二) 发布者/订阅者模式
var publisher = { // 订阅者数组 subscribers : { "any" : [] }, // 增加订阅者 on : function(type, fn, ...
- PHP微信支付开发之扫描支付(模式二)后如何回调
其实在写这篇文章的时候感觉自己已经落伍了,不过笔者在百度上搜索"微信支付开发之扫描支付(模式二)后如何回调"寻找答案时,发现依旧有很多朋友没有解决这个问题,所以就把自己的解决思路分 ...
随机推荐
- 一篇谈Flink不错的文章
精华 : 在执行引擎这一层,流处理系统与批处理系统最大不同在于节点间的数据传输方式.对于一个流处理系统,其节点间数据传输的标准模型是:当一条数据被处理完成后,序列化到缓存中,然后立刻通过网络传输到下一 ...
- spark 中划分stage的思路
窄依赖指父RDD的每一个分区最多被一个子RDD的分区所用,表现为 一个父RDD的分区对应于一个子RDD的分区 两个父RDD的分区对应于一个子RDD 的分区. 宽依赖指子RDD的每个分区都要依赖于父RD ...
- JSON 全解
和js对象的区别 json只是一种数据格式,不支持undefined,字符串必须使用双引号,需要对/进行转义/. js属性名可不加"" json属性名必须加"" ...
- SRM469
250pt 在一个10^9 * 10^9大的剧院里,有最多47个位子有人,然后有一对couple想找一对左右相邻的位子,问有多少种选择方式. 思路: 总共有 n * (m-1)种方案,然后扣掉有人位置 ...
- 【Unity】UGUI系列教程——拼接一个简单界面
0.简介: 在目前的游戏市场上,手游依然是市场上的主力军,而只有快速上线,玩法系统完善的游戏才能在国内市场中占据份额.而在手游开发过程中,搭建UI系统是非常基本且重要的技能,极端的说如果对Unity的 ...
- 剑指offer编程题Java实现——面试题3二维数组中的查找
题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 下面是我实现的代码 ...
- ovs flow 原理及实验
OpenFlow概述 在支持OpenFlow的交换机中包含了若干个Flow table,Flow table可以用来控制数据包的处理,交换机会执行与flow相匹配的表项中所罗列的动作. OpenFlo ...
- tomcat服务的启动与隐藏启动(win)
一: tomcat的启动与隐藏启动 1. 正常启动:D:\apache-tomcat-8.5.24\bin中的 startup.bat 双击启动 2. 启动tomcat服务后,window下方 ...
- JPA-style positional param was not an integral ordinal
参数错误 多为SQL语句问题 例如SQL拼装中的空格,换行时首位应多加空格保持语句效果
- Python上下文管理协议:__enter__和__exit__
上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围.一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存).它的语 ...