全面介绍javascript实用技巧及单竖杠


Posted in Javascript onJuly 18, 2016

JavaScript 本身可以算是一门简单的语言,但我们也不断用智慧和灵活的模式来改进它。昨天我们将这些模式应用到了 JavaScript 框架中,今天这些框架又驱动了我们的 Web 应用程序。很多新手开发者被各种强大的 JavaScript 框架吸引进来,但他们却忽略了框架身后浩如星海的 JavaScript 实用技巧。本文将为你全面的介绍其中的知识点。

一、js整数的操作

使用|0和~~可以将浮点转成整型且效率方面要比同类的parseInt,Math.round 要快,在处理像素及动画位移等效果的时候会很有用。性能比较见此。

var foo = (12.4 / 4.13) | 0;//结果为3
var bar = ~~(12.4 / 4.13);//结果为3

还有一个小技巧,就是!!2个叹号,可以讲一个值,快速转化为布尔值。你可以测试一下!

var eee="eee";
alert(!!eee)

返回的是true,也就是说任何一个值前面加!!都可以恒等于true。除非这个值本来就是布尔值,或者为 undefined, null, 0, false, NaN, '',因为我提到的 undefined, null, 0, false, NaN, '' ,这些,本来就是false,所以加了两个!!之后,还是fasle。

二、重写原生alert,记录弹框次数

(function() {
 var oldAlert = window.alert,
 count = 0;
 window.alert = function(a) {
 count++;
 oldAlert(a + "\n You've called alert " + count + " times now. Stop, it's evil!");
 };
})();
alert("Hello Haorooms");

三、数字交换不声明中间变量的方法

两个数字之间做交换,我们的一般做法是声明一个中间变量,但是今天的做法比较奇葩,不用声明中间变量,看看是如何实现的!

var a=1,b=2;a=[b,b=a][0];
console.log('a:'+a+',b:'+b);

 //输出a:2,b:1

怎么样,这个方法是不是有一种焕然一新的感觉?

四、万物皆对象

在JavaScript的世界,万物皆对象。除了null和undefined,其他基本类型数字,字符串和布尔值都有对应有包装对象。对象的一个特征是你可以在它身上直接调用方法。

对于数字基本类型,当试图在其身上调用toString方法会失败,但用括号括起来后再调用就不会失败了,内部实现是用相应的包装对象将基本类型转为对象。所以(1).toString()相当于new Number(1).toString()。因此,你的确可以把基本类型数字,字符串,布尔等当对象使用的,只是注意语法要得体。

同时我们注意到,JavaScript中数字是不分浮点和整形的,所有数字其实均是浮点类型,只是把小数点省略了而以,比如你看到的1可以写成1.,这也就是为什么当你试图1.toString()时会报错,所以正确的写法应该是这样:1..toString(),或者如上面所述加上括号,这里括号的作用是纠正JS解析器,不要把1后面的点当成小数点。内部实现如上面所述,是将1.用包装对象转成对象再调用方法。

五、If语句的变形

当你需要写一个if语句的时候,不妨尝试另一种更简便的方法,用JavaScript中的逻辑操作符来代替。

var day=(new Date).getDay()===0;
//传统if语句
if (day) {
 alert('Today is Sunday!');
};
//运用逻辑与代替if
day&&alert('Today is Sunday!');

比如上面的代码,首先得到今天的日期,如果是星期天,则弹窗,否则什么也不做。我们知道逻辑操作存在短路的情况,对于逻辑与表达式,只有两者都真才结果才为真,如果前面的day变量被判断为假了,那么对于整个与表达式来说结果就是假,所以就不会继续去执行后面的alert了,如果前面day为真,则还要继续执行后面的代码来确定整个表达式的真假。利用这点达到了if的效果。

对于传统的if语句,如果执行体代码超过了1 条语句,则需要加花括号,而利用逗号表达式,可以执行任意条代码而不用加花括号。

if(conditoin) alert(1),alert(2),console.log(3);

六、使用===,而不是==

==(或!=)操作符在需要的时候会自动执行类型转换。===(或!==)操作不会执行任何转换。它将比较值和类型,而且在速度上也被认为优于==。

[10] === 10 // is false
[10] == 10 // is true
'10' == 10 // is true
'10' === 10 // is false
 [] == 0 // is true
 [] === 0 // is false
 '' == false // is true but true == "a" is false
 '' === false // is false

七、使用闭包实现私有变量

function Person(name, age) {
 this.getName = function() { return name; };
 this.setName = function(newName) { name = newName; };
 this.getAge = function() { return age; };
 this.setAge = function(newAge) { age = newAge; };

 //未在构造函数中初始化的属性
 var occupation;
 this.getOccupation = function() { return occupation; };
 this.setOccupation = function(newOcc) { occupation = 
  newOcc; };
}

八、创建对象的构造函数

function Person(firstName, lastName){
 this.firstName = firstName;
 this.lastName = lastName;
}

var Saad = new Person("Saad", "Mousliki");

九、小心使用typeof、instanceof和constructor

var arr = ["a", "b", "c"];
typeof arr; // return "object"
arr instanceof Array // true
arr.constructor(); //[]

十、创建一个自调用函数(Self-calling Funtion)

这个经常被称为自调用匿名函数(Self-Invoked Anonymous Function)或者即时调用函数表达式(IIFE-Immediately Invoked Function Expression)。这是一个在创建后立即自动执行的函数,通常如下:

(function(){
 // some private code that will be executed automatically
})();
(function(a,b){
 var result = a+b;
 return result;
})(10,20)

十一、从数组中获取一个随机项

var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];

var randomItem = items[Math.floor(Math.random() * items.length)];

十二、在特定范围内获取一个随机数

这个代码片段在你想要生成测试数据的时候非常有用,比如一个在最小最大值之间的一个随机薪水值。

var x = Math.floor(Math.random() * (max - min + 1)) + min;

十三、在0和设定的最大值之间生成一个数字数组

var numbersArray = [] , max = 100;

for( var i=1; numbersArray.push(i++) < max;); // numbers = [0,1,2,3 ... 100]

十四、生成一个随机的数字字母字符串

function generateRandomAlphaNum(len) {
 var rdmstring = "";
 for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
 return rdmString.substr(0, len);
}

//调用方法generateRandomAlphaNum(15);

十五、打乱一个数字数组

var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){ return Math.random() - 0.5});
/* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205] */

十六、 String的trim函数

String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};

十七、 附加(append)一个数组到另一个数组上

var array1 = [12 , "foo" , {name: "Joe"} , -2458];

var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 will be equal to [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

十八、将arguments对象转换成一个数组

var argArray = Array.prototype.slice.call(arguments);
【译者注:arguments对象是一个类数组对象,但不是一个真正的数组】

十九、验证参数是否是数字(number)

function isNumber(n){
 return !isNaN(parseFloat(n)) && isFinite(n);
}

二十、验证参数是否是数组

function isArray(obj){
 return Object.prototype.toString.call(obj) === '[object Array]' ;
}

注意:如果toString()方法被重写了(overridden),你使用这个技巧就不能得到想要的结果了。或者你可以使用:

Array.isArray(obj); // 这是一个新的array的方法

如果你不在使用多重frames的情况下,你还可以使用 instanceof 方法。但如果你有多个上下文,你就会得到错误的结果。

var myFrame = document.createElement('iframe');
document.body.appendChild(myFrame);

var myArray = window.frames[window.frames.length-1].Array;
var arr = new myArray(a,b,10); // [a,b,10]

// instanceof will not work correctly, myArray loses his constructor
// constructor is not shared between frames
arr instanceof Array; // false

【译者注:关于如何判断数组网上有不少讨论,大家可以google一下。这篇就写的挺详细的。】

二十一、获取一个数字数组中的最大值或最小值

var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers);
var minInNumbers = Math.min.apply(Math, numbers);
【译者注:这里使用了Function.prototype.apply方法传递参数的技巧】

二十二、清空一个数组

var myArray = [12 , 222 , 1000 ];
myArray.length = 0; // myArray will be equal to [].

二十三、不要使用 delete 来删除一个数组中的项。

使用 splice 而不要使用 delete 来删除数组中的某个项。使用 delete 只是用 undefined 来替换掉原有的项,并不是真正的从数组中删除。

不要使用这种方式:

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
delete items[3]; // return true
items.length; // return 11
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

而使用:

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
items.splice(3,1) ;
items.length; // return 10
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

delete 方法应该被用来删除一个对象的某个属性。

二十四、使用 length 来截短一个数组

跟上面的清空数组的方式类似,我们使用 length 属性来截短一个数组。

var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ];
myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].

此外,如果你将一个数组的 length 设置成一个比现在大的值,那么这个数组的长度就会被改变,会增加新的 undefined 的项补上。 数组的 length 不是一个只读属性。

myArray.length = 10; // the new array length is 10
myArray[myArray.length - 1] ; // undefined

二十五、使用逻辑 AND/OR 做条件判断

同(五),if变形语句!

var foo = 10;
foo == 10 && doSomething(); // 等价于 if (foo == 10) doSomething();
foo == 5 || doSomething(); // 等价于 if (foo != 5) doSomething();

逻辑 AND 还可以被使用来为函数参数设置默认值

function doSomething(arg1){
 Arg1 = arg1 || 10; // 如果arg1没有被设置的话,Arg1将被默认设成10
}

二十六、使用 map() 方法来遍历一个数组里的项

var squares = [1,2,3,4].map(function (val) {
 return val * val;
});
// squares will be equal to [1, 4, 9, 16]

二十七、四舍五入一个数字,保留N位小数

var num =2.443242342;
num = num.toFixed(4); // num will be equal to 2.4432

二十八、浮点数问题

0.1 + 0.2 === 0.3 // is false
9007199254740992 + 1 // is equal to 9007199254740992
9007199254740992 + 2 // is equal to 9007199254740994

为什么会这样? 0.1+0.2等于0.30000000000000004。你要知道,所有的JavaScript数字在内部都是以64位二进制表示的浮点数,符合IEEE 754标准。更多的介绍,可以阅读这篇博文。你可以使用 toFixed() 和 toPrecision() 方法解决这个问题。

二十九、使用for-in遍历一个对象内部属性的时候注意检查属性

下面的代码片段能够避免在遍历一个对象属性的时候访问原型的属性

for (var name in object) {
 if (object.hasOwnProperty(name)) {
 // do something with name
 }
}

三十、 逗号操作符

var a = 0;
var b = ( a++, 99 );
console.log(a); // a will be equal to 1
console.log(b); // b is equal to 99

三十一、缓存需要计算和查询(calculation or querying)的变量

对于jQuery选择器,我们最好缓存这些DOM元素。

var navright = document.querySelector('#right');
var navleft = document.querySelector('#left');
var navup = document.querySelector('#up');
var navdown = document.querySelector('#down');

三十二、在调用 isFinite()之前验证参数

isFinite(0/0) ; // false
isFinite("foo"); // false
isFinite("10"); // true
isFinite(10); // true
isFinite(undifined); // false
isFinite(); // false
isFinite(null); // true !!!

三十三、避免数组中的负数索引(negative indexes)

var numbersArray = [1,2,3,4,5];
var from = numbersArray.indexOf("foo") ; // from is equal to -1
numbersArray.splice(from,2); // will return [5]

确保调用 indexOf 时的参数不是负数。

三十四、基于JSON的序列化和反序列化(serialization and deserialization)

var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString is equal to person object */

三十五、避免使用 eval() 和 Function 构造函数

使用 eval 和 Function 构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。

var func1 = new Function(functionCode);
var func2 = eval(functionCode);

三十六、避免使用 with()

使用 with() 会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦。

三十七、避免使用 for-in 来遍历一个数组

避免使用这样的方式:

var sum = 0;
for (var i in arrayNumbers) {
 sum += arrayNumbers[i];
}

更好的方式是:

var sum = 0;
for (var i = 0, len = arrayNumbers.length; i < len; i++) {
 sum += arrayNumbers[i];
}

附加的好处是,i 和 len 两个变量的取值都只执行了一次,会比下面的方式更高效:

for (var i = 0; i < arrayNumbers.length; i++)

为什么?因为arrayNumbers.length每次循环的时候都会被计算。

三十八、在调用 setTimeout() 和 setInterval() 的时候传入函数,而不是字符串。

如果你将字符串传递给 setTimeout() 或者 setInterval(),这个字符串将被如使用 eval 一样被解析,这个是非常耗时的。

不要使用:

setInterval('doSomethingPeriodically()', 1000);
setTimeOut('doSomethingAfterFiveSeconds()', 5000)

而用:

setInterval(doSomethingPeriodically, 1000);
setTimeOut(doSomethingAfterFiveSeconds, 5000);

三十九、使用 switch/case 语句,而不是一长串的 if/else

在判断情况大于2种的时候,使用 switch/case 更高效,而且更优雅(更易于组织代码)。但在判断的情况超过10种的时候不要使用 switch/case。

四十、在判断数值范围时使用 switch/case

在下面的这种情况,使用 switch/case 判断数值范围的时候是合理的:

function getCategory(age) {
 var category = "";
 switch (true) {
 case isNaN(age):
 category = "not an age";
 break;
 case (age >= 50):
 category = "Old";
 break;
 case (age <= 20):
 category = "Baby";
 break;
 default:
 category = "Young";
 break;
 };
 return category;
}
getCategory(5); // will return "Baby"

【译者注:一般对于数值范围的判断,用 if/else 会比较合适。 switch/case 更适合对确定数值的判断】

四十一、为创建的对象指定prototype对象

写一个函数来创建一个以指定参数作为prototype的对象是有可能:

function clone(object) {
 function OneShotConstructor(){};
 OneShotConstructor.prototype= object;
 return new OneShotConstructor();
}
clone(Array).prototype ; // []

四十二、一个HTML转义函数

function escapeHTML(text) {
 var replacements= {"<": "<", ">": ">","&": "&", "\"": """};
 return text.replace(/[<>&"]/g, function(character) {
 return replacements[character];
 });
}

四十三、避免在循环内部使用 try-catch-finally

在运行时,每次当 catch 从句被执行的时候,被捕获的异常对象会赋值给一个变量,而在 try-catch-finally 结构中,每次都会新建这个变量。

避免这样的写法:

var object = ['foo', 'bar'], i;
for (i = 0, len = object.length; i <len; i++) {
 try {
 // do something that throws an exception
 }
 catch (e) {
 // handle exception
 }
}

而使用:

var object = ['foo', 'bar'], i;
try {
 for (i = 0, len = object.length; i <len; i++) {
 // do something that throws an exception
 }
}
catch (e) {
 // handle exception
}

四十四、为 XMLHttpRequests 设置超时。

在一个XHR请求占用很长时间后(比如由于网络问题),你可能需要中止这次请求,那么你可以对XHR调用配套使用 setTimeout()。

var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
 if (this.readyState == 4) {
 clearTimeout(timeout);
 // do something with response data
 }
}
var timeout = setTimeout( function () {
 xhr.abort(); // call error callback
}, 60*1000 /* timeout after a minute */ );
xhr.open('GET', url, true); 

xhr.send();

此外,一般你应该完全避免同步的Ajax请求。

四十五、处理WebSocket超时

通常,在一个WebSocket连接创建之后,如果你没有活动的话,服务器会在30秒之后断开(time out)你的连接。防火墙也会在一段时间不活动之后断开连接。

为了防止超时的问题,你可能需要间歇性地向服务器端发送空消息。要这样做的话,你可以在你的代码里添加下面的两个函数:一个用来保持连接,另一个用来取消连接的保持。通过这个技巧,你可以控制超时的问题。

使用一个 timerID:

var timerID = 0;
function keepAlive() {
 var timeout = 15000;
 if (webSocket.readyState == webSocket.OPEN) {
 webSocket.send('');
 }
 timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
 if (timerId) {
 cancelTimeout(timerId);
 }
}

keepAlive()方法应该被添加在webSOcket连接的 onOpen() 方法的最后,而 cancelKeepAlive() 添加在 onClose() 方法的最后。

四十六、牢记,原始运算符始终比函数调用要高效。使用VanillaJS。

举例来说,不使用:

var min = Math.min(a,b);
A.push(v);

而用:

var min = a < b ? a b;
A[A.length] = v;

四十七、从整数中,随机选取一个数值

有如下公式,非常有用,可以让我们随机显示某些名人名言或者新闻事件!

值=Math.floor(Math.random()*可能值的总数+第一个可能的值)
例如:要想选择一个介于2到10之间的值,我们可以这么写

var num=Math.floor(Math.random()*9+2)

请记住上面公式!~

js运算符单竖杠“|”的用法和作用及js数据处理

刚才在js整数操作的时候,相当于去除小数点,parseInt。在正数的时候相当于Math.floor(),负数的时候相当于Math.ceil() 注:

1. Math.ceil()用作向上取整。
2. Math.floor()用作向下取整。
3. Math.round() 我们数学中常用到的四舍五入取整。

console.log(0.6|0)//0
console.log(1.1|0)//1
console.log(3.65555|0)//3
console.log(5.99999|0)//5
console.log(-7.777|0)//-7

注:除了Math的三个方法处理数字,我们还经常用parseInt()、parseFloat()、toFixed()与toPrecision() 等等。 简单解释:

toFixed方法用法如下:

100.456001.toFixed(2); //100.47

100.456001.toFixed(3); //100.456

Number.prototype.toFixed.call(100.456001,2); //100.47

缺点:用之后就会变成字符串。

toPrecision用法如下:

99.456001.toPrecision(5); //99.456

100.456001.toPrecision(5); //100.46

Number.prototype.toPrecision.call(10.456001,5); //10.456

单竖杠的运算规则

看了上面的例子,大体知道单竖杠可以进行取整运算,就是只保留正数部分,小数部分通过拿掉,但是“|0”,又是如何进行运算的呢,为什么能“|0”能达到取整的目的呢?单竖杠不是0有会是多少呢?

带着这些问题,我们看下面例子:

console.log(3|4); //7
console.log(4|4);//4
console.log(8|3);//11
console.log(5.3|4.1);//5
console.log(9|3455);//3455

好像无规律可以寻找啊?网上搜索吧。http://tools.3water.com/table/priority

这里面提到了单竖杠“|”但是没有javascript的。

好吧,我在这里公布答案吧。其实单竖杠“|”就是转换为2进制之后相加得到的结果。例如我们拿简单的举例:

3|4
转换为二进制之后011|100 相加得到111=7

4|4
转换为二进制之后100 |100 相加得到100=4

8|3
转换为二进制之后1000 |011 相加得到1011=11

以此类推,我在这里就不一一列举了,单竖杠“|”运算就是转换为2进制之后相加得到的结果!都学会了吗?

Javascript 相关文章推荐
列表内容的选择
Jun 30 Javascript
动态加载js和css(外部文件)
Apr 17 Javascript
纯javascript实现自动发送邮件
Oct 21 Javascript
jQuery ajaxSubmit 实现ajax提交表单局部刷新
Jul 04 Javascript
JS简单去除数组中重复项的方法
Sep 13 Javascript
Angular4学习笔记之新建项目的方法
Jul 18 Javascript
JS自定义函数实现时间戳转换成date的方法示例
Aug 27 Javascript
微信小程序实现图片上传功能实例(前端+PHP后端)
Jan 10 Javascript
Vue中常用rules校验规则(实例代码)
Nov 14 Javascript
解决antd 表单设置默认值initialValue后验证失效的问题
Nov 02 Javascript
vue中的计算属性和侦听属性
Nov 06 Javascript
JS Canvas接口和动画效果大全
Apr 29 Javascript
Bootstrap 布局组件(全)
Jul 18 #Javascript
js验证真实姓名与身份证号,手机号的简单实例
Jul 18 #Javascript
Bootstrap零基础入门教程(三)
Jul 18 #Javascript
15位和18位身份证JS校验的简单实例
Jul 18 #Javascript
Bootstrap零基础入门教程(二)
Jul 18 #Javascript
Bootstrap插件全集
Jul 18 #Javascript
全面了解javascript中的错误处理机制
Jul 18 #Javascript
You might like
php面向对象中static静态属性与方法的内存位置分析
2015/02/08 PHP
yii2缓存Caching基本用法示例
2016/07/18 PHP
php获取远程图片并下载保存到本地的方法分析
2016/10/08 PHP
PHP实现基于面向对象的mysqli扩展库增删改查操作工具类
2017/07/18 PHP
PHP实现小程序批量通知推送
2018/11/27 PHP
javascript实现时间格式输出FormatDate函数
2015/01/13 Javascript
JS+CSS实现带关闭按钮DIV弹出窗口的方法
2015/02/27 Javascript
jQuery使用empty()方法删除元素及其所有子元素的方法
2015/03/26 Javascript
JS实现屏蔽shift,Ctrl,alt等功能键的方法
2015/06/01 Javascript
微信企业号开发之微信考勤Cookies的使用
2015/09/11 Javascript
Bootstrap每天必学之警告框插件
2016/04/26 Javascript
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
在Vue组件化中利用axios处理ajax请求的使用方法
2017/08/25 Javascript
karma+webpack搭建vue单元测试环境的方法示例
2018/05/24 Javascript
JavaScript私有变量实例详解
2019/01/24 Javascript
微信小程序清空输入框信息与实现屏幕往上滚动的示例代码
2020/06/23 Javascript
Openlayers实现地图的基本操作
2020/09/28 Javascript
Python获取脚本所在目录的正确方法
2014/04/15 Python
Python 多核并行计算的示例代码
2017/11/07 Python
python发送邮件脚本
2018/05/22 Python
python实现大文本文件分割
2019/07/22 Python
Django在admin后台集成TinyMCE富文本编辑器的例子
2019/08/09 Python
500行python代码实现飞机大战
2020/04/24 Python
Python特殊属性property原理及使用方法解析
2020/10/09 Python
分享29个基于Bootstrap的HTML5响应式网页设计模板
2015/11/19 HTML / CSS
英国护发和美妆在线商店:Klip Shop
2019/03/24 全球购物
物流专业大学生职业生涯规划书范文
2014/01/15 职场文书
《藏戏》教学反思
2014/02/11 职场文书
总账会计岗位职责
2014/03/13 职场文书
个人投资计划书
2014/05/01 职场文书
教师职业道德事迹材料
2014/08/18 职场文书
信访工作汇报材料
2014/10/27 职场文书
工作保证书怎么写
2015/02/28 职场文书
5道关于python基础 while循环练习题
2021/11/27 Python
Spring Boot接口定义和全局异常统一处理
2022/04/20 Java/Android
nginx实现多geoserver服务的负载均衡
2022/05/15 Servers