成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Nodejs中的一些小trick

tomorrowwu / 1664人閱讀

摘要:要達(dá)到想要的效果正確的做法是即用來產(chǎn)生一個(gè)立即作用域,保證回調(diào)函數(shù)執(zhí)行的時(shí)候最近的原型作用域的就是當(dāng)時(shí)循環(huán)的。判斷數(shù)組中是否存在滿足條件的項(xiàng),只要有一項(xiàng)滿足條件,就會(huì)返回。

之前常常因?yàn)椴蛔⒁?,?xí)慣用寫PHP或者Java的方式來寫nodejs,產(chǎn)生了了一些錯(cuò)誤,這里總結(jié)一些小小的trick,以便于展示nodejs的不同,和平時(shí)需要注意的地方。

變量提升
var variable = "global";
console.log(variable); 
function fn () {
    console.log(variable); 
    var variable = "local";
    console.log(variable);
}
fn();

你可能以為這段代碼執(zhí)行結(jié)果為:

global
global
local

但實(shí)際上結(jié)果是

global
undefined
local

原因就是函數(shù)作用域?qū)е戮植孔兞吭谡麄€(gè)函數(shù)體內(nèi)部可見,所以執(zhí)行起來就成了:

 function fn () {
     var variable
     console.log(variable); 
     variable = "local";
     console.log(variable);
 }

函數(shù)內(nèi)部的console.log出于就近原則讀取的是內(nèi)部variable,亦即局部variable覆蓋了全局variable,然后局部variable是整個(gè)函數(shù)體內(nèi)可見,所以相當(dāng)于提升了變量聲明,亦即變量聲明放在了函數(shù)開頭,但是變量初始化還是在原來的位置,所以就是上面展示的順序。
寫Java的時(shí)候我們傾向于在最開始使用一個(gè)局部變量之前聲明它,這樣幫我們清晰它的作用域以及生命周期;但是JavaScript沒有塊級作用域,所以局部變量最好寫在函數(shù)開始,這樣才能更清晰的展示它的作用域(整個(gè)函數(shù)內(nèi)部)和生命周期,避免產(chǎn)生誤解。

有點(diǎn)需要注意的是:聲明寫var與不寫var是有區(qū)別的:

console.log(a);   
a = 1;

會(huì)報(bào)錯(cuò),而下面這個(gè):

console.log(a);   
var a = 1;

結(jié)果是 undefined ,也就是沒有var的聲明不會(huì)提升。

函數(shù)提升

js中創(chuàng)建函數(shù)有兩種方式:函數(shù)聲明式和函數(shù)字面量式。只有函數(shù)聲明才存在函數(shù)提升:

console.log(f1);  
console.log(f2);   
function f1() {}
var f2 = function() {}

結(jié)果:

[Function: f1]
undefined

就是函數(shù)提升導(dǎo)致順序變?yōu)椋?/p>

function f1() {}     
console.log(f1);   
console.log(f2);   
var f2 = function() {}
原型繼承中的坑

JavaScript 沒有 提供對象繼承的語言級別特性,而是通過原型復(fù)制來實(shí)現(xiàn)的。

var util = require("util")
function Superclass(){
    this.a = "a";
}
Superclass.prototype.d = "d";
function Subclass(){
    this.b = "b";
}
util.inherits(Subclass, Superclass);
var superC = new Superclass();
var subC = new Subclass();

console.log(superC.a);
console.log(subC.a);
subC.a = "suba";
console.log(superC.a);
console.log(subC.a);
subC.cc = "cc";
console.log(superC.cc);
console.log(subC.cc);
console.log(superC.d);
console.log(subC.d);

結(jié)果:

a
undefined
a
suba
undefined
cc
d
d
Superclass { a: "a" }

subC僅僅繼承了superC在prototype中定義的屬性d,而構(gòu)造函數(shù)內(nèi)部創(chuàng)造的a屬性沒有被subC繼承。同時(shí),在原型中定義的屬性不會(huì)被console.log作為對象的屬性輸出。在subC中修改屬性a并不會(huì)修改superC的屬性a,但是能獲取superC的屬性d,而且設(shè)置了一個(gè)屬性cc也不會(huì)影響superC。所以對于set操作并不會(huì)修改原型鏈,只有g(shù)et操作才會(huì)體會(huì)到原型鏈(繼承)的存在。

var util = require("util")
function Superclass(){
    this.a = "a";
}
Superclass.prototype.d = "d";
function Subclass(){
    this.b = "b";
}
util.inherits(Subclass, Superclass);
var superC = new Superclass();
var subC = new Subclass();


for(x in subC){
    console.log(x);
}

結(jié)果是

b
d

也就是說 in 關(guān)鍵字能檢測到自有屬性和繼承熟性,這個(gè)可以用 !==來代替

for(x in subC){
    if(subC[x] !== undefined)
        console.log(x);
}

結(jié)果一致, 但是in可以區(qū)分屬性不存在 和 屬性存在且為undefined 兩種情況,而!==不能區(qū)分。
再看下面的:

for(x in subC){
    if(subC.hasOwnProperty(x))
        console.log(x);
}

結(jié)果是

b

也就是說hasOwnProperty能檢測到自身屬性,不包含繼承屬性??偨Y(jié)一下:

superC.hasOwnProperty();             //自有屬性為真
superC.propertyIsEnumerable(superC); //可枚舉屬性為真
Object.keys(superC);                 //所有可枚舉自有屬性
Object.getOwnPropertyNames(superC);  //所有自有屬性
for x in superC                      //自有及其其原型鏈上繼承到的可枚舉屬性
依然是作用域

看看這段代碼:

for(var i = 0; i < 5; i++){
    setTimeout(function(){
        console.log(i);
    },100*i)
}

你可能會(huì)認(rèn)為結(jié)果是

0 1 2 3 4

但是結(jié)果是

5 5 5 5 5

原因就是 settimeout的回調(diào)函數(shù)執(zhí)行時(shí),for循環(huán)已經(jīng)執(zhí)行完畢。i變成了5,而回調(diào)函數(shù)最近的原型作用域上的i(此處也就是全局作用域)就是5,自然就是5了。要達(dá)到想要的效果正確的做法是:

for(var i = 0; i < 5; i++){
    (function(i){setTimeout(function(){
        console.log(i);
    },100*i)})(i)
}

即用 (function(i){})(i);來產(chǎn)生一個(gè)立即作用域,保證settimeout回調(diào)函數(shù)執(zhí)行的時(shí)候最近的原型作用域的i就是當(dāng)時(shí)循環(huán)的i。

說到這個(gè)就得談?wù)勯]包:所謂“閉包”,指的是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。用大白話:閉包的作用就是在一個(gè)函數(shù)執(zhí)行完并返回后,并不回收該函數(shù)所占用的資源,因?yàn)樵摵瘮?shù)的內(nèi)部函數(shù)(或?qū)傩裕┑膱?zhí)行需要依賴該函數(shù)中的屬性。

function outF() {
   var count = 0;
   return function inF(){
      count++;
      console.log(count);
   }
}

var inF= outF();
inF();  // 1
inF();  // 2

可見outF執(zhí)行過后,其屬性count并未回收?;氐缴厦婺莻€(gè)錯(cuò)誤的循環(huán),for創(chuàng)建了若干個(gè)閉包,每個(gè)閉包共享上下文環(huán)境 i。因?yàn)閒or(很大可能)會(huì)先跑完,所以運(yùn)行回調(diào)函數(shù)的時(shí)候 i 已經(jīng)變成了5。而正確的循環(huán)中,也通過匿名函數(shù)創(chuàng)建了閉包,這個(gè)匿名函數(shù)作為外部函數(shù),通過立即調(diào)用,使得settimeout不需要共享循環(huán)中的i,而是獨(dú)享每一次循環(huán)不同的i。

作用域真的可以說是JavaScript的一個(gè)問題,var 聲明是具有整個(gè)函數(shù)內(nèi)部的可見性,而js1.7之后的let的出現(xiàn)算是彌補(bǔ)了這個(gè)缺陷(至于是不是缺陷就見仁見智了),let 聲明的變量只屬于就近的花括號內(nèi)部,看下面的代碼

for(let i = 0; i < 5; i++){
    setTimeout(function(){
        console.log(i);
    },100*i)
}

結(jié)果就是

 0 1 2 3 4

區(qū)別就在于使用了 var 和 let 來生明變量i,let 使得每次程序進(jìn)入花括號就產(chǎn)生了一個(gè)塊級作用域,也就是說settimeout的回調(diào)函數(shù)作用域鏈中最近的i不再是全局的i,而是塊級作用域的i,也就是每一次不同的0,1,2,3,4而不是全局i最后是5。let產(chǎn)生了和上面立即作用域相同的效果。

對象類型

非常奇怪,在Javascript中沒有非常簡單的獲取一個(gè)對象的類別的方法,instanceof 是要檢查原型鏈的,類似于isPropertypeOf,所以無法一步到位獲得最精確地的對象類型,一般用下面這個(gè) classof可以獲得最精確的類型

var a = new Date();

function classof(o){
    if(o===null) return "Null";
    if(o===undefined) return "Undefined";
    return Object.prototype.toString.call(o).slice(8,-1);
}

console.log(classof(a));//Date

之所以不直接用Object.prototype.toString,是因?yàn)楹枚囝愋椭貙懥诉@個(gè)方法,不能保證它輸出是
[object class],所以使用Function.call方法。

萬惡的分號 ;

nodejs中分號; 是可選的,這個(gè)有一定程度的便利,可是在我看來它更多的是造成了混亂,js會(huì)在必要的時(shí)候幫助我們添加分號,它有自己的添加規(guī)則(我們自然都懶得去記)。

var a
a 
=
3
console.log(a)

這個(gè)會(huì)解析成

var a; a = 3;console.log(a);

沒啥毛病。
可是

var equa = function(a,b){
    if(a===b){
        return
        true;
    }
    return false;        
}
console.log(equa(5,5));//undefined

就沒有按預(yù)期執(zhí)行,因?yàn)樗馕龀闪?return;true;返回的自然是undefined。
所以避免混亂最簡單的做法就是老老實(shí)實(shí)的給每一句都加上 ;

數(shù)組相關(guān)
a = [];a[1000]=5; //a.length=1001,雖然a只有一個(gè)元素

a1 = [,,,]; // [undefined,undefined,undefined]
a2 = new Array(3); //數(shù)組根本沒有元素
0 in a1;// true  ,如上所說,in 可以區(qū)分元素不存在和元素值存在且為undefined的情況
0 in a2;// false
高級數(shù)組方法

filter():“過濾”功能,數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù),返回滿足過濾條件組成的數(shù)組。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr2 = arr.filter(function(x, index) {
    return index % 3 === 0 || x >= 8;
}); 
console.log(arr2); //[1, 4, 7, 8, 9, 10]

every():判斷數(shù)組中每一項(xiàng)都是否滿足條件,只有所有項(xiàng)都滿足條件,才會(huì)返回true。

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.every(function(x) {
    return x < 10;
}); 
console.log(arr2); //true
var arr3 = arr.every(function(x) {
    return x < 3;
}); 
console.log(arr3); // false  

some():判斷數(shù)組中是否存在滿足條件的項(xiàng),只要有一項(xiàng)滿足條件,就會(huì)返回true。

reduce() 和 reduceRight(),這兩個(gè)方法都會(huì)實(shí)現(xiàn)迭代數(shù)組的所有項(xiàng),然后構(gòu)建一個(gè)最終返回的值。reduce()方法從數(shù)組的第一項(xiàng)開始,逐個(gè)遍歷到最后。而 reduceRight()則從數(shù)組的最后一項(xiàng)開始,向前遍歷到第一項(xiàng)。
這兩個(gè)方法都接收兩個(gè)參數(shù):一個(gè)在每一項(xiàng)上調(diào)用的函數(shù)和(可選的)作為歸并基礎(chǔ)的初始值。
傳給 reduce()和 reduceRight()的函數(shù)接收 4 個(gè)參數(shù):前一個(gè)值、當(dāng)前值、項(xiàng)的索引和數(shù)組對象。這個(gè)函數(shù)返回的任何值都會(huì)作為第一個(gè)參數(shù)自動(dòng)傳給下一項(xiàng)。第一次迭代發(fā)生在數(shù)組的第二項(xiàng)上,因此第一個(gè)參數(shù)是數(shù)組的第一項(xiàng),第二個(gè)參數(shù)就是數(shù)組的第二項(xiàng)。
下面代碼用reduce()實(shí)現(xiàn)數(shù)組求。

var values = [1,2,3,4,5];
var sum = values.reduceRight(function(prev, cur, index, array){
    return prev + cur;
},0);
console.log(sum); //15
調(diào)用函數(shù)之 this

調(diào)用函數(shù)有4種方式,不同之處就在于調(diào)用上下文,也就是關(guān)鍵字(不是變量,不是屬性名)this的值

函數(shù)調(diào)用 ,亦即直接調(diào)用一個(gè)函數(shù),在非嚴(yán)格模式下this指向全局對象,嚴(yán)格模式下指向undefined。需要注意的是嵌套函數(shù)的this并不指向外層函數(shù)的上下文,而是也遵照這個(gè)規(guī)則。

方法調(diào)用 ,亦即作為一個(gè)類的方法調(diào)用一個(gè)函數(shù),this指向這個(gè)類的對象

構(gòu)造器調(diào)用 ,亦即使用 new 關(guān)鍵字,this指向新建的對象本身

call,apply調(diào)用 ,this指向該函數(shù)綁定的對象

參考

JavaScript 權(quán)威指南 第六版;
JavaScript 語言精粹;
深入淺出 nodejs;
http://blog.csdn.net/u0146071...
https://developer.mozilla.org...

歡迎訪問我的主頁 Mageek`s Wonderland http://mageek.cn/archives/32/

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83827.html

相關(guān)文章

  • FCC 成都社區(qū)·前端周刊 第 11 期

    摘要:正式發(fā)布已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在中的運(yùn)行速度問題。文章內(nèi)容包括什么是內(nèi)存,內(nèi)存生命周期,中的內(nèi)存分配,內(nèi)存釋放,垃圾收集,種常見的內(nèi)存泄漏以及如何處理內(nèi)存泄漏的技巧。 1. Angular 6 正式發(fā)布 Angular 6.0.0 已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在 Angular 中的運(yùn)行速度問題。Angular v6 是統(tǒng)一整體框架、Material ...

    lentrue 評論0 收藏0
  • FCC 成都社區(qū)·前端周刊 第 11 期

    摘要:正式發(fā)布已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在中的運(yùn)行速度問題。文章內(nèi)容包括什么是內(nèi)存,內(nèi)存生命周期,中的內(nèi)存分配,內(nèi)存釋放,垃圾收集,種常見的內(nèi)存泄漏以及如何處理內(nèi)存泄漏的技巧。 1. Angular 6 正式發(fā)布 Angular 6.0.0 已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在 Angular 中的運(yùn)行速度問題。Angular v6 是統(tǒng)一整體框架、Material ...

    NusterCache 評論0 收藏0
  • FCC 成都社區(qū)·前端周刊 第 11 期

    摘要:正式發(fā)布已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在中的運(yùn)行速度問題。文章內(nèi)容包括什么是內(nèi)存,內(nèi)存生命周期,中的內(nèi)存分配,內(nèi)存釋放,垃圾收集,種常見的內(nèi)存泄漏以及如何處理內(nèi)存泄漏的技巧。 1. Angular 6 正式發(fā)布 Angular 6.0.0 已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在 Angular 中的運(yùn)行速度問題。Angular v6 是統(tǒng)一整體框架、Material ...

    betacat 評論0 收藏0
  • Javascript中的一些trick

    摘要:下面是收集了一些中的一些小技巧,會(huì)不定時(shí)更新,歡迎留言補(bǔ)充。專業(yè)的叫法是,可以保持唯一性,具有復(fù)雜的算法,這里僅僅介紹簡單的。以下列舉幾種生成方法第一種隨機(jī)程度可以隨著的調(diào)用次數(shù)而變化第二種原理差不多交換值第一種第二種請自行領(lǐng)悟。 下面是收集了一些Javascript中的一些小技巧,會(huì)不定時(shí)更新,歡迎留言補(bǔ)充。 數(shù)字0-6到一二三四五六日的對應(yīng) Javascript中的日期對象得到...

    ideaa 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<