Javascript 技法100第一篇

1. 神乎其技的 + 号

//使用 `+` 运算符可以快速将一个字符串数值转化为数字
console.log(typeof '1');  //string
console.log(typeof +'1');  //number

//Date类型会转化为number类型的时间戳,精确到ms
console.log(+new Date())  //1484219585488

//相比这种方式转换时间戳简便,Date.parse()只精确到s,ms的位置都为0
console.log(Date.parse(new Date()))  //'1484219585000'

//无法转换为有效的数字一般会得到NaN
console.log(+'abc') //NaN
console.log(+function(){})  //NaN

//数组有点奇特
console.log(+[1,2,3]);  //NaN
console.log(+[]);  //0
console.log(+[5]);  //5

//这还就导致了
console.log(++[[]][+[]]+[+[]])  //10

//为什么呢?一脸懵逼的你一定愿意看看推导

+[] = 0
  =>  ++[[]][+[]]+[+[]] = ++[[]][0]+[0] 

[[]][0] = []
  =>  ++[[]][0] = ++[] = [] + 1 = '' + '1' =  '1'

//++运算符得到的结果一定是number,所以有必要用 + 号再一次转换类型

++[] = +( [] + 1 ) = +'1' = 1
  =>  1 + [0] = '1' + '0' = '10'

2. 妙用数组length属性

var a = [1, 2, 3, 4];

console.log(a.length)   //4

//清空数组
a.length = 0;   //a = []

//截取数组
a.length = 2;   //a = [1, 2]

//扩张数组,用undefined填充
a.length = 5;   //a = [1, 2, 3, 4, undefined]

3. 两个数花式交换

//方案一
var a = 1, b =2;
a = [b, b = a][0];
console.log(a, b);  //2 1

//方案二
var a = 1, b =2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a,b)  //2 1

4. 在读取length的循环中缓存length

var a = [1, 2, 3];
for(var i = 0; i < a.length; i++){
    console.log(a[i])
}

尽管上面的做法没有异议,但每次循环都会额外做一个计算数组length的操作,数组足够小的时候这当然没有任何问题,但当它足够大,它就会成为拖垮性能的一个元凶。假如你尝试过在java中处理一个超大文件的每一个字节时使用上面的做法,你可能会懂得它对性能的破坏力有多大。

必要的时候采用下面这种做法吧:

var a = [1, 2, 3];
for(var i = 0, len = a.length; i < len; i++){
    console.log(a[i]);
}

5. 可动态指定地访问Object属性

var o = {
    name : 'cmx',
    age : 24
}
//可以这么访问一个key
console.log(o.name);

//还可以这么访问一个key
console.log(a['name']);

//再直白一点
var key = 'name';
console.log(a[key]);

看完你能知道应用场景吗?

6. 妙用And和Or

//设置变量的初始默认值
function(a){
    a = a || '默认值';
}

//代替if语句,利用短路特性,如果a变量是有效值(非undefined、null、""、false、0等),执行方法dosomething
a && dosomething(a);

//同理,a为无效值时执行dosomething函数
a || dosomething();

7. 数组拼接

存在两种方式去拼接两个数组:

var a = [1,2];
var b = [3];

//生成一个新的数组,不破坏原数组
a = a.concat(b)    //a=[1,2,3]

//以第一个参数数组作为this,第二个参数数组作为遍历参数,push进第一个数组,最终第一个数组为两个数组的拼接,第二个数组不改变
Array.prototype.push.apply(a, b)    //a=[1,2,3] b=[3]

//相当于
a.push(b[0], b[1], b[2]..)

什么时候用哪种呢?concat由于生成新的数组,必然是占内存的,但它不限制合并数组大小。而第二种方法存在合并数组个数限制(实际上是函数的形参个数限制,不超过65536),内存则相对于concat减少了一个合并后数组的大小。性能上相差不多。

8. 两个操作符typeof跟instanceof

  • typeof判断变量的类型,为一元运算符
  • instanceof判断变量的实例(原型链),为二元运算符

用法上,

console.log(typeof {name:'chenmuxin'}) //'object'

console.log({name:'chenmuxin'} instanceof Object)  //true

typeof返回的是一个全小写字符串,依据变量的类型可能会返回:

'object''number''string''undefined''function''boolean''symbol'

如你所见,不存在数组类型。数组返回的是'object',不仅数组,所有诸如DateRegExp都被作为object看待

'number'类型:

typeof 1
typeof(1)   //也可以这样使用,类似java
typeof 3.1415   //js的number类型统一了整型浮点型等
typeof NaN  //Not a number表示的是无穷和非数值,它是一个number类型
typeof Number(1)    //Number类直接返回的类型也是number

'undefined'类型:

typeof undefined
typeof i_am_undeclared  //一个未声明变量

var i_am_declared_but_undefined_value;  //一个已声明但未赋值变量
typeof i_am_declared_but_undefined_value

最容易迷惑情形:

typeof new Number(1)    //返回'object',使用new操作符时,诸如String、Boolean等引用类返回的是object
typeof Number(1)    //'number'

typeof null //返回'object',js诞生之时起,null就是跟object同类型,这显然不合适。但es6的提案typeof null == 'null'被否决,所以目前都还只能这么认识它

typeof /a/  //正则在不同浏览器上可能有不同类型,可能是function,也可能是object,标准是object。判断正则应使用instanceof

使用instanceof时,首先要保证对象可以new,只有允许new才会存在所谓实例。所以想使用instanceof判断一个基本变量的类型是不可行的。

console.log(1 instanceof Number) //false

数组无法使用typeof来判断,但可以使用instanceof(一定场景下会失败,例如多重iframe)

console.log([1] instanceof Array)  //true

当然也可以使用更稳妥的数组的方法:

console.log(Array.isArray([1])) //true

总结:像数组、正则等继承自Object但具体的对象(首先可以new),我们一般都可以用instanceof去判断。像很多基本变量以及它们的引用类型,我们就用typeof去判断。

9. in和for遍历

var a = [10,20,30];
var b = {name : 'cmx'}

//基本数组遍历
for(var i=0,length = a.length; i < length; i++){
    console.log(a[i]);
}

//of运算符每次循环直接得到数组值
for(var i of a){
    console.log(i);
}

//in运算符每次循环得到当前下标
for(var i in a){
    console.log(a[i]);
}

//in运算符遍历对象时,每次得到对象的key
for(var i in b){
    console.log(i);
    console.log(b[i]);
}

存在一些特殊情况,in遍历时,不仅会把数组(或对象)的每一个下标(key)遍历出来,一旦像下面这样定义了原型属性或方法

Array.prototype.what = function(){ }

in遍历还会把它们一起遍历出来,这里得到一个what。如果没有作必要的判断往往会导致如下:

for(var i in a){
    //打印a[what]出错
    console.log(a[i]);
}

要么不使用原型直接添加的方式,而使用Object.defineProperty并设置可枚举属性为false。要么就in遍历数组时,都判断当前i是否为number类型:

var a = [1, 2, 3];
Array.prototype.cmx = 5;

for(var i in a){
    //+i是因为i遍历出来的都是字符串形式。至于为什么不使用 i != NaN ,因为任意两个NaN不相等啊
    if(!Number.isNaN(+i)){
        console.log(i)
    }
}

因为原型扩展是不允许添加一个number类型的,所以上面的做法成立。

Array.prototype.1 = 1 //error

或者使用通用的方法(同时适合数组和对象)

for(var i in a){
    if(a.hasOwnProperty(i)){
        console.log(a[i])
    }
}

Object.prototype.hasOwnProperty()会忽略对象原型链上的属性和方法。

10. call和apply

我们先来看段代码:

function Chen(){
    this.name = '老陈';
    
    this.sayHello = function(hello){
        console.log('我是老陈的方法');
        console.log(hello + ', I am ' + this.name);
    }
}

function Huang(){
    this.name = '老黄';
    
    this.sayHello = function(hello){
        console.log('我是老黄的方法');
        console.log(hello + ', I am ' + this.name);
    }
}

var chen = new Chen();
chen.sayHello('你好');    //我是老陈的方法  你好, I am 老陈

var huang = new Huang();

chen.sayHello.call(huang,'Hello');  //我是老陈的方法  Hello, I am 老黄

chen.sayHello.apply(huang,['Hi'])  //我是老陈的方法  Hi, I am 老黄

callapply非常像,都是为一个函数指定上下文,并传入参数。唯一的区别在于参数参入的形式。

Function.prototype.call(thisObj, ...args)
Function.prototype.apply(thisObj[, argArray])

call()thisObj作为上下文带上若干个指定的参数值调用某个函数或方法,参数必须展开。

apply()thisObj作为上下文带上一个数组或累数组参数调用某个函数或方法,参数必须组合成一个数组。

由于只是形式不同,故以其中一个作为示例说明:

chen.sayHello.call(huang, 'Hello')

huang作为上下文,调用chensayHello方法,由于chen.sayHello()调用的this.name已经被更改为huang.name,所以得到上面的执行结果。

call或者apply来模拟一下继承:

function Boy(name, love){
    this.name = name;
    this.lova = love;
    
    this.say = function(){
        console.log('I am '+ name +',I like '+ love +',what about you?');
    }
}

function BadBoy(name, love){
    Boy.call(this, name, love);
    
    this.do = function(){
        console.log('I made a mistake!');
    }
}

var badBoy = new BadBoy('张三','打架');
badBoy.say();   //I am 张三,I like 打架,what about you?
badBoy.do();    //I made a mistake!

var boy = new Boy('李四','学习');
boy.say();  //I am 李四,I like 学习,what about you?
boy.do();   //boy.do is not a function

(转载请注明出处,简书-沐心chen)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,204评论 0 4
  • 语法基础 - 词法 字符集 Unicode字符集, 区分大小写 注释 // /* */ 直接量 数字 小数 字符串...
    KeKeMars阅读 872评论 1 11
  • 写过的诗 都是垃圾碎片 生活过的岁月 都是炼狱场 幻想是一只令人 垂怜的花朵 对着湖面不停地 叹息自己的美丽 不被...
    枝楼阅读 184评论 0 0
  • 沉醉在春风里 那些美好 恍惚 闪烁 浩荡春光 光阴深静 听一曲春风引 等待重逢
    夏天里的飞天喵阅读 278评论 2 1
  • 楼市政策不断出台,调控力度不断加深,很多准备入手买房或观望的人在此时下手一定要注意了,别让自己辛辛苦苦筹集的首付和...
    哈思琪阅读 236评论 0 0