前言:
最近在學習javascript中數據類型、運算符,以及運算符優先級等相關基礎知識,相對簡單、基礎但也很重要。加上老師的推薦看了阮一峰老師所寫的《javascript教程》。從中刷新了過往認知的概念和固有的規則,明白了javascript的出現會打破以往的慣性思維。在這里1+1不再一定等于2,你常見的算數符號也不是你通常認為的那種作用,一個數字可以是表達式,同時一個表達式也是一個值。。。所以學習這樣一種新知識,你要學會先接受,然后敢于去打破自身的思維慣性,之后才能勇于迎接更多挑戰。
自我總結:
值===數據類型——轉化為:數值(number)/字符串(string)/布爾值(boolean)/undefined/null/對象(object)——轉為Nan或者數字(其中:(1)數字+undefined===Nan (2)null===(undefined===Nan ) ——判斷布爾值true or false
一、基本語法
1、調試
打開chrome開發工具:右鍵——檢查——console(esc鍵調取另一個console)
- Win F12
- Mac Command + Option + I
2、語句
(1)語句 VS 表達式
A、區別:
- 語句,主要為了進行某種任務而進行的操作,一般情況下不需要返回值;
- 表達式,為了得到返回值的計算式,一定會返回一個值。凡是JavaScript語言中預期為值的地方,都可以使用表達式。比如,賦值語句的等號右邊,預期是一個值,因此可以放置各種表達式
B、例子:
- 賦值語句:
var a = 1 + 3;
//先用var命令,聲明了變量a
,然后將1 + 3
的運算結果賦值給變量a - 表達式:
1 + 3
(2)分號
分號前面可以沒有任何內容,JavaScript引擎將其視為空語句。
;;;
A、語句,以分號結尾。一個分號就表示一個語句結束。多個語句可以寫在一行內。不需要加分號,換行默認上一行為語句。
var a = 1 + 3 ;
var b = 'abc';
/*或*/
var a = 3
var b = 4
var c = a+b
B、表達式不需要分號結尾。一旦在表達式后面添加分號,則JavaScript引擎就將表達式視為語句,這樣會產生一些沒有任何意義的語句。下面兩行語句有返回值,但是沒有任何意義,因為只是返回一個單純的值,沒有任何其他操作。
1 + 3; //語句,但無任何意義
'abc';
如圖:
3、變量
(1)定義
最前面的var是變量聲明命令。它表示通知解釋引擎,要創建一個變量a(相當于申請了1個內存放在變量a這里)。
變量是對“值”的引用,使用變量等同于引用一個值。每一個變量都有一個變量名。
var a = 1;
(2)變量提升
A、定義:
變量提升(hoisting),即JavaScript引擎的工作方式是:先解析代碼獲取所有被聲明的變量,然后再一行一行地運行。這造成的結果,就是所有變量的聲明語句,都會被提升到代碼的頭部,如:
//假設
var a = 1
//這里會產生一個變量提升
var a ;
a =1;
或
a = 3
var a
//控制臺顯示并不會報錯,只要有var變量命令的聲明,默認情況下就會自動提升到最前面,之后再作賦值
總結:
變量提升只對var命令聲明的變量有效,如果一個變量不是用var命令聲明的,就不會發生變量提升。
B、說說變量提升的幾種場景
第1種場景:
console.log(a); var a = 1;
代碼首先使用console.log
方法,在控制臺顯示變量a
的值。這時變量a
還沒有聲明和賦值,所以這是一種錯誤的做法,但是實際上不會報錯。因為有var
存在,即也存在變量提升,引擎中真正運行的是下面這段代碼:
var a; console.log(a); a = 1;
最后的結果是顯示undefined
,表示變量a
已聲明,且位于最前面,但還未賦值。
注:
這種變量提升的技巧很重要,與之后函數作用,復雜函數執行時所出現的一些情況都可解釋
第2種場景:
console.log(b); b = 1;
語句將會報錯,提示“ReferenceError:b is not defined”
,即變量b
未聲明,這是因為b不是用var
命令聲明的,JavaScript引擎不會將其提升,而只是視為對頂層對象的b屬性的賦值。
4、標識符
(1)定義:
標識符(identifier),用來識別具體對象的一個名稱。最常見標識符:變量名、函數名。
注:
JavaScript語言的標識符對大小寫敏感,所以a和A是兩個不同的標識符。
(2)標識符命名規則
A、第一個字符,可以是任意Unicode
字母(包括英文字母和其他語言的字母),以及美元符號($
)和下劃線(_
)。
B、第二個字符及后面的字符,除了Unicode字母、美元符號和下劃線,還可以用數字0-9。
C、一些命名實例:
- 下面這些都是合法的標識符。
arg0
_tmp
$elem
π
- 下面這些則是不合法的標識符。
1a // 第一個字符不能是數字
23 // 同上
*** // 標識符不能包含星號
a+b // 標識符不能包含加號
-d // 標識符不能包含減號或連詞線
- 中文是合法的標識符,可以用作變量名。
var 臨時變量 = 1;
- JavaScript有一些保留字,不能用作標識符:
arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield
- 三個詞具有特別含義,也不應該用作標識符:
Infinity
NaN
undefined
5、注釋:
// 這是單行注釋
/*
這是
多行
注釋
*/
//歷史上JavaScript兼容HTML代碼的注釋,所以<!--和-->也被視為單行注釋。
x = 1; <!-- x = 2;--> x = 3;
6、區塊
(1)定義 JavaScript使用大括號,將多個相關的語句組合在一起,稱為區塊(block)。
(2)與大多數編程語言不一樣,JavaScript的區塊不構成單獨的作用域(scope)。即區塊中的變量與區塊外的變量,屬于同一個作用域。如:
{
var a = 1;
}
a // 1
二、數據類型
1、定義
JS語言的每一個值,都屬于某一種數據類型。
2、值所屬的數據類型分類
JavaScript 的數據類型,共有6種:
注:
ES6 又新增了第七種 Symbol 類型的值
(1)數值(number):值為整數和小數(比如1和3.14)
(2)字符串(string):值為字符組成的文本(比如"Hello World")
(3)布爾值(boolean):值判定為true(真)和false(假)兩個特定值
注:
用于詢問的便可用boolean進行變量命名,如:
var isBoy = true
(4)undefined
:值判定為未處理,未定義或不存在。目前未定義所以此處暫時沒有任何值,但之后可以去放東西。
注:
一個變量沒有賦值,只能是undefined
,不會是null
(5)null
:值為表示經過處理之后的無值,即此處的值就是“無”的狀態。
(6)對象(object):或稱“引用類型”,各種值組成的集合。對象=屬性+值
對象又可以分成三個子類型:
- 狹義的對象(object)
- 數組(array)
- 函數(function)
3、typeof
運算符(用來確定值所屬的數據類型)
(1)三種運算符用來確定數據類型
運算符,用于連接簡單表達式,組成一個復雜的表達式(即通過一個關鍵字,后面加一個變量或值,得出一個結果)
JavaScript有三種方法,可以確定一個值到底屬于什么類型。
-
typeof
運算符 -
instanceof
運算符 -
Object.prototype.toString
方法
(2)作用
用typeof
可以判斷一個變量或可以返回一個值為哪種數據類型,如:
※數值、字符串、布爾值分別返回number
、string
、boolean
。
//數值、字符串、布爾值分別返回number、string、boolean。
typeof 123// "number"
typeof '123'// "string"
typeof false// "boolean"
※函數返回function。
function f(){
}
typeof f
// "function"
※ undefined
返回 undefined
typeof undefined
// "undefined"
※ 利用這一點,typeof
用來檢查一個沒有聲明的變量,而不報錯。如代碼中變量v沒有用var命令聲明,直接使用就會報錯;但放在typeof
后面就不報錯了,而是返回undefined
。
v
// ReferenceError: v is not defined
typeof v
// "undefined"
※實際編程中,變量v要用var命令聲明,這個特點通常用在判斷語句。
// 錯誤的寫法
if (v) {
// ...
}
// ReferenceError: v is not defined
// 正確的寫法
if (typeof v === "undefined") {
// ...
}
※除此以外,其他情況都返回object
。
//除此以外,其他情況都返回object
typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
實際操作中:
如何判斷一個變量是否為函數?
4、布爾值
(1)作用
布爾值代表“真”和“假”兩個狀態。“真”用關鍵字true表示,“假”用關鍵字false表示。布爾值只有這兩個值。
(2)下列運算符會返回布爾值
A、兩元邏輯運算符:&&
(And),||
(Or)
B、前置邏輯運算符:!
(Not)
C、相等運算符:===
,!==
,==
,!=
D、比較運算符:>
,>=
,<
,<=
如:
4>3-->true
(3)如果JavaScript預期某個位置應該是布爾值,會將該位置上現有的值自動轉為布爾值。轉換規則是除了下面六種值被轉為false
,其他值都視為true
。
-
undefined
-->false
-
null
-->false
-
false
-->false
-
+0
,-0
,NaN
-->false
【其他number(數字)為true】 -
""
或''
(空字符串)-->false
【其他string(字符串,包含" "空白字符串)為true】
A、關于""
或''
(空字符串)布爾值往往用于程序流程的控制,
如:
if ('') {
console.log(true);
}
// 沒有任何輸出
//上面代碼的if命令后面的判斷條件,預期應該是一個布爾值,所以JavaScript自動將空字符串,
//轉為布爾值false,導致程序不會進入代碼塊,所以沒有任何輸出
B、空數組([]
)和空對象({}
)對應的布爾值,都是true。如:
if ([]) {
console.log(true);
}
// true
if ({}) {
console.log(true);
}
// true
三、數據類型轉換解密
總結:js的數據類型如何判斷,即任何表達式先轉字符串再轉數字
1、if判斷
(1)js如何轉換判斷
從面試題說說if的數據類型:
// 題目1:如下代碼輸出什么?
if ("hello") {
console.log("hello")
} //true
// 題目2:如下代碼輸出什么?
if ("") {
console.log('empty')
}//空字符串,代表里面什么都沒有 //false
// 題目3:如下代碼輸出什么?
if (" ") {
console.log('blank')
}//空白字符串,仍然代表一個值,只不過是空值 //true
// 題目4:如下代碼輸出什么?
if ([0]) {
console.log('array')//對象 true
}
if([]){
console.log('hahah')
} //特殊對象 true
// 題目5:如下代碼輸出什么?
if('0.00'){
console.log('0.00')
} //字符串(除空字符串外)true
if(+0.00){
console.log('hahah')
} //false
(2)判斷原理:
對于if()
里括號的表達式(如以下),會被強制轉換為布爾類型
-
undefined
-->false
-
null
-->false
-
false`` -->
false``` -
+0
,-0
,NaN
-->false
【其他number(數字)為true】 -
""
或''
(空字符串)-->false
【其他string(字符串,包含" "空白字符串)為true】
2、==
判斷
(1)js處理 ==
的表達式 判斷
"" == 0 //題目1 ""空字符串===false===0 0==0 //true
" " == 0 //題目2 Number(' ')-->0===false 0==0 //true
"" == true //題目3 0===1 //false
"" == false //題目4 0===0 //true
" " == true //題目5 false===0 0==1 //false
!" " == true //題目6 " "空白字符串===true !0===false===0 0不等于true //false
!" " == false //題目7 false==false //true
*"hello" == true //題目8 字母字符串===Nan Nan不等于1 //fasle
*"hello" == false //題目9 字母字符串===Nan Nan不等于0 //fasle
"0" == true //題目10 "0"(數字字符串)===0不等于1 //false
"0" == false //題目11 "0"(數字字符串)===0===0 //true
*"00" == false //題目12 "00"(數字字符串)===00===0 //true
"0.00" == false //題目13 "0.00"(數字字符串)===0===0 //true
* undefined == null //題目14 undefined===Nan===null //true
*{} == true //題目15 {}===object(沒有字符串)不等于true //fasle
*[] == true //題目16 [](空數組)===object(沒有字符串)不等于true //fasle
var obj = {
a: 0,
valueOf: function(){return 1}
}
obj == "[object Object]" //題目17 //false
obj == 1 //題目18 //true
obj == true //題目19 //true
(2)判斷原理
兩圖對照,就能判斷表達式的數據類型:
四、運算符
1、作用:
運算符,主要用于連接簡單表達式,組成一個復雜的表達式
如typeof
,為運算符。即typeof 100 === 'numeber'
是一個值為字符串'numeber'
的表達式
再如:
-
3
:表達式 -
3+4
:表達式,+
,為運算符 -
(1+2)*5
:表達式。+
和*
均為運算符
2、判斷參考標準:
(1)有些操作符對不同的數據類型有不同的含義,比如+
,在兩個操作數都是數字的時候,會做加法運算
(2)兩個參數都是字符串或在有一個參數是字符串的情況下會把另外一個參數轉換為字符串,做字符串拼接
(3)在參數有對象的情況下會調用其valueOf或toString的函數(兩者同時使用,注意優先級)
(4)在只有一個字符串參數的時候會嘗試將其轉換為數字
注:
如果字符串無法轉換成數字,那么則轉換失敗,通常結果為:Nan
(5)在只有一個數字參數的時候返回其正數值
console.log(2+4); //6 加法運算
console.log("2"+"4"); //"24"為字符串 字符串的拼接
console.log(2+"4"); //"24" 一個數字+字符串,會把數字轉化成字符串,然后再進行拼接,
不是一個連讀的數字24,而是2和4的分開讀
console.log(2+new Date());//"2Mon Jan 20 2014 17:15:01 GMT+0800 (China Standard Time)"
/* 一個數字+一個對象,會調用這個對象的valueOf或toString這個方法*/
console.log(+"4");//4
3、常見類型:
- 算數表達式
- 比較表達式
- 邏輯表達式
- 賦值表達式
- 單目運算符
- 關鍵字作為運算符,如
typeof
、delete
、instanceof
等
(1)算數表達式
A、加法運算符(Addition):x + y
B、減法運算符(Subtraction):x - y
C、乘法運算符(Multiplication):x * y
D、除法運算符(Division):x / y
加減乘除的運算,這里會盡可能將字符串轉化成數字,如果轉換不了數字,則會得出Nan
這個結果
E、余數運算符(Remainder):x % y
用于循環語句
F、自增運算符(Increment):x ++
或者++x
-
x++
,由簡單表達式(x)和運算符(++)組成一個復雜的表達式,一個表達式本身整體,就是一個值,那么x++
的值就是x的原始值; -
x++
,作為表達式的結果是是它自己本身,同一作用域中的下一個變量,則是x++
內部又自增了1,即x=x+1
注:
-
x++
:是自增前x的原始值 -
++x
:是自增后下一個x變量的值
如:
而++ e
則是自增后的那個值,圖1所示,自增+1的e ===10
,那么++e === 11
- 自減運算符(Decrement):
--x
或者x--
同上可得 - 求負運算符(Negate):
-x
- 數值運算符(Convert to number):
+x
(2)賦值運算符
x += y // 等同于 x = x + y
x -= y // 等同于 x = x - y
x *= y // 等同于 x = x * y
x /= y // 等同于 x = x / y
x %= y // 等同于 x = x % y
x >>= y // 等同于 x = x >> y
x <<= y // 等同于 x = x << y
x >>>= y // 等同于 x = x >>> y
x &= y // 等同于 x = x & y
x |= y // 等同于 x = x | y
x ^= y // 等同于 x = x ^ y
(3)比較運算符
比較運算符比較兩個值,然后返回一個布爾值(實際上是ture
或 false
),表示是否滿足比較條件。JavaScript提供了8個比較運算符。
A、=
=
為賦值運算符,連接兩個簡單的表達式構成復雜的表達式,如x=y
即為表達式,若將其看成一個整體,即會輸出一個值,這個值則為最終賦的值,如:
B、==
相等
這里的相等是,近似相等,后臺得到的值則是ture
或者 false
如數字和字符串的比較,后臺會將字符串做一個類型轉換:
C、===
嚴格相等
這里的相等則更嚴格,值和類型的嚴格相等
題外話:
===
VS ==
-
===
叫做嚴格運算符 -
==
叫做相等運算符
關于這兩者的區別我在知乎上看到一篇文章:
Javascript 中 == 和 === 區別是什么?
a、嚴格運算符的運算規則如下:
(1)不同類型值
如果兩個值的類型不同,直接返回false
。
(2)同一類的原始類型值
同一類型的原始類型的值(數值、字符串、布爾值)比較時,值相同就返回true,值不同就返回false
。
(3)同一類的復合類型值
兩個復合類型(對象、數組、函數)的數據比較時,不是比較它們的值是否相等,而是比較它們是否指向同一個對象。
(4)undefined
和null
undefined
和 null
與自身嚴格相等。
null === null //true
undefined === undefined // true
b、相等運算符在比較相同類型的數據時,與嚴格相等運算符完全一樣。在比較不同類型的數據時,相等運算符會先將數據進行類型轉換,然后再用嚴格相等運算符比較。類型轉換規則如~下:
(1)原始類型的值
原始類型的數據會轉換成數值類型再進行比較。字符串和布爾值都會轉換成數值,所以題主的問題中會有第二個string輸出。
(2)對象與原始類型值比較
對象(這里指廣義的對象,包括數值和函數)與原始類型的值比較時,對象轉化成原始類型的值,再進行比較。
(3)undefined
和 null
undefined
和null
與其他類型的值比較時,結果都為false
, 它們互相比較時結果為true
。
(4)相等運算符的缺點
相等運算符隱藏的類型轉換,會帶來- -些違反直覺的結果。
== '0' // false
0 == // true
0 == // true
false == 'false' // false
false == '0' //true
false == undefined // false
false == null // false
null == undefined // true
' \t\r\n ' == 0 // true
這就是為什么建議盡量不要使用相等運算符。至于使用相等運算符會不會對后續代碼造成意外影響,答案是有可能會。
var a = undefined;
if(!a){
console.log("1");
}
//1
var a = undefined;
if(a == null){
console.log("1");
}
//1
var a = undefined;
if(a === null){
console.log("1");
}
// 無輸出
也就是說當a為undefined
時,輸出的值會有變化,而在編程中對象變成undefined
實在是太常見了。
D、!=
不相等
E、!==
嚴格不相等
F、<
小于
G、<=
小于或等于
H、>
大于
I、>=
大于或等于
(5)布爾運算符
A、!
取反運算符
B、&&
且運算符
表達式&&
表達式 會自動地轉化成ture
或者 false
進行比較。或判斷一個東西是否存在,是否滿足條件
C、||
或運算符
初始化賦值的時候可用
題外話:
&&
且 運算符 VS ||
或 運算符
a、且——&&
:用于判斷一個東西是否存在,或是否滿足條件(有false就判斷)
如果第一個為true,第二個也為true,最終值就是第二個值;
如:var a = “hello”
,那么a && console.log(a)
就能進行判斷,第二個值的最終結果為true
- 如果第一個為true,再看第二個是否為false,那最終的值就是為第一個值;
- 如果第一個為false,那就不用再判斷第二個,就是第一個值
總結:
如果是false就不用再看了;如果有true,再看第二個
b、或——||
: 用于初始化值
如果第一個為true,后面就不用再管;如果第一個為false,再看第二個
總結:
如果是true,就不會再管了;如果有false,再看第二個。只要一項為真,那就不用管,如:
第二個cc為undefined
,轉化為Boolean類型為false,||中還會看第二個,0為true,那么結果就為0。將0賦值給第一個cc,那么cc則有了初始值。
假如cc=100
,再執行cc=cc||0
,那么cc仍然等于100,轉換為boolean類型為true,那么則不需要在看第二個數
如果cc之前沒有聲明的話,得到的是一個默認值;如果cc之前聲明過,值還保持不變。
D、condition? true case : false case
三元條件運算符
題外話:
三目運算符 Condition?true case:false case
這里有一個條件判斷,如果條件判斷為真的話,那么整個表達式的結果就是true case
執行的結果;如果條件判斷為假的話,那么整個表達式的結果就是false case
執行的結果,當然,false case
還是會再做一些執行
如:
if (a > 10) {
b = a
}
else {
b = a - 2
}
答:b = a>10? a : a-2
(5)位運算符
下面的內容涉及到二進制的一些知識,可以看看這篇文章對二進制的解釋:
- 二進制www.zhihu.com[圖片上傳失敗...(image-a3baaa-1533800797470)]
看不懂也沒事,必要時看看二進制轉換對照表也行:
二進制轉換對照表
A、或運算(or):符號為|
,表示兩個二進制位中有一個為1,則結果為1,否則為0。
B、與運算(and):符號為&
,表示兩個二進制位都為1,則結果為1,否則為0。
C、否運算(not):符號為~
,表示將一個二進制位變成相反值。
D、異或運算(xor):符號為?
,表示兩個二進制位中有且僅有一個為1時,結果為1,否則為0。
E、左移運算(left shift):符號為<<
F、右移運算(right shift):符號為>>
J、帶符號位的右移運算(zero filled right shift):符號為>>>
(6)其它運算符(考慮優先級)
A、小括號
在JavaScript中,圓括號是一種運算符,它有兩種用法:
如果把表達式放在圓括號之中,作用是求值;如果跟在函數的后面,作用是調用函數。
B、void
void運算符的作用是執行一個表達式,然后返回undefined
。
C、逗號運算符
逗號運算符用于對兩個表達式求值,并返回后一個表達式的值。如:
五、運算符優先級和結合性
1、定義
結合性是指多個具有同樣優先級的運算符表達式中的運算順序
2、實踐——理論:
(1)有的運算符是左結合的,即運算從左到右執行,下面兩個運算是一樣的
w = x + y + z;
w = (x + y) + z;
(2)有的運算符是右結合的
w = x = y = z;
w = (x = (y = z));
w = a: b: c ? d : e? f : g;
w = a? b : (c? d: (e? f : g));
如:
- 最高:
typeof
- 最低:
,
3、理論——實踐
幾個優先級從高到低:
typrof () ++ -- ! +-*% && || =
(1)typeof的優先級相當的高,比加減乘除都優先,所以雖然是操作符,但在復雜表達式的時候我們還是習慣加括號,如:
typeof 2*3;//NaN
typeof (2*3);//"number"
typeof 2+3;// "number3"
題外話: NanN
(即not and number)
定義:是一個數字類型,不過它不是一個有效的數,表示為錯誤數字。
通過number函數可以把一個數字的字符創轉化成數字,不過無法將一個字母的字符串轉化成數字,得出結果為NaN。當NaN===NaN—>false
,一個數字與自己不相等,作為一個數字,二者對等與否對方均無從得知,沒有突出一個數字的識別性。如:
(2)++
、--
是右結合的操作符(優先級最高的幾個都是右結合),而且比加減乘除優先級高。同時自增、自減運算符的運算數得是左值(可以放在賦值符號左邊的值),而不能是常數
4++; //ReferenceError: Invalid left-hand side expression in postfix operation
var a=0,b=0;//, 忽略第一個操作數,返回第二個操作數 L(往左運算)
a+++b;//0
a;//1,++優先級比+高,所以相當于(a++)+b
b;//0
(3)賦值運算符的優先級相當的低
a = b == c; //等同于a = (b==c)
(4)邏輯非!也在優先級隊列的前端,比加減乘除高,但邏輯與、邏輯或優先級很低,不如加減乘除
!2*0; //0, 等價于(!2)*0
(5)一個關于邏輯運算符的有意思地方是其“短路”功能,會結合表達式計算值來判斷
1 && 3;
1 && "foo" || 0;
1 || "foo" && 0
如: