零JS筆記 | 作用域

瀏覽器:
JS解析器,在域內,一定會有兩步
1)找東西: var function 參數
2)逐行解讀代碼 [碰到script,及fn,會解析執行]

什麼是域: script 全局變量、全局函數

alert(a);
var a = 1;
function fn(){ alert(a) }

//1)找東西 找var function 參數
    a = undefined  //如果var去掉,則js解析器為空,所以a is not defined
    fn = function fn(){ alert(a) } (在倉庫內存放)
//2)逐行解讀代碼
    alert(a); 倉庫內為未定義
    var a = 1 ; (看見表達式:= + - * / % ++ -- 參數;)(把倉庫內的a = undefined 改為 a = 1) 
alert(a); //function a() { alert(4) 
var a = 1;
alert(a); //1
function a() { alert(2) ;}
alert(a); //1
var a = 3; //
alert(a); //3
function a() { alert(4) } 
alert(a); //3


//1)找東西 找var function 參數
  //a = undefined
    a = function a() { alert(2) } //又找到a,是函數,變量與函數重命,則只留函數
  //a = undefined                 //重命,只留下函數
    a = function a() { alert(4) } //遇到函數,前面被覆蓋;(存到倉庫裏只有這一行)
//2)逐行解讀代碼
    alert(a); //倉庫裏有 a = function a() { alert(4) } 
    var a = 1; //出現表達式,a被修改為 a = 1;
    function a() { alert(2) ;}  //函數聲明,不是表達式,所以不改東西 a = 1
    alert(a);  //所以1
    var a = 3     //出現表達式,a被修改為 a = 3;
    alert(a);  //所以是a = 3
    function a() { alert(4) }  ////函數聲明,不是表達式,所以不改東西 a= 3
    alert(a) //a = 3 //倉庫裏無函數了,所以若:
    a() //相當於 3(),報錯!
//域是分開執行的 先後順序,自上而下
<script> alert(a) </script>      // a is not defined 
<script> var a = 1 </script>
var a = 1;
function fn(){
    alert(a);
    var a = 2;
}
fn();
alert(a);

//1)找東西 找var function 參數
    a = undefined
    fn = function fn() { alert(a);var a = 2; }                 
//2)逐行解讀代碼
    a = 1;
    fn(); //1
           //1)找東西 找var function 參數  
               var a = 2  //a = undefined; // a为局部變量 ,與外面的a無關係 所以只在局部倉庫裏;
           //2)逐行解讀代碼
                a = 2;    //局部垃圾回收機制回收
    alert(a) //1 全局倉庫裏
var a = 1;
function fn(){
    alert(a);
    a = 2;  //去掉var,相當於改全局倉庫裏的值;
}
fn(); //1
alert(a); //2
var a = 1;
function fn(a){  //加參數
    alert(a); //往上找到參數a,到達不了 var a = 1; 所以預解析a = undefined
    a = 2;   //局域的a被改為a = 2,執行完後銷毀
}
fn(); //局部a = undefined
alert(a); //全局a = 1
var a = 1;
function fn(a){ 
    alert(a); 
    a = 2; 
}
fn(a);//執行時傳參進來 所以1
alert(a); //1
//獲取fn內的值方法一:

var str = ''         //1、定義
function fn(){
    var a = 'pig'
    str = a         //2、str 拿到
}
fn(); /////////////////////////////////////////     3、一定要執行;
alert(str)         //4、可找到pig
//获取fn内的值方法二:

function fn2(){
    var a = 'MM';
    fn3(a);
}
fn2()
function fn3(e){ //调用参数接收
    alert(e);  //e = a = 'MM'
}

写代码注意事项:
1、if条件判断非作用域;如下代码,但ff不能对下面的函数进行预解析;兼容性问题,所以若需定义全局变量或全局函数,不要在if或for循环里定义!

//不要這麼寫:
alert(a);  //undefined正常
alert(fn)  //if非作用域,理论上应该弹出整个fn内容chrome,但在ff上:fn is not defined
if(true){
  var a = 1
  function fn(){
    alert(123)
  }
}

//需這麼寫,變量與函數定義在if或for 外面
alert(a);  //undefined正常
alert(fn)  // function fn(){alert(123)}
  var a = 1
  function fn(){
    alert(123)
  }
if(true){
}
var btn = document.getElementsByTagName('input')
for (var i = 0; i < btn.length; i++) { //一個循環
  btn[i].onclick = function () {
    for (var i = 0; i < btn.length; i++) { //點擊每一個時,循環三次,正常
      btn[i].style.background = 'red'
    }
  }
}
for (var i = 0; i < btn.length; i++) { //一個循環3
  btn[i].onclick = function () {
    alert(i) //i = 3,執行完for後才點擊,i向上找,所以是3;
  }
}
for (var i = 0; i < btn.length; i++) { //一個循環3
  btn[i].onclick = function () { //這一塊是作用域,下面有var = 0,所以最開始 彈 i = undefined
    alert(i) // undefined
    for (var i = 0; i < btn.length; i++) { //如去掉var,則上面的i 必須往上找
      btn[i].style.background = 'red'
    }
  }
}

零JS筆記 | 數據類型

JS中的數據類型:number(NaN) string boolean function object(fn,[],{},null) undefined

var str = 'abc';
str.charAt(3) //下標

var obj = window; //object

var arr = [1] //
console.log(typeof arr); //object

function fn() {
  alert(this)
}
console.log(typeof fn); //function

obj.fn1 = function () {
  alert(1)
}
console.log(typeof obj.fn1); //object

var json = {
  name: 'elmok'
}
console.log(typeof json); //object

var u;
alert(u) //undefined 表示一種狀態
alert(typeof u) //undefined

顯式類型轉換:Number(),parseInt(),parseFloat()

//字符串轉數字 Number()
//可轉換的類型
var a = '100'
alert(a + 100) // '100100'

alert(Number(a) + 100) // 200

var b = '000100';
alert(Number(b)) //100

var c = '+100'
alert(Number(c)) //100

var d = ''; //d = '   '
alert(Number(d)); //0

var e = true
alert(Number(e)) //1

var arr = [] //['']-->0   [1,2,3]-->NaN  ['123']-->123
alert(Number(arr)) //0

var f = null
alert(Number(f)) // 0

//可轉換類型:parseInt(),parseFloat()
var i = '100px'
alert(parseInt(i)) //100,從左到右查看,若有非數字,則截斷;

var j = '+100'
alert(parseInt(j)) //從左到右,如遇到 + - 空格,則例外

var l = '100px'
alert(parseInt(l, 8)) // parseInt(l,進制)

var k = '10.1231231231元'
alert(parseFloat(k)) // 10.1231231231
//判斷是否有帶小數點  parseInt(n) == parseFloat(n)

無法轉換的數據類型:

1、NaN: not a number //不是數字 的 數字類型;
2、出現NaN表示進行了非法的操作;
3、NaN ==> false;
4、自已不等於自己;
5、isNaN 不是數字 返回true, 數字返回false
6、isNaN內部依靠Number()轉換

var fn = function () {
}
alert(Number(fn)) //NaN

var json = {
} //json無法轉

alert(Number(json)) //NaN

var g; //undefined
alert(Number(g)) //NaN

var h = '100px'
alert(Number(h)) //NaN

var o = Number('abc')
alert(o) //NaN

alert(typeof NaN) // number

//isNaN 不是數字 返回true,  是數字返回false ,即Number()能轉換的
alert(isNaN(123)) //false
alert(isNaN('abc')) //true
alert(isNaN(function () {
  alert(1)
})) //true
alert(isNaN('250')) //false ,使用Number('250')轉成250數字後返回false
alert(isNaN(true)) // false
alert(isNaN([])) //false
alert(isNaN(NaN)) //true

inp[1].onclick = function () {
  if (isNaN(inp[0].value)) { //有缺陷,如輸入 空格、true false
    alert('不是數字')
  } 
  else {
    alert('是數字')
  }
}

if (NaN) {
  alert('真')
} 
else {
  alert('假')
}

隱式類型轉換: - * / % 可讓字符串變成數字 + 可讓數字變成字符串 ++ -- 變成數字 > < 數字比較,字符串比較 !轉成布爾值 ==

alert(100 - '1') //99
alert('100' + 1) // 101
var n = '10'
alert(n++) //11
alert('10' > 5) // true '10'被轉成數字10
alert('10' < '5') // true 編碼位置比較
alert(!true) //false
alert(!'ok') //false
alert('2' == 2) //true

小技巧:

找字符:判斷typeof == 'string';
找數字:判斷typeof=='number' && 排除屬性NaN的數字類型:!isNaN(obj)
找可以轉成數字的:parseFloat(arr[i])==parseInt(arr[i])
找NaN:判斷typeof==='number' && 並且屬性不是數字:isNaN(obj)
var arr = [ '100px', 'abc'-6, [], -98765, 34, -2, 0, '300', , function(){alert(1);}, null, document, [], true, '200px'-30,'23.45元', 5, Number('abc'), function(){ alert(3); }, 'xyz'-90 ]

//找到數字,排除布爾值
for (var i = 0; i < arr.length; i++) { 
  if ((typeof arr[i]) == 'number' && !isNaN(arr[i])) {
    console.log(arr[i])
  }
}
//parseFloat会干掉0  所以要加上
var arrN = []
for (var i = 0; i < arr.length; i++) {
  if (parseFloat(arr[i]) == parseInt(arr[i])) {
    console.log(arr[i]);
    arrN.push(arr[i])
  }
}
console.log(Max(arrN));
function Max(arr) {
  var max = arr[0];
  for (var i = 0; i < arr.length; i++) {
    if (max < arr[i]) {
      max = arr[i]
    }
  }
  return max
}
//找字符串
for (var i = 0; i < arr.length; i++) {
  if (typeof arr[i] === 'string') {
    console.log(arr[i])
  }
}
//找到數字類型,並且是NaN
for (var i = 0; i < arr.length; i++) {
  if (typeof (arr[i]) == 'number' && isNaN(arr[i])) {
    console.log(i + ':' + arr[i]);
  }
}