PIXNET Logo登入

互聯網 - 大數據

跳到主文

本部落格為互聯網熱門頭條訊息管理中心

部落格全站分類:生活綜合

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 3月 09 週四 201720:16
  • 總結的JS數據類型判定(非常全面)


文章出處
用typeof 來檢測數據類型
Javascript自帶兩套類型:基本數據類型(undefined,string,null,boolean,function,object)和對象類型。
但是如果嘗試用typeof 來檢測對象類型都一律返回"object"并不能加以區分
typeof null // "object"
typeof [] // "object"
typeof document.childNodes //"object"
typeof /\d/ //"object"
typeof new Number() //"object"

 
用 constructor 屬性來檢測類型的構造函數
[].constructor === Array //true
document.childNodes === NodeList //true
/\d/.constructor === RegExp //true
function isRegExp(obj) {
return obj && typeof obj === "object" && obj.constructor === RegExp;
}
//檢測正則表達式對象
function isNull(obj){
return obj === null;
}

用construct檢測可以完成大多數的類型檢測,null特殊直接比較。然而iframe中的數組類型確無法檢測出正確類型,這是用construct檢測的一個缺陷;同時在舊版本IE下DOM和BOM的construct是無法訪問的
利用 Object.prototype.toString 來判斷
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(/\d/) // "[object RegExp]"
Object.prototype.toString.call(1)//"[object Number]"

來看看jQuery源碼中是如何使用toString方法的
/*
* jQuery JavaScript Library v1.11.2
*/
var class2type = {}; //用來保存js數據類型

jQuery.each(
"Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {//構造class2type存儲常用類型的映射關系,遍歷基本類型并賦值,鍵值為 [object 類型]
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
type:
function( obj ) {
if ( obj == null ) {//首先如果是null則返回null字符串
return obj + "";
}
//接著判斷給定參數類型是否為object或者function,是的話在映射表中尋找 toString后的鍵值名稱并返回,不是的話利用typeof就可以得到正確類型。
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call(obj) ]
|| "object" :
typeof obj;
},
/****************************/
jQuery.type(
/\d/) //"regexp"
jQuery.type(new Number()) //"number"

這里能夠使用toString方法來檢測是因為不同對象都會重新定義自己的toString方法
說說一些特殊類型的檢測
上述調試是在IE8中進行的,因為undefined 在javascript中并不是關鍵字,在IE8以下(之后的版本不可以賦值)是可以賦值的,查看jQuery.type源碼可知,對于undefined檢測由是 typeof undefined完成的。jQuery.type并不能在舊的IE中檢測出undefined的正確性。想要獲得純凈的undefined可以使用void 0 
另外,對于DOM,BOM對象在舊的IE中使用Objec.prototype.toString檢測出來的值均為 “[object Object]”
但是在chrome下的結果卻完全不同(chrome可以檢測出真實類型)
了解一下jQuery檢測特殊類型
isWindow: function( obj ) {//ECMA規定window為全局對象global,且global.window === global
return obj != null && obj == obj.window;
},
isPlainObject:
function( obj ) {
var key;
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
try {//判斷它最近的原形對象是否含有isPrototypeOf屬性
if ( obj.constructor &&
!hasOwn.call(obj, "constructor") &&
!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
}
catch ( e ) {
return false;
}
if ( support.ownLast ) {
for ( key in obj ) {
return hasOwn.call( obj, key );
}
}

 
mass Framework相對jQuery中改善的地方
var class2type = {//將可能出現的類型都映射在了class2type對象中,從而減少isXXX函數
"[object HTMLDocument]": "Document",
"[object HTMLCollection]": "NodeList",
"[object StaticNodeList]": "NodeList",
"[object DOMWindow]": "Window",
"[object global]": "Window",
"null": "Null",
"NaN": "NaN",
"undefined": "Undefined"
};
type:
function(obj, str) {
var result = class2type[(obj == null || obj !== obj) ? obj : serialize.call(obj)] || obj.nodeName || "#"; //serialize == class2type.toString
if (result.charAt(0) === "#") { //兼容舊式瀏覽器與處理個別情況,如window.opera
//利用IE678 window == document為true,document == window竟然為false的神奇特性
if (obj == obj.document && obj.document != obj) {//對DOM,BOM對象采用nodeType(單一)和item(節點集合)進行判斷
result = "Window"; //返回構造器名字
} else if (obj.nodeType === 9) {
result
= "Document"; //返回構造器名字
} else if (obj.callee) {
result
= "Arguments"; //返回構造器名字
} else if (isFinite(obj.length) && obj.item) {
result
= "NodeList"; //處理節點集合
} else {
result
= serialize.call(obj).slice(8, -1);
}
}
if (str) {
return str === result;
}
return result;
}

 
類數組
類數組是一類特殊的數據類型存在,他們本身類似Array但是又不能使用Array的方法,他們有一個明顯的特點就是含有length屬性,而且鍵值是以整數有序的排列的。這樣的數組可以通過 Array.slice() 這樣的方法轉換成真正的數組,從而使用Array提供的方法。
常見類數組:arguments,document.forms,document.getElementsByClassName(等一些列節點集合NodeList,HTMLCollection),或者是一些特殊對象,如下所示:
var arrayLike={ 
0:"a",
1:"b",
2:"c",
length:
3
}

通常情況下通過Array.slice.call既可以轉換類數組,但是舊IE的HTMLCollection,NodeList不是Object的子類,不能使用該方法,這時候需要構建一個空數組,然后將遍歷節點push就如空數組中,返回新生成的數組即可,同時要區別出window 和 string對象,因為這類的對象同樣含有length>=0(length不可被修改),但是不是類數組。
 
jQuery如何處理類數組的
makeArray: function( arr, results ) {
var ret = results || [];
if ( arr != null ) {
if ( isArraylike( Object(arr) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
//jQuery.merge 合并數組 ,若是字符串則封裝成數組河濱,不是則世界合并
} else {
push.call( ret, arr );
}
}
return ret;
}

 
Ext.js是如何處理類數組的
toArray: function(iterable, start, end) {
if (!iterable || !iterable.length) {
return []; //非類數組類型直接返回[]
}
if (typeof iterable === 'string') {
iterable
= iterable.split(''); //分解字符串
}
if (supportsSliceOnNodeList) {
return slice.call(iterable, start || 0, end || iterable.length); //對于NodeList支持
}
var array = [],
i;
start
= start || 0;
end
= end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
for (i = start; i < end; i++) {
array.push(iterable[i]);
}
return array;
}

 
mass Framework.js是如何處理類數組的
slice: W3C ? function(nodes, start, end) { //var W3C = DOC.dispatchEvent; IE9開始支持W3C的事件模型
return factorys.slice.call(nodes, start, end);
} :
function(nodes, start, end) {
var ret = [],
n
= nodes.length;
if (end === void 0 || typeof end === "number" && isFinite(end)) {
start
= parseInt(start, 10) || 0;
end
= end == void 0 ? n : parseInt(end, 10);
if (start < 0) {
start
+= n;
}
if (end > n) {
end
= n;
}
if (end < 0) {
end
+= n;
}
for (var i = start; i < end; ++i) {
ret[i
- start] = nodes[i];
}
}
return ret;
}

(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:15
  • 關于數組添加值和訪問值的一些小問題


文章出處
今天來看看關于數組方面的一些小問題,可能對你會有一些小小的幫助,當然如果我有說錯的地方也歡迎指教,畢竟我也是一個菜鳥。
 1.
1 // var arr = [1,2,3];
2 // arr["bbb"]="nor 1";
3 // arr[-2]="nor 2";
4 // console.log(arr); >> [1, 2, 3, bbb: "nor 1", -2: "nor 2"]
5 // console.log(arr.bbb) >> "nor 1"

 
如果我們想往數組里面添加一個值,以[]的形式添加,如果寫的是負數或者字符串那么它是在數組的末尾添加,并且它是以鍵值對的形式添加的,所以下次訪問這個值的時候可以使用點的形式訪問,但是如果是數字必須通過[]訪問。
2.
1 // var arr = [1,2,3];
2 // arr["bbb"]="nor 1";
3 // console.log(arr); [1, 2, 3, bbb: "nor 1"]
4 // console.log(arr[3]) undefined

如果通過字符串或者負數往數組里面添加一個值,那么下次訪問的時候也必須通過鍵值對形式訪問
3.
1 // var arr = [1,2,3];
2 // arr["bbb"]="nor 1";
3 // arr[-2]=222;
4 // arr.push(4);
5 // console.log(arr); >> [1, 2, 3, 4, bbb: "nor 1"]
6 // console.log(arr.length); >> 4

 
// 值得注意的是通過字符串或者負數添加的值,那個數組是不會添加它的長度的,并且使用這種方式來添加的永遠會在數組的最后面,因為我們使用push方法添加數字4的時候我們發現它并沒有把是添加到最后后面,大家都知道push方法的將值添加到數組的末尾的。也許我們可以得出一個結論那就是數字和數字排列,鍵值對與鍵值對排列。
 
 
更新數組小問題。
 
1 // var num = [];
2 // num.push(4,3,5); >>返回值是添加的最后那個數也就是數字5
3 // num.reverse(); >>數組倒序排列,不是按照大小,是反過來
4 // console.log(num) >>[5, 3, 4]

 
 
 
1 var num = [];
2 num[5,"a",0]="111"; >>["111"] 如果末尾寫的是0或者數組長度加1那么和正常情況一樣。
3 console.log(num);

 
1 var num = [];
2 num[5,"a",6]="111";
3 console.log(num); >>[6: "111"]

 
// 后面的會把前面的覆蓋,最后一位寫的索引不能大于數組長度+1,否則不管你寫的是不是數字都是通過鍵值對的方式添加,如果是負數也是一樣的。
 
1 // var a = [];
2 // a[10] = 10;
3 // console.log(a); >>[10: 10]
4 // console.log(a.length); >>11
5 // console.log(a[0]); >>undefined
6 // console.log(a[10]); >>10

// 如果數組的長度是0或者沒有你要添加的那個索引那么長,那么js會把之前的值全部設置成undefined,并且用鍵值對的形式添加的。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:15
  • 面向對象tab欄例子分析


文章出處
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
ul{
margin:0;
padding:0;
}
li{
list-style:none;
width:218px;
height:200px;
box-shadow:0 0 0 1px #ccc;
display:none;
}
a{
display:inline-block;
padding:10px 20px;
border:1px solid #ccc;
text-decoration:none;
margin-left:-1px;
}
.action{
display:block;
}
</style>
</head>
<body>
<!--
1.程序具有良好的結構。本文檔所關注的核心。
2.容易理解,代碼公用性強
-->
<div id="box">
<div class="class1">
<a href="javascript:;">游戲
<a href="javascript:;">平臺
<a href="javascript:;">服務</a>
</div>
<div class="class2">
<ul>
<li class="action">游戲平臺</li>
<li>平臺平臺</li>
<li>服務平臺</li>
</ul>
</div>
</div>
<div id="box2">
<div class="class1">
<a href="javascript:;">游戲
<a href="javascript:;">平臺
<a href="javascript:;">服務</a>
</div>
<div class="class2">
<ul>
<li class="action">游戲平臺</li>
<li>平臺平臺</li>
<li>服務平臺</li>
</ul>
</div>
</div>
<script defer="defer">
// 初始化
function Util(){
}
// 獲取元素
Util.prototype.getDom = function(dom){
return document.querySelectorAll(dom);
};
// 點擊事件
Util.prototype.click = function(dom,callback){
var doms = this.getDom(dom);
if(!doms.length){
doms.addEventListener('click',callback(this,0));
}
for(var i=0;i<doms.length;i++){
(function(index){
doms[i].addEventListener('click',function(){
callback(this,index);
})
}(i))
}
};
// 顯示
Util.prototype.show = function(dom){
this.isDisplay(true,dom);
};
// 隱藏
Util.prototype.hide = function(dom){
this.isDisplay(false,dom);
};
// 顯示隱藏
Util.prototype.isDisplay = function(is,dom){
if(is){
if(!dom.length){
dom.style.display = 'block';
return false;
}
for(var i=0;i<dom.length;i++){
dom[i].style.display = 'block';
}
}else{
if(!dom.length){
dom.style.display = 'none';
return false;
}
for(var i=0;i<dom.length;i++){
dom[i].style.display = 'none';
}
}
};
// 當前顯示其他隱藏
Util.prototype.action = function(doms,index){
this.hide(this.getDom(doms));
this.show(this.getDom(doms)[index]);
};
// tab欄組件
Util.prototype.tab = function(doms1,doms2){
var _this = this;
this.click(doms1,function(item,index){
_this.action(doms2,index);
})
};
var util = new Util();
// util.click('#box>.class1>a',function(item,index){
// util.action('#box>.class2 li',index);
// // util.hide(util.getDom('#box>.class2 li'));
// // util.show(util.getDom('#box>.class2 li')[index]);
// })
// 點擊a標簽讓對應的li顯示
util.tab('#box>.class1>a','#box>.class2 li');
util.tab('#box2>.class1>a','#box2>.class2 li');
</script>
</body>
</html>

  這段代碼并不能說是完全用面向對象思想寫的,怎么說呢,我們來看看,它一共分成了以下幾個部分:創建一個構造函數,給這構造函數的原型上添加了一些方法,連tab欄也一道封裝到了那個構造函數里面,這樣從整體上來看的話,這整個功能更像是一個工具函數。因此并不能說它是一個完整的面向對象的例子,于是寫完之后發現不對勁,這更本就不像面向對象,重新寫了一個,就是底下的這個例子,棒棒的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
ul
{
margin
:0;
padding
:0;
}
li
{
list-style
:none;
width
:218px;
height
:200px;
box-shadow
:0 0 0 1px #ccc;
display
:none;
}
a
{
display
:inline-block;
padding
:10px 20px;
border
:1px solid #ccc;
text-decoration
:none;
margin-left
:-1px;
}
.action
{
display
:block;
}
</style>
</head>
<body>
<!--
1.程序具有良好的結構。本文檔所關注的核心。
2.容易理解,代碼公用性強
-->
<div id="box">
<div class="class1">
<a href="javascript:;">游戲
<a href="javascript:;">平臺
<a href="javascript:;">服務</a>
</div>
<div class="class2">
<ul>
<li class="action">游戲平臺</li>
<li>平臺平臺</li>
<li>服務平臺</li>
</ul>
</div>
</div>
<div id="box2">
<div class="class1">
<a href="javascript:;">游戲
<a href="javascript:;">平臺
<a href="javascript:;">服務</a>
</div>
<div class="class2">
<ul>
<li class="action">游戲平臺</li>
<li>平臺平臺</li>
<li>服務平臺</li>
</ul>
</div>
</div>
<script defer="defer">
// 初始化
function Util(){
}
// 獲取元素
Util.prototype.getDom = function(dom){
return document.querySelectorAll(dom);
};
// 添加事件
Util.prototype.toggleOn = function(dom,way,callback){
var doms = this.getDom(dom);
if(!doms.length){
doms.addEventListener(way,callback(
this,0));
}
for(var i=0;i<doms.length;i++){
(
function(index){
doms[i].addEventListener(way,
function(){
callback(
this,index);
})
}(i))
}
};
// 顯示元素
Util.prototype.show = function(dom){
this.isDisplay(true,dom);
};
// 隱藏元素
Util.prototype.hide = function(dom){
this.isDisplay(false,dom);
};
// 顯示隱藏元素
Util.prototype.isDisplay = function(is,dom){
if(is){
if(!dom.length){
dom.style.display
= 'block';
return false;
}
for(var i=0;i<dom.length;i++){
dom[i].style.display
= 'block';
}
}
else{
if(!dom.length){
dom.style.display
= 'none';
return false;
}
for(var i=0;i<dom.length;i++){
dom[i].style.display
= 'none';
}
}
};
// 讓當前那個元素顯示
Util.prototype.action = function(doms,index){
this.hide(this.getDom(doms));
this.show(this.getDom(doms)[index]);
};
// tab組件
function Tab(doms1,doms2){
var util = new Util();
this.doms1 = doms1;
this.doms2 = doms2;
};
// tab切換
Tab.prototype.toggleTab = function(way,callback){
var util = new Util();
var _this = this;
util.toggleOn(
this.doms1,way,function(item,index){
if(callback){callback(util.getDom(_this.doms1),item,index)};
util.action(_this.doms2,index);
})
};
// 實例1
var tab = new Tab('#box>.class1>a','#box>.class2 li');
tab.toggleTab(
'mouseout');
// 實例2
var tab2 = new Tab('#box2>.class1>a','#box2>.class2 li');
tab2.toggleTab(
'mouseover',function(items,item,index){
for(var i=0;i<items.length;i++){
items[i].style.color
= '';
}
item.style.color
= 'red';
});
</script>
</body>
</html>

這段代碼和之前那段不同之處在于我把tab重新創建了一個構造函數,因為tab本來就是獨立的,這段代碼還有一個還有一個好處就是我使用了高階函數,使用起來特別爽。
就是這一段:

  


for(var i=0;i<doms.length;i++){
(function(index){
doms[i].addEventListener(way,function(){
callback(this,index);
})
}(i))
}

  


使用如下:

  


var tab2 = new Tab('#box2>.class1>a','#box2>.class2 li');
tab2.toggleTab('mouseover',function(items,item,index){
for(var i=0;i<items.length;i++){
items[i].style.color = '';
}
item.style.color = 'red';
});

  


 高階函數,大家可以搜索一下,這里不做介紹。
 
這里主要想說是面向對象就是把一個大的代碼塊拆分成很多個小的代碼塊,如果是一個功能就是一個代碼塊,另外一個功能就是另外一個代碼塊,然后可以把一些公用的方法弄成一個函數庫。
 
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:15
  • 那些年我們一起過的JS閉包,作用域,this,讓我們一起劃上完美的句號。


文章出處
  之前有寫過閉包,作用域,this方面的文章,但現在想想當時寫的真是廢話太多了,以至于繞來繞去的,讓新手反而更難理解了,所以就有了此篇文章,也好和閉包,作用域,this告一段落。
    
    第一個問題:什么是閉包?
    我不想回答這個問題,但是我可以告訴你的是閉包可以解決函數外部無法訪問函數內部變量的問題。下面是一段沒有使用閉包的代碼:

  function fn(){


    var a = 10;


  }


     alert(a);


     //報錯了,因為a沒有定義,雖然函數fn里面定義了a但是,但是它只能在函數fn中使用。也就是作用域的問題。


   再看‘閉包可以解決函數外部無法訪問函數內部變量的問題’這段話,好像有點意思,那么究竟閉包是怎么做的,看下面代碼。

  function fn(){


        //定義了一個變量name


   var name = '追夢子';


        //我現在想在外部訪問這個變量name怎么辦呢?哈:不是有return,我把它返回出去,我再用個變量接收一下不就可以了,哈哈哈哈~~~~~


         return name;


      }


      var name = fn();//接收fn返回的name值。


      alert(name);//追夢子;


     ·······這里的閉包就是利用函數的return。除了通過return還可以通過其他的幾種方法如下:
  
  方法1:

    


function fn(){
  var a = 0;
  b = a;
}
alert(b)


  這里利用了js的一個特性,如果在函數中沒有用var定義變量,那么這個變量屬于全局的,但這種方法多少有些不好。
  
  方法2:

  


var f = null;
function fn(){
  var a = 0;
  f = function(){
    a++;
    f.a = a;
  };
}
fn();
f();
alert(f.a);//1
f();
alert(f.a);//2


 
    但好像也沒有那樣神奇對吧?其實閉包還有一個很重要的特性。來看一個例子。

  var lis= document.getElementsByTagName['li']; 


  //假如這段代碼中的lis.length = 5;


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


    lis[i].onclick = function(){


      alert(i);


    };


     }


  最終結果是不管單擊哪個li元素都是彈5。不信你試試。為什么呢。看下面分析。

    


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


      }


      // i = 5對吧


  lis[0].onclick = function(){


    alert(i); 


  };


  lis[1].onclick = function(){


    alert(i); 


  };


  lis[2].onclick = function(){


    alert(i);


  };


  lis[3].onclick = function(){


    alert(i);


  };


  lis[4].onclick = function(){


    alert(i);


  };


    為什么會這樣呢,因為你for循環只是給li綁定事件,但是里面的函數代碼并不會執行啊,這個執行是在你點擊的時候才執行的好吧?但是此時的i已經是5了,所以所有的都打印出5來了。
  如果想解決這個問題我們可以使用閉包,閉包的特點不只是讓函數外部訪問函數內部變量這么簡單,還有一個大的特點就是通過閉包我們可以讓函數中的變量持久保持。來看。

  function fn(){


    var num = 0;


   return function(){


    num+=1;


           alert(num);   


         };  


      }


      var f = fn();


      f(); //1


      f(); //2


     如果你是初學者可能沒覺得這有什么。OK,讓你看個東西。

  function fn(){


        var num = 5;


        num+=1;


        alert(num);


     }  


    fn(); //6


    fn(); //6


     為什么呢?因為函數一旦調用里面的內容就會被銷毀,下一次調用又是一個新的函數,和上一個調用的不相關了,不過有個特殊的情況,看這:

  


  function fn(){


    var num = 0;


   return function(){


    num+=1;


           alert(num);   


         };  


      }


      var f = fn();


      f(); //1


      f(); //2


    


    這段代碼很簡單,不要被它欺騙了,我們首頁定義了一個fn函數,里面有個num默認為0,接著返回了一個匿名函數(也就是沒有名字的函數)。我們在外部用f接收這個返回的函數。這個匿名函數干的事情就是把num加1,還有我們用來調試的alert。
  這里之所以執行玩這個函數num沒有被銷毀是因為那個匿名函數的問題,因為這個匿名函數用到了這個num,所以沒有被銷毀,一直保持在內存中,因此我們f()時num可以一直加。
   這里你可以看不懂了,之所以有這種感覺是因為js回收機制你不懂,強烈建議你看我之前的再次講解js中的回收機制是怎么一回事。這篇文章。
 
   關于閉包的知識就到這里了,如果你想看關于閉包的案例可以看這篇:從閉包案例中學習閉包的作用,會不會由你。
   而外:關于在for循環中綁定事件打印變量i是最后一次。
  
   而外說一句:這里并不是說return就是閉包,這里只是強調return的重要性,如果你還是一個新手建議你多看一些初級文章,在來看這篇文章,希望你會有新收獲。寫這篇文章一開始我也說了它的目的是回顧一下當初我沒有理解的地方,當初已經理解的這篇文章并沒有過多的去講。
 
 作用域竟然上面已經講完了~~~
   
   大前端 369451410歡迎你的加入。
 
   那就說一下this:
  我們經常用this,但是也許你還不清楚它是什么吧?

     lis[i].onclick=function(){this.style.border="1px solid #ccc";} ;


     此時的this表示lis[?]它的引用。


     這里的i不是i實際上是一個準確的數字:如lis[2].onclick = function(){this.style.border="1px solid #ccc";}; this = lis[2] ;   


     簡單來說this它始終引用一個對象。
       lis[2]它也一個對象,是一個HTMLElement對象。
       其實不管什么情況下它都會有對象的,這個你不用操心,看

    function fn(){


     this.name = "追夢子";    


          };    


          fn();


          alert(this.name);//追夢子


          //當然也可以這樣


    alert(name);


           雖然這段代碼中看似沒有對象,但大錯特錯,因為瀏覽器環境中默認就有一個window對象,因此你在函數中直接用this.name實際上這個this就表示window。

  var json = {


    name:'yyy',


    fn:function(){alert(this.name)} 


    };


   json.fn(); // yyy;


  fn屬于json,所以this實際上就是json。
     如果你是初學者建議你暫時先記住這三點,當然this還有很多要說的,不過做為初學者你可以在項目中通過console.log來檢查this是否是你預期的那樣。
     更多關于this的內容,可以看徹底理解js中this的指向,不必硬背。
 
     這篇文章并不算是一篇入門的教程,這篇文章主要是總結之前沒有理解的地方,或者是以一種更加簡單明了的方式寫的,當然是按照我自己的理解來的,不一定你能理解,sorry,好了一切就從這里結束吧。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(1)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:15
  • 設計模式之封裝,學習筆記


文章出處
  封裝即把代碼隱藏起來,why?好好的為什么要隱藏起來,這里指的隱藏并非真的隱藏,而是把一些復雜的代碼給包裹起來,留下的是一個接口,到時候要用的時候直接調用這個接口即可,這樣那些不是干技術的也可以輕松上手了。有時我們還會把一些私有屬性屬性給封裝起來,如下:

function fn(){
  var _name = 'javascript';
  return {getName:function(){
    return _name;
  }};
}
fn().getName(); //javascript


或

var f = (function(){
  var _name = 'javascript';
  return function(){
    return _name;
};
}());


或
 

var f = null;
(function(){
  var _name = 'javascript';
  f = _name;
}())
alert(f); //javascript


  這樣外部就無法修改里面的_name值了,如果想讓外部修改可以這樣。


var f = (function(){
  var _name = 'javascript';
  return {
    getName:function(){
      return _name;
    },
    setName:function(name){
      _name = name;
    }
  };
}());


f.getName(); //javascript
f.setName('CSS3');
f.getName(); //CSS3


  封裝還有一點就是把將來可能會發生變化的給封裝起來,另外就是它不在乎里面的代碼是怎么實現的,它只關心你留給他的接口是否有發生變化。如下就是一個封裝變化點。
 

function getByClass(className){
  var tags = document.getElementsByTagName('*');
  var arr = [];
  var t = null;
  for(var i=0,len=tags.length;i<len;i++){
    t = tags[i].className.split(' ');
    for(var k=0;k<t.length;k++){
      if(t[k]===className){
        arr.push(tags[i]);
        break;
      }
    }
  }
  return arr;
}
getByClass('className');


  這段代碼的意思是通過class來獲取元素,大家知道IE低版本瀏覽器不兼容document.getElementsByClassName。所以我們進行了封裝,使用的話就只需要通過getByClass來獲取,假如有一天瀏覽器都兼容document.getElementsByClassName這個方法的話可以這樣。

function getByClass(className){
  return document.getElementsByClassName(className);
}
getByClass('li');


使用方法和上面還是一樣的,這就是封裝變化點,不改變接口,只改變內部細節。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(8)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:15
  • JS中call、apply、bind使用指南,帶部分原理。


文章出處
為什么需要這些?主要是因為this,來看看this干的好事。
 

box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};


我們原本以為這里面的this指向的是box,然而卻是Window。一般我們這樣解決:

box.onclick = function(){
  var _this = this;
  function fn(){
    alert(_this);
  }
  fn();
};


將this保存下來。
 
還有一些情況,有時我們想讓偽數組也能夠調用數組的一些方法,這時call、apply、bind就派上用場了。
 
我們先來解決第一個問題修復this指向。


box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};


改成如下:
 

box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};


很神奇吧,call的作用就是改變this的指向的,第一個傳的是一個對象,就是你要借用的那個對象。
 

fn.call(this);


 
  這里的意思是讓this去調用fn這個函數,這里的this是box,這個沒有意見吧?如果這個你不清楚,很可能你是javscript的新朋友。box調用fn,這句話非常重要,我們知道this它始終指向一個對象,剛好box就是一個對象。那么fn里面的this就是box。
 

box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};


 
這句話在某些情況下是可以簡寫的,比如:


box.onclick = function(){
  var fn = function(){
    console.log(this); //box
  }.call(this);
};


 
或者這樣:
 

box.onclick = function(){
  (function(){
    console.log(this);
  }.call(this)); //box
};


 
又或者這樣:


var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016


 
call和apply、bind但是用來改變this的指向的,但也有一些小小的差別。下面我們來看看它們的差別在哪。
 

function fn(a,b,c,d){
  console.log(a,b,c,d);
}


//call
fn.call(null,1,2,3);


//apply
fn.apply(null,[1,2,3]);


//bind
var f = fn.bind(null,1,2,3);
f(4);


 
結果如下:


1 2 3 undefined
1 2 3 undefined
1 2 3 4


  前面說過第一個參數傳的是一個你要借用的對象,但這么我們不需要,所有就傳了一個null,當然你也可以傳其他的,反正在這里沒有用到,除了第一個參數后面的參數將作為實際參數傳入到函數中。
  call就是挨個傳值,apply傳一個數組,bind也是挨個傳值,但和call和apply還有多少不同,使用call和apply會直接執行這個函數,而bind并不會而是將綁定好的this重新返回一個新函數,什么時候調用由你自己決定。


var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016


這里也就是為什么我要用bind的原因,如果用call的話就會報錯了。自己想想這個sayHello在obj都已經執行完了,就根本沒有sayHello這個函數了。
 
這幾個方法使用的好的話可以幫你解決不少問題比如:
 
正常情況下Math.max只能這樣用

Math.max(10,6)


但如果你想傳一個數組的話你可以用apply

var arr = [1,2,30,4,5];
console.log(Math.max.apply(null,arr));


又或者你想讓偽數組調用數組的方法

function fn(){
  [].push.call(arguments,3);
  console.log(arguments); //[1, 2, 3]
}
fn(1,2);


再者:

var arr = ['aaabc'];
console.log(''.indexOf.call(arr,'b')); //3


牛逼不,簡直偷梁換柱,當然還有很多可以利用的,自己盡情花輝去吧。
 
簡單說一下這種偷梁換柱的原理吧,實際上瀏覽器內部根本就不在乎你是誰,它只關心你傳給我的是不是我能夠運行的,如下:
 
正常情況


var str = 'aaabc';
console.log(str.indexOf('b'));


 
而這種情況其實做的事情和上面一模一樣,看我來拆解。
 

var arr = ['aaabc'];
''.indexOf.call(arr);


 
這句話就是說讓arr調用字符串的indexOf方法,前面說過了瀏覽器內部不在乎你是誰,所以誰都可以來調用,但不是100%成功,具體看如下。
 

''.indexOf.call(arr,'b')


這里的arr就是['aaabc'],內部很可能拆成了'aaabc',因此就成了下面的這段代碼。
 

'aaabc'.indexOf('b');


這就是它們的秘密。
 
這里得說一下bind在某些瀏覽器下不兼容。我們來模擬一個玩玩。


Function.prototype.$bind = function(obj){
    //保存當前this
  var _this = this;
    //截取除了第一個以外的所有實際參數
  var a = [].slice.call(arguments,1);
    //返回一個新函數
  return function(){
    //讓當前那個調用的函數的this指向obj,并且把實參傳給它,這里用了concat是因為,我們可能在綁定以后還傳遞參數,所以才把他們合并起來。如f(4)這個是在綁定以后傳的參數,a這個argument是綁定時的。
    _this.apply(obj,a.concat([].slice.call(arguments)));
  };
};


function fn(a,b,c,d){
  console.log(a,b,c,d);
}


var f = fn.$bind(null,1,2,3);
f(4);


 
這個方法和實際上的bind還是差別很大的,如


var arr = ['JSS'];


var index = ''.indexOf.$bind(arr,'S');
console.log(index())


------------------


function fff(){
  [].push.$bind(arguments,1);
  console.log(arguments);
}


fff();


這些都沒法使用,因為技術有限就沒辦法帶大家封裝一個完美的bind了,如果有需要網上搜索一下吧。
 
結束了啊。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(8)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:14
  • Javascript函數中的高級運用


文章出處
  先介紹一下js中的高階函數,所謂的高階函數就是,一個函數中的參數是一個函數或者返回的是一個函數,就稱為高階函數。
  js中已經提高了一下高階函數,使用起來非常棒,當然我們也可以自己實現,我介紹幾種ES5/ES6新增的數組函數。
  首先是forEach,forEach它接受兩個參數,第一個函數,第二個傳一個this引用對象(可以不傳),函數支持傳3個參數第一個表示遍歷的當前值,第二個為索引,第三個表示當前對象。

[1,2,4,5].forEach(function(item,index){
  console.log(item,index);
})


  模擬forEach的實現

Array.prototype.for = function(fn){
  for(var i=0;i<this.length;i++){
    fn(this[i],i);
  }
};
[2,3,4,5,6].for(function(item,index){
  console.log(item,index);
})


  map返回處理過后的一個新數組


var arr = [1,2,3,4,5];
var a = arr.map(function(item,index){
  if(index>0){
    return item*index;
  }
  return item;
})


console.log(a); //[1, 2, 6, 12, 20]
console.log(arr); //[1, 2, 3, 4, 5]


  模擬實現map


var arr = [1,2,3,4,5];
Array.prototype.m = function(fn){
  var arr = [];
  for(var i=0;i<this.length;i++){
    arr.push(fn(this[i],i,this));
  }
  return arr;
};
console.log(arr.m(function(item,index,thisValue){
  console.log(thisValue); //[1, 2, 3, 4, 5]
  if(item>3){
    return item;
  }
  return item-1;
})) //[0, 1, 2, 4, 5]


  
  some方法用于檢測數組中的元素是否滿足指定條件,如果有一個元素滿足條件,則表達式返回true , 剩余的元素不會再執行檢測,如果沒有滿足條件的元素,則返回false。

Array.prototype.so = function(fn){
  for(var i=0;i<this.length;i++){
    if(fn(this[i],i,this)){
      return true;
    };
  }
  return false;
};


var arr = [1,2,3,4,5,6];


console.log(arr.so(function(item){
  return item>7;
}))


  filter返回滿足條件的值,是一個新數組。

Array.prototype.f = function(fn){
  var arr = [];
  for(var i=0;i<this.length;i++){
    fn(this[i],i,this)&&arr.push(this[i]);
  }
  return arr;
};
var arr = [1,2,3,4,5,6];
console.log(arr.f(function(item){
  return item<2;
}))


  every檢測數組所有元素是否都符合指定條件,如果數組中檢測到有一個元素不滿足,則整個表達式返回 false ,且剩余的元素不會再進行檢測。


Array.prototype.ev = function(fn){
  for(var i=0;i<this.length;i++){
    if(!fn(this[i],i,this)){
      return false;
    };
  }
  return true;
};


var arr = [1,2,3];


console.log(arr.ev(function(item){
  return item>1;
}))


 
函數柯里化
  簡單來說就是某些情況下我們執行某個函數,并不需要它直接返回一些值給我們,而是再我們需要的時候它再給我們返回,這就是函數柯里化,以下是某位大牛寫的。
一個 currying 的函數首先會接受一些參數,接受了這些參數之后,該函數并不會立即求值,而是繼續返回另外一個函數,剛才傳入的參數在函數形成的閉包中被保存起來。待到函數被真正需要求值的時候,之前傳入的所有參數都會被一次性用于求值。
 
不完全柯里化版
 

var fn = (function(){
  var num = 0;
  return function(){
    if(arguments.length===0){
      return num;
    }else{
      for(var i=0;i<arguments.length;i+=1){
        num+=arguments[i];
      }
    }
  };
}())


fn(2);
fn(2,2,2);
fn(2);
console.log(fn()); //10


柯里化版

var currying = function(fn){
var arrNum = [];
  return function(){
    if(arguments.length===0){
      return fn.apply(this,arrNum);
    }else{
      [].push.apply(arrNum,arguments);
      return arguments.callee;
    }
  };
}


var count = (function(){
  var num = 0;
  return function(){
    for(var i=0;i<arguments.length;i+=1){
      num+=arguments[i];
    }
    return num;
  };
}());


var s = currying(count);
s(3);
s(3,3,3);



console.log(s());


 
函數反柯里化unCurrying
創建一個應用范圍更廣的函數。使本來只有特定對象才適用的方法,擴展到更多的對象。
簡單版

var obj = {
"length": 3,
"0": 1,
"1": 2,
"2": 3
};


// Array.prototype.push.call(obj,3);
// console.log(obj);


function push(){
  var a = [].shift.call(arguments);
  Array.prototype.push.apply(a,arguments);
};
push(obj,3);
push(obj,30);
push(obj,'js');
console.log(obj);


也可以這樣。

var obj = {
"length": 3,
"0": 1,
"1": 2,
"2": 3
};


// Array.prototype.push.call(obj,3);
// console.log(obj);


Function.prototype.uncurrying = function(){
  var _this = this; //Array.prototype.push
  return function(){
    //刪除第一個,并且返回 obj
    var obj = [].shift.call(arguments);
    //obj調用Array.prototype.push方法,傳遞arguments,注意此時arguments已經沒有包含obj這個參數了。
    return _this.apply(obj,arguments);
  };
};


var push = Array.prototype.push.uncurrying();


console.log(push(obj,'666'));
console.log(obj)
push(obj,'777');
console.log(obj)


(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(12)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:14
  • Javascript設計模式系列學習筆記


文章出處
因為是學習筆記,里面并沒有很多注釋和講解,所有不太適合0基礎的朋友看,只能說抱歉了。
這些筆記目前還存在很多的問題,不過我相信再今后的學習過程中會把這些問題挨個的解決。
除了前面3節后面的都不分前后順序。
 
初了解JS設計模式,學習筆記 1
設計模式之封裝,學習筆記 2
設計模式之原型,學習筆記 3
設計模式之代理模式,學習筆記 4
設計模式之單例模式,學習筆記 5
設計模式之策略模式,學習筆記 6
 
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(2)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:14
  • 初窺Javascript單元測試,附帶掌握一門新技能的學習方式。


文章出處
  之前沒感覺要學啥單元測試,項目中測試都是手動測的,但也沒覺的啥,但最近看文章和招聘上也多多少少有這方面的需求,于是網上搜索了一下,只找到了一些文章,但介紹的都不是很詳細或者說比較復雜,滿滿的傷,雖然看懂一部分,但還是不知道有啥用,于是不了了之了。
  但是就在今天又在某本書上講啥測試,實在坐不住了,于是下定決心,一定得搞定到底什么是單元測試,在實際項目中又是如何使用的,于是就有了此文章。
 
茫茫人海只為找到你......  
  搜索:Javascript單元測試入門、javascript單元測試教程、javascript單元測試視頻教程、JS單元測試教程.......這些都是我常搜索的關鍵字。
      對于經常干這個的,通過搜索結果馬上就能找到幾個比較適合自己的教程。
  原本打算學Qunit這個單元測試但是沒有看到比較好的入門教程,其實也是有的,只是上一次看的時候沒有看一篇介紹它在實際項目中的應用,所以打算換一個框架搜索。這里搜到了一個叫Karma的單元測試,并且講解通俗,簡單的使用已經會了,但可惜這篇文章也沒有講在實際開發中的應用,只好接著找,但這次既然Karma會了一些,自然搜索換成了這個:Karma單元測試入門教程,Karma單元測試教程....
  馬上找到一篇比較詳細的,雖然前面大部分講解的比較復雜,但因為有了前面的基礎,所以秒懂里面的意思了,里面簡單的介紹了一個例子,但這已經足夠了。
  
  別看這小小的一段話,里面是一個不錯的學習方式:先簡單 -- 復雜 -- 項目實踐。也就是說如果你要學習a,但是a方面的資源比較少,并且難懂,不過有個和它相鄰的b和它很像,這樣的話你可以搜索b,通過學習b來掌握一些基本的概念,通過掌握這些概念再來學習a就會簡單很多。
 
  底下是個人學習記錄,不會寫的太詳細,大家就不用看了,看看頂上的學習方式將好,反正感覺學編程用現實生活中怎么學習的,你拿到編程里面就很好了。
 
回歸到單元測試
  Karma是一個單元測試,我們先來下載它。
    1. 通過npm init初始化
      package.json
        2.通過npm下載Karma以及依賴項
      npm install -g karma karma-jasmine karma-chrome-launcher
    3.創建 karma 配置文件
      karma init
 
 
編寫測試demo.js

describe('隨便寫,就是看你看看是哪里來的', function(){
  it('就是給你看看具體哪出來的 1', function(){
    expect(true).toBe(true);
  });
  it('就是給你看看具體哪出來的 2', function(){
    expect(true).toBe(false);
  })
});


 
啟動 Karma
  karma start
 
結果:
  
 
解釋一下上面的代碼:

describe('隨便寫,就是看你看看是哪里來的', function(){
  it('就是給你看看具體哪出來的 1', function(){
    expect(true).toBe(true);
  });
  it('就是給你看看具體哪出來的 2', function(){
    expect(true).toBe(false);
  })
});  


describe:就是把你要測試的包起來,形成一個代碼塊,就像一個函數。
  第一個參數:隨便寫,自己看一下上面的那張圖就知道怎么回事了,第二個參數放一個函數。
 
it:負責單個測試,里面可以放你要測試的代碼。
expect:用來測試這個參數里面的值等于不等于toBe里面的參數。toBe是你期望的結果,而expect放你需要測試的結果。
 
其實這段代碼沒啥復雜,但多少還是有些迷惑,ok,來一個更實際一點的。

function count(a,b){
  return a + b;
}



describe('測試count函數', function(){
  it('3 + 3 = 6', function(){
    var a = count(3,3);


    // expect實際結果  toBe希望的結果
    expect(a).toBe(6);
  });
  it('3 + 3 = 6', function(){
    var a = count(2,3);
    expect(a).toBe(6);
  })
});


 
結果如下:
 
到這里我相信大家對單元測試多少有那么一點點的了解了。
我的理解單元測試就是將一些線上可能會發生的一些bug情況,通過一些技術提前來發現并且解決bug。
 
接著我得去學習Qunit,就到這了。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(0)

  • 個人分類:生活學習
▲top
  • 3月 09 週四 201720:14
  • Javascript單元測試之QUnit


文章出處
首先去Qunit官網下載。
Qunit有一個js腳本文件和一個css我們在頁面中引入它。

<script src="qunit-2.0.1.js"></script>
<link rel="stylesheet" href="qunit-2.0.1.css">


頁面中有兩段必須的標簽。

<div id="qunit"></div>
<div id="qunit-fixture"></div>


不寫上這個,頁面就是空白的了,這兩個標簽用來顯示測試結果以及其他的東西。
 
接下來我們可以新建一個js文件來進行簡單的測試了。

function add(a, b) {
  return a + b;
}


QUnit.test( "add test", function( assert ) {
  assert.ok( add(2,3) === 6, "add IS 5" );
});


結果如下:
看到圈起來的沒

QUnit.test( "add test", function( assert ) {
  assert.ok( add(2,3) === 6, "add IS 5" );
});


QUnit.test表示你要測試一段代碼,第一個也就是我圈起來的那段,只是用來顯示的,第二個參數是一個函數,里面放一個assert參數,這個測試有很多的屬性,在這里我們用到的是ok這個函數可以用來測試一個布爾值,第一個寫你要測試的,如果相等表示通過,否則會報錯,第二個也是用來顯示的。
 
如果是通過的會是這樣的。
如果你想比較兩個值是否相等而不是比較布爾值,可以用equal函數。

QUnit.test( "test", function( assert ) {
  assert.equal( 555 , 555 , "IS 555 ?" );
});


n1:實際值
n2:希望值
n3:看看而已
如果這樣:

QUnit.test( "test", function( assert ) {
  assert.equal( '555' , 555 , "IS 555 ?" );
});


因為equal用的是Javascript中的==比較,所以會隱式轉換。
如果不想這樣我們可以使用deepEqual函數

QUnit.test( "test", function( assert ) {
  assert.deepEqual( '555' , 555 , "IS 555 ?" );
});


deepEqual和equal函數功能差不多,不過它用的是===全等。
如果是異步的話這些就有些無能為力了,不管QUnit提供了幾個函數可以解決。

QUnit.test( "test", function( assert ) {
  var done = assert.async();
  var qunit = document.getElementById('qunit');
  qunit.onclick = function(){
    assert.ok( true , "IS 555 ?" );
    done();
  };


});


assert.async函數用來創建一個異步操作它會返回一個函數,這個可以在你測試的下方執行一下done();
 
但是正如QUnit官方說的:
Call assert.async() for each operation. Each done callback can be called at most once.
調用每個操作async()斷言,每個所做的回調可以至多被調用一次。
 
也就是說只能執行一次,看這個。
會多一次的,也就是說如果你想執行多次這樣還不行,但是有一個叫啥斷言的東西,我們來看看。

QUnit.test( "test", function( assert ) {
  assert.expect(5);
  var done = assert.async(5);
  var qunit = document.getElementById('qunit');
    qunit.onclick = function(){
    assert.ok( true , "istrue" );
    done();
  };


});


assert.expect(5);這里寫你要測試的次數,var done = assert.async(5);也要加上次數。
我也醉了為什么要限制這個。
 
QUnit官網:http://api.qunitjs.com/
刷去吧。
(繼續閱讀...)
文章標籤

AutoPoster 發表在 痞客邦 留言(0) 人氣(14)

  • 個人分類:生活學習
▲top
«1...293031230»

pop-under

參觀人氣

  • 本日人氣:
  • 累積人氣:

線上人數

Marquee

最新文章

  • 文章列表
  • jvm系列(四):jvm調優-命令大全(jps jstat jmap jhat jstack jinfo)
  • spring boot(一):入門篇
  • jvm系列(一):java類的加載機制
  • jvm系列(三):java GC算法 垃圾收集器
  • spring boot 實戰:我們的第一款開源軟件
  • jvm系列(六):jvm調優-從eclipse開始
  • 混合應用技術選型
  • jvm系列(二):JVM內存結構
  • spring boot(五):spring data jpa的使用

熱門文章

  • (1,763)jQuery之前端國際化jQuery.i18n.properties
  • (629)技術筆記:Indy控件發送郵件
  • (515)linux下安裝sqlite3
  • (499)學習筆記: Delphi之線程類TThread
  • (241)VC單選按鈕控件(Radio Button)用法(轉)
  • (103)單條件和多條件查詢
  • (50)淺談config文件的使用
  • (26)Tomcat shutdown執行后無法退出進程問題排查及解決
  • (22)基于 Asp.Net的 Comet 技術解析
  • (15)Java中的抽象類

文章分類

  • 生活學習 (2,296)
  • 未分類文章 (1)

最新留言

  • [20/04/24] 我是女生想約炮 有男生願意給我溫暖的嗎?我賴是woyou58 於文章「(1)從底層設計,探討插件式GIS框架的...」留言:
    我叫黎兒女生最近內心掙扎著要不要約炮我的line:woy...

文章搜尋

文章精選

誰來我家

Live Traffic Feed