主頁 > 企業開發 > 《JavaScript語言入門教程》記錄整理:入門和資料型別

《JavaScript語言入門教程》記錄整理:入門和資料型別

2020-09-13 14:18:47 企業開發

目錄

  • 入門篇
    • js介紹
    • 歷史
    • 基本語法
  • 資料型別
    • 概述
    • null 和 undefined
    • 數值
    • 字串
    • 物件
    • 函式
    • 陣列

本系列基于阮一峰老師的《JavaScrip語言入門教程》或《JavaScript教程》記錄整理,教程采用知識共享 署名-相同方式共享 3.0協議,這幾乎是學習js最好的教程之一(去掉之一都不過分)

最好的教程而阮一峰老師又采用開源方式共享出來,之所以重新記錄一遍,一是強迫自己重新認真讀一遍學一遍;二是對其中知識點有個自己的記錄,加深自己的理解;三是感謝這么好的教程,希望更多人閱讀了解

入門篇

js介紹

  1. JavaScript 是一種輕量級的腳本語言和嵌入式(embedded)語言,其只能通過宿主環境(host,瀏覽器或node環境)提供I/O操作
  2. 語法角度,JS是一種"物件模型"語言,支持函式式編程、"面向物件"編程、程序式編程等
  3. js核心語法包括:基本的語法構造(比如運算子、控制結構、陳述句)和標準庫(就是一系列具有各種功能的物件比如ArrayDateMath等),然后就是宿主提供的API(比如瀏覽器提供的BOM、DOM和Web互聯網相關的類;Node環境提供檔案操作API、網路通信API等)
  4. JavaScript 的所有值都是物件
  5. js可以采用事件驅動(event-driven)和非阻塞式(non-blocking)設計,實作高并發、多任務處理

歷史

  1. 1995年,Brendan Eich 只用了10天,完成了js的第一版,其設計借鑒了C、java、Scheme、Awk、Self、Perl、Python等多種語言,同時也留下了各種設計缺陷(導致常常需要學習各種解決問題的模式)
  2. JavaScript與Java是兩種不同的語言,兩者的關系僅僅是js的基本語法和物件體系最開始是想要模仿Java,而后又與當時Java的公司Sun有合作,也借助Java的聲勢,從而后來改名叫JavaScript
  3. ECMAScript 和 JavaScript 的關系是,前者是后者的規格,后者是前者的一種實作,ECMAScript 只用來標準化 JavaScript 的基本語法結構,但其他標準如 DOM 的標準就是由 W3C組織(World Wide Web Consortium)制定的
  4. 2007年,ECMAScript 4.0版草案發布,但是過于激進,導致后面中止了 ECMAScript 4.0 ,將其中一小部分功能發布為ECMAScript 3.1,之后又將其改名為 ECMAScript 5,
  5. 2015年6月,ECMAScript 6 正式發布,且更名為“ECMAScript 2015”,之后每年發布一個ECMAScript版本
  6. 周邊大事記

基本語法

  1. js執行單位是行(line),一行一行地執行,一般,一行就是一個陳述句
  2. 陳述句(statement)執行某種操作、運算式(expression)用于得到回傳值,凡是 JavaScript 語言中預期為值的地方,都可以使用運算式(這一點使js某些使用很靈活)
  3. 陳述句以分號結尾,一個分號表示一個陳述句結束,多個陳述句可以寫在一行內,分號前無內容,表示空陳述句,運算式不需要分號結尾
  4. 變數是對“值”的具名參考,即為"值"取名,變數的名字就是變數名,如下使用var宣告一個變數a,并賦值1
var a=1;
  1. 只宣告變數而不賦值,則該變數的值是undefined,表示"無定義",同時變數賦值時不寫var也有效,但不建議,變數必須先宣告再使用,否則會報錯not defined
  2. 一條var命令可以宣告多個變數,js是動態型別語言,變數型別可以隨時更改,
var a = 1;
a = 'hello';
  1. 使用var重新宣告一個已存在的變數,是無效的,重新宣告時賦值,相當于重新賦值
  2. 變數提升:js的執行方式是,先決議代碼,獲取所有被宣告的變數,然后再一行一行地運行,這樣就會導致所有變數的宣告陳述句,會被提升到代碼的頭部,這叫做變數提升(hoisting)
  3. 識別符號(identifier)指的是識別各種值的合法名稱,比如變數名、函式名,js識別符號大小寫敏感,識別符號的命名規則是:只能以字母、下劃線(_)和美元符號($)開頭,從第二個字符開始還可以使用數字,
  4. js識別符號中的字母指的是Unicode字母,因此中文識別符號也可以使用
  5. js中的保留字不能用于識別符號,保留字是指js中用來表示特定含義的字符,如return、class、true、false、function等
  6. 注釋:注釋用來對代碼進行解釋,js引擎執行時會忽略注釋部分,//表示單行注釋,/* */表示多行注釋
  7. js使用大括號表示"區塊"(block),對于var命令,js的區塊不構成單獨的作用域(scope)
  8. 條件陳述句:
  • ifif...else...結構,根據條件的布林值判斷執行,

  • switch結構判斷運算式的值是否與case相符并執行,如果都不符則執行最后的defaultcasebreak不能少,否則當前case代碼塊執行完會接著執行下一個case,switch陳述句部分和case陳述句部分,都可以使用運算式,這就是js中可以為值的地方,都可以使用運算式的體現,如下:

switch (1 + 3) {
  case 2 + 2:
    f();
    break;
  default:
    neverHappens();
}

switch陳述句的值和case陳述句的值,比較時采用的是嚴格相等運算子(===)

  • ?:三元運算子:如下,條件true,執行"運算式1",否則執行"運算式2",然后獲取對應回傳值
(條件) ? 運算式1 : 運算式2
  1. 回圈陳述句:重復執行某個操作
  • while 回圈:回圈條件和代碼塊,條件為真,就回圈執行代碼塊

  • for 回圈:可以指定回圈的起點、終點和終止條件,分為初始化運算式(initialize)、條件運算式(test)、遞增運算式(increment)

for (初始化運算式; 條件; 遞增運算式) {
  陳述句
}

所有for回圈,都可以改寫成while回圈

for陳述句的無線回圈表示:

for ( ; ; ){
  console.log('Hello World');
}
  • do...while 回圈:先執行一次回圈體,再判斷條件
  • break陳述句用于跳出代碼塊或回圈,continue陳述句用于立即終止本輪回圈,并開始下一輪回圈
  1. js陳述句的前面可以添加標簽(label),相當于定位符,用于跳轉到程式的任意位置
label:
  陳述句

資料型別

概述

  1. JavaScript的資料型別有六種(ES6新增了 Symbol 型別)
  • 數值(number):整數和小數(比如1和3.14)
  • 字串(strin):文本(比如"Hello World"),
  • 布林值(boolean):表示真偽的兩個特殊值,即true(真)和false(假)
  • undefined:表示“未定義”或不存在,即由于目前沒有定義,所以此處暫時沒有任何值
  • null:表示空值,即此處的值為空,
  • 物件(object):各種值組成的集合,

數值、字串、布林值稱為原始型別(primitive type),是最基本的資料型別,物件稱為合成型別(complex type),undefinednull兩個特殊值,

物件分為:狹義的物件(object)、陣列(array)、函式(function)

  1. 型別判斷

typeof運算子回傳一個值的資料型別:

  • 數值、字串、布林值分別回傳numberstringboolean
  • 函式回傳functionundefined回傳undefined(可以檢測未宣告的變數),物件回傳objectnull回傳object
// 檢測未宣告
if (typeof v === "undefined") {
  // ...
}

typeof window // "object"
typeof {} // "object"
typeof [] // "object"

typeof null // "object"
  • instanceof可以區分陣列和物件
[] instanceof Array // false
[] instanceof Array // true

null 和 undefined

  1. 兩者含義"類似",if陳述句中自動轉為false,相等于運算子(==)兩者比較為true,null表示"空"物件,轉為數值是0undefined表示"無定義"的原始值,轉為數值是NaN
Number(null) // 0
Number(undefined) // NaN
  1. 函式沒有回傳值時,默認回傳 undefined
  2. 布林值表示truefalse兩個真偽狀態,
  3. 如果 JavaScript 預期某個位置應該是布林值,則會將該位置上現有的值自動轉為布林值,

下面六個值會被轉為false,其他的值都是true

  • undefined
  • null
  • false
  • 0
  • NaN
  • ""或''(空字串)

空陣列([])和空物件({})對應的布林值,都是true

數值

  1. js中所有數字都是以64位浮點數存盤,整數也是如此,因此1===1.0,是同一個數
1 === 1.0 // true

JavaScript 語言的底層根本沒有整數,所有數字都是小數(64位浮點數)

  1. 浮點數不是精確的值,因此小數的比較和運算要特別注意
0.1 + 0.2 === 0.3   // false

0.3 / 0.1           // 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)   // false
  1. js浮點數的64個二進制位,從最左邊開始,由如下組成:
  • 第1位:符號位,0表示正數,1表示負數,數值正負
  • 第2位到第12位(共11位):指數部分,數值的大小
  • 第13位到第64位(共52位):小數部分(即有效數字),數值的精度
  1. 絕對值小于2的53次方的整數,即$-253$到$253$,都可以精確表示
Math.pow(2, 53); // 9007199254740992

Math.pow(2, 53) + 1; // 9007199254740992

Math.pow(2, 53) + 2; // 9007199254740994

Math.pow(2, 53) + 3; // 9007199254740996

Math.pow(2, 53) + 4; // 9007199254740996
  1. 最大值和最小值:Number.MAX_VALUENumber.MIN_VALUE
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
  1. 數值表示法:50(十進制)、0xFF(十六進制)、123e3123e-3(科學計數法)
  2. 當小數點前面的數字多于21位時,或者小數點后的零多于5個時,js會自動將數值轉為科學計數法表示
  3. 使用字面量(literal)表示數值時:
  • 十進制:沒有前導0的數值
  • 八進制:有前綴0o0O的數值,或者有前導0、且只用到0-7的八個阿拉伯數字的數值,
  • 十六進制:有前綴0x0X的數值,
  • 二進制:有前綴0b0B的數值,

js會自動將八進制、十六進制、二進制轉為十進制

  1. js存在2個0:+0-0,兩者是等價的,唯一區別是+0-0當作分母時運算式的回傳值不相等,
  2. NaN表示“非數字”(Not a Number),比如字串決議為數字報錯時會回傳NaN,0除以0得到NaN,NaN只是一個特殊值,型別依舊是Number
  3. NaN不等于任何值,包括它本身
NaN === NaN // false

NaN的布林值為false,NaN與任何數(包括它自己)的運算,得到的都是NaN

  1. Infinity表示“無窮”,表示無法表示正無窮(Infinity)和負無窮(-Infinity);非0數除以0,得到Infinity
    Infinity大于一切數值(除了NaN),-Infinity小于一切數值(除了NaN)

NaN的比較運算會回傳false

  1. parseInt()方法將字串轉為整數,字串轉為整數時,會一個個字符依次轉換,如果遇到不能轉為數字的字符,就不再進行下去,回傳已經轉好的部分,轉換失敗回傳NaN

決議科學計數法的數字時會出現奇怪的結果

第二個引數表示決議的值的進制

parseInt('1000', 2) // 8
parseInt('1000', 6) // 216
parseInt('1000', 8) // 512
  1. parseFloat():將一個字串轉為浮點數,可以對科學計數法字串正確轉換
  2. isNaN()判斷一個值是否是NaNisNaN()只對數值有效,其他型別值會先轉為數值,再判斷,對于空陣列和只有一個數值成員的陣列,isNaN()回傳false
isNaN('Hello') // true
// 相當于
isNaN(Number('Hello')) // true
  1. 判斷NaN最好的方法是:NaN是唯一不等于自身的值
function myIsNaN(value) {
  return value !== value;
}

如果使用isNaN()判斷,要同時判斷型別:

function myIsNaN(value) {
  return typeof value =https://www.cnblogs.com/codemissing/p/=='number' && isNaN(value);
}
  1. isFinite()判斷是否為正常的數值,判斷是引數也會進行型別轉換

字串

  1. 字串是放在單引號或雙引號中的零個或多個排在一起的字符,字串中使用相同的引號要用\反斜杠轉義
  2. 每行的尾部使用反斜杠,可以實作多行字串(\后面只能有換行符,否則報錯)
var longString = 'Long \
long \
long \
string';

longString // "Long long long string"

也可使用+可以將多個字串行連接

  1. 反斜杠(\)用來表示一些特殊字符,稱為轉義,如\n換行符;\r:回車鍵;\t:制表符,如果在字串中需要包含反斜杠,需要\轉義自身,
"你好,反斜杠\\";  // "你好,反斜杠\"
  1. 字串可以看做字符陣列,但僅能使用陣列的方括號運算子獲取字符,而不能進行其他操作
  2. length屬性回傳字串長度
'hello'.length  // 5
  1. js使用Unicode字符集,不僅以Unicode存盤字符,而且可以只用Unicode碼點,如'\u00A9'表示著作權符號
var s = '\u00A9';
s // "?"

每個字符在 JavaScript 內部都是以16位(2個位元組)的 UTF-16 格式儲存,js單位字符長度固定為16位長度

js 對 UTF-16 的支持不完整,只支持兩位元組的字符,無法識別四位元組的字符,比如四位元組字符??,瀏覽器可以正確識別是一個字符,但js無法識別,認為是兩個字符,需要特別注意

'??'.length // 2
  1. Base64編碼:對于ASCII 碼0到31的符號無法列印出來,可以使用Base64編碼轉換為可列印的字符;以文本格式傳遞二進制資料,也可以使用Base64編碼
  2. Base64 是一種編碼方法,可以將任意值轉成 0~9、A~Z、a-z、+/這64個字符組成的可列印字符,目的是不出現特殊字符,簡化程式處理,
  • btoa():任意值轉為 Base64 編碼
  • atob()Base64 編碼轉為原來的值
var string = 'Hello World!';
btoa(string) // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"
  1. btoa()atob()的Base64編碼解碼不使用非ASCII碼的字符,如btoa('你好')就會報錯,處理辦法是加一個URI轉碼,如下
function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
  return decodeURIComponent(atob(str));
}

b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

物件

  1. 物件是一組"鍵值對"(key-value)的集合,是一種無序的復合資料集合,

如下,物件用大括號,鍵值對又叫成員,分為"鍵名"和"鍵值",對應"成員的名稱"和"成員的值",鍵名與鍵值用冒號分割,鍵值對逗號分割,

var obj = {
  foo: 'Hello',
  bar: 'World'
};
  1. 物件的所有鍵名都是字串(ES6中Symbol值也可以作為鍵名),鍵名要么符合標識名的規則,要么使用引號包含,鍵名又稱為"屬性"(property),屬性可以動態創建
  2. "鍵值"可以是任何資料型別,比如
    屬性值可以為函式,這個屬性也可以稱為"方法",可以像函式一樣呼叫
    屬性的值還是物件,就可以形成鏈式參考
  3. 物件屬性之間逗號分割,最后一個屬性可以加逗號(trailing comma),也可不加
  4. 不同的變數名指向同一個物件,則它們都是這個物件的參考,即指向同一個記憶體地址,參考只局限于物件,原始型別中,兩個變數就是值的拷貝
  5. 物件采用大括號表示,則就有可能和代碼塊的大括號產生歧義,比如行首是大括號,如果看做運算式,則是一個物件;如果是陳述句,則表示一個代碼區塊,
{ foo: 123 }

遇到大括號的歧義時,無法確定是物件還是代碼塊,JavaScript引擎一律解釋為代碼塊,

可以將大括號放入圓括號中,這樣就是運算式

// eval 對字串求值
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
  1. 使用點運算子或方括號運算子讀取物件的屬性,同時也可以用來賦值,
    方括號運算子的鍵名必須有引號,否則被看做變數
var obj = {
  p: 'Hello World'
};

obj.p // "Hello World"
obj['p'] // "Hello World"

數值鍵名不能使用點運算子,使用方括號運算子時數值鍵名會轉換為字串
8. Object.keys(obj)查看一個物件所有屬性或鍵名
9. delete用于洗掉物件本身的屬性,成功后回傳true,且洗掉不存在的key也回傳true,只有屬性存在且不能洗掉時,才回傳false,不能洗掉繼承的屬性

delete obj.p // true
  1. in運算子檢查物件是否包含某個屬性,繼承時屬性也會回傳true,
  2. hasOwnProperty(key)方法判斷是否為物件自身的屬性
  3. for...in回圈用于遍歷物件的全部屬性
  • 遍歷的是物件所有可遍歷(enumerable)的屬性,會跳過不可遍歷的屬性,
  • 不僅遍歷物件自身的屬性,還遍歷繼承的屬性,

通常都是遍歷物件自身的屬性,因此可以結合hasOwnProperty方法

var person = { name: '阮一峰老師' };

for (var key in person) {
  if (person.hasOwnProperty(key)) {
    console.log(key);
  }
}
// name

函式

  1. 函式是一段可以反復呼叫的代碼塊
  2. js中宣告函式的三種方法
  • function 命令——函式的宣告(Function Declaration)

如下,function 函式名(引數1,...){函式體}

function print(s) {
  console.log(s);
}
  • 函式運算式(Function Expression)

變數賦值的方式,這個匿名函式又稱函式運算式

var print = function(s) {
  console.log(s);
};

函式運算式需要在陳述句的結尾加上分號,表示陳述句結束,

函式運算式宣告函式時,function后面不帶有函式名,如果加上函式名也僅在函式體內部有效,可用于在函式內部呼叫函式自身(如遞回等),

  • Function 建構式

如下,使用Function建構式時,可以傳遞任意數量的引數,只有最后一個引數會被當做函式體

var add = new Function(
  'x',
  'y',
  'return x + y'
);

// 等同于
function add(x, y) {
  return x + y;
}
  1. 函式的重復宣告:如果同一個函式被多次宣告,后面的就會覆寫前面的宣告,
  2. 函式圓括號在宣告時用于放入引數;非宣告時函式后緊跟圓括號,表示呼叫函式并傳入引數,return陳述句表示回傳后面運算式的值,并退出當前函式
  3. 函式呼叫自身,就是遞回(recursion)
  4. js將函式看作一種值,凡是可以使用值的地方,就能使用函式,函式是一個可以執行的值,因為函式與其他資料型別地位平等,所有在js中又稱函式為第一等公民
  5. js將函式名視為變數名,所以同樣有函式名的提升,function宣告函式時會被提升到代碼頭部,但是賦值陳述句定義函式,在賦值前呼叫會報錯(因為是undefined)
  6. 函式的屬性和方法
  • name屬性回傳函式的名字
  • length屬性回傳函式預期傳入的引數個數,即函式定義之中的引數個數,
    length屬性提供了一種機制,判斷定義時和呼叫時引數的差異,以便實作面向物件編程的“方法多載”(overload)
  • toString()方法回傳字串,內容是函式的原始碼,函式內的注釋也會回傳,
    原生函式,toString()方法回傳function (){[native code]}
  1. 函式作用域:作用域(scope)指變數存在的范圍,ES5中,JavaScript只有兩種作用域:全域作用域(變數在整個程式中一直存在);函式作用域(變數只在函式內部存在),函式作用域內同樣存在變數提升,ES6新增了塊級作用域
  2. 對于頂層函式(直接在js檔案中或<script>標簽中),函式外部宣告的變數就是全域變數(global variable),函式內部定義的變數,外部無法讀取,稱為"區域變數"(local variable),且函式內部定義的區域變數,在當前函式作用內會覆寫同名全域變數
  3. 使用var宣告的變數只有在函式內才是區域變數,其他區塊內宣告仍是全域變數(比如ifwhile等塊內)
  4. 函式本身的作用域:函式本身也是一個值,它的作用域與變數一樣,是其宣告時所在的作用域,與其運行時所在的作用域無關函式執行時所在的作用域,是定義時的作用域,而不是呼叫時所在的作用域
var a = 1;
var x = function () {
  console.log(a); //宣告時所在作用域的變數a
};

function f() {
  var a = 2;
  x();
}
f() // 1

同樣,函式體內部宣告的函式,作用域系結函式體內部,

function foo() {
  var x = 1;
  function bar() {
    console.log(x);
  }
  return bar;
}

var x = 2;
var f = foo();
f() // 1

如上,fon顳部宣告的函式bar,bar的作用域為foo函式內部,當在foo外部取出bar執行時,bar中使用的變數x指向的是foo內部(宣告時所在作用域)的x,而不是foo外部的x,這就是閉包現象

  1. 閉包(closure)就是能夠讀取其他函式內部變數的函式,而js中,只有函式內部的子函式才能讀取內部變數,因此閉包簡單理解就是"定義在一個函式內部的函式",本質上,閉包用于將函式內部和函式外部連接起來,

理解閉包,要先理解變數的作用域,函式內部可以讀取全域變數

var e = "我是全域變數";

function f1() {
  console.log(e);
}
f1() // "我是全域變數"

但是,函式外部無法讀取函式內部宣告的變數,

function f1() {
  var n = "我是函式內部變數";
}

console.log(n)  // Uncaught ReferenceError: n is not defined

但是,正常無法得到函式內的區域變數,如果想要實作必須通過變通方法:在函式的內部,再定義一個函式,這樣函式內部的子函式就可以使用函式內的區域變數,但是函式內無法使用其子函式內的區域變數,這就是js特有的 "鏈式作用域"結構(chain scope),子物件會一級一級地向上尋找所有父物件的變數,

父物件的所有變數,對子物件都是可見的,反之則不成立,

這樣將子函式作為回傳值,就可以在函式外部讀取它的內部變數

function f1() {
  var n = "我是函式內部變數";
  function f2() {
  console.log(n); // "我是函式內部變數"
  }
  return f2;
}

var result=f1();
result(); // "我是函式內部變數"

如上,獲取f1的回傳值f2函式,而f2可以讀取f1的內部變數,這樣就可以在外部獲取f1內部的變數,閉包就是函式f2

閉包最大的特點,就是它可以"記住"誕生的環境

閉包的用處:

  • 讀取函式內部的變數之外
  • 讓變數始終保持在記憶體中(即閉包可以使得它的誕生環境一直存在)
function createIncrementor(start) {
  return function () {
    return start++;
  };
}

var inc = createIncrementor(5);

inc() // 5  // 閉包使得start變數一直在記憶體中
inc() // 6
inc() // 7

閉包使得函式內部環境一直存在,閉包可以看作是函式內部作用域的一個介面

  • 封裝物件的私有屬性和私有方法
function Person(name) {
  var _age;
  function setAge(n) {
    _age = n;
  }
  function getAge() {
    return _age;
  }

  return {
    name: name,
    getAge: getAge,
    setAge: setAge
  };
}

var p1 = Person('張三');
p1.setAge(25);
p1.getAge(); // 25
p1.name;     // "張三"

如上,函式Person的內部變數_age,通過閉包getAge和setAge,變成了回傳物件p1的私有變數,

比如下面,就是閉包使用的典型例子,通常其在處理回圈頁面dom元素并添加事件方法時需要特別注意

var funs=[];
for(var i=0;i<5;i++){
  funs[i]=function(){
    console.log(i);
  }
}
funs.forEach(function(f){ 
  f(); 
})
// 輸出 5個5,而不是0,1,2,3,4

利用閉包,可實作將變數i的每一個回圈值"保存",供呼叫時輸出

var funs=[];
for(var i=0;i<5;i++){
  (function(i){
    funs[i]=function(){
      console.log(i);
    }
  })(i);
}
funs.forEach(function(f){ 
  f(); 
})
// 輸出 0,1,2,3,4
  1. 不能濫用閉包,容易產生網頁性能問題,外層函式每次運行,都會生成一個新的閉包,而每個閉包都會保留外層函式的內部變數,記憶體消耗很大,
  2. 函式的引數,通過圓括號傳遞外部資料,js在呼叫時允許省略引數(省略的引數變為undefined,但只能省略在后面的引數,靠前的引數不能省略)
  3. 引數傳遞方式:函式引數如果是原始型別的值(數值、字串、布林值),引數傳遞就是傳值傳遞(passes by value),函式引數是復合型別的值(陣列、物件、其他函式),傳遞方式是傳址傳遞(pass by reference),此時在函式內部修改引數,會影響原始值
  4. arguments物件包含了函式運行時的所有引數,arguments[0]是第一個引數,arguments[1]是第二個引數,以此類推,arguments只能在函式體內部使用,

argumentslength屬性可以判斷函式呼叫時的引數個數

arguments是物件,只是很像陣列,如果想使用陣列方法,需要將arguments轉為陣列,下面是轉換為陣列的兩種方法:

var args = Array.prototype.slice.call(arguments);

// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}
  1. 立即呼叫的函式運算式(IIFE):

圓括號()運算子跟在函式名后面,表示呼叫該函式,如果在定義函式之后,立即呼叫該函式,如下當function出現在行首時,js會將其解釋為陳述句,后面是函式的定義,這是以圓括號結尾就會報錯,

function(){ /* code */ }();

function出現在行首就是陳述句,

// 陳述句
function f() {}

// 運算式
var f = function f() {}

解決辦法就是不要讓function出現在行首,讓js引擎解釋為運算式,這樣就可以在定義函式之后立即運行

比如放圓括號中:

(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();

這就是"立即呼叫的函式運算式"(Immediately-Invoked Function Expression,IIFE),

IIFE最后的分號是必須的,尤其是兩個IIFE寫在一起時,如果省略分號,連著的兩個IIFE就出出現問題,可能會報錯

如下,兩行之間沒有分號,js將它們連在一起解釋,將第二行解釋為第一行的引數

// 報錯
(function(){ /* code */ }())
(function(){ /* code */ }())

任何讓解釋器以運算式來處理函式定義的方法,都能產生IIFE

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// 甚至
!function () { /* code */ }();
~function () { /* code */ }();
-function () { /* code */ }();
+function () { /* code */ }();

通常,只對匿名函式使用"立即執行的函式運算式",目的:一是不必為函式命名,避免了污染全域變數;二是 IIFE 內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變數,

如下,寫法二完全避免了污染全域變數

// 寫法一
var tmp = newData;
processData(tmp);
storeData(tmp);

// 寫法二
(function () {
  var tmp = newData;
  processData(tmp);
  storeData(tmp);
}());

陣列

  1. 陣列(array)是按次序排列的一組值,位置編號從0開始,用方括號表示,比如var arr = ['a', 'b', 'c'];
  2. 任何型別的資料都可以放入陣列
var arr = [
  {a: 1},
  [1, 2, 3],
  function() {return true;}
];

arr[0] // Object {a: 1}
arr[1] // [1, 2, 3]
arr[2] // function (){return true;}
  1. 陣列本質是一種特殊的物件,typeof回傳陣列的型別是object

陣列"物件"的鍵名,是按次序排列的整數,

var arr = ['a', 'b', 'c'];

Object.keys(arr); // ["0", "1", "2"]

js中,物件的鍵名一律為字串,陣列的鍵名也是字串,物件中數值的鍵名不能使用點結構(object.key),所以陣列元素不能使用.獲取

  1. 陣列的length屬性,回傳陣列元素的個數,即陣列長度

js使用一個32位整數,保存陣列的元素個數,即陣列長度最多只有 4294967295 個($2^32 - 1$)個

length屬性是可寫的,減少length值可用于洗掉陣列元素,length設定為0可用于清空陣列,length屬性的值等于最大的數字鍵加1

var arr = [ 'a', 'b', 'c' ];
arr.length // 3

arr.length = 2;
arr // ["a", "b"]
  1. 不推薦使用for...in遍歷陣列(會遍歷非數字鍵),可使用forwhile回圈,或forEach方法遍歷
var a = [1, 2, 3];

// for回圈
for(var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

// while回圈
var i = 0;
while (i < a.length) {
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
  console.log(a[l]);
}

// forEach方法
a.forEach(function (item) {
  console.log(item);
});
  1. 陣列的某個位置是空元素,即兩個逗號之間沒有任何值,稱該陣列存在空位(hole)
var a = [1, , 3 , 4];
a.length // 4

a[1] // undefined

delete a[2];
a[2] // undefined
a.length // 4

陣列的空位不影響length屬性,陣列最后一個元素后面有逗號,不會產生空位,空位回傳undefineddelete命令洗掉一個陣列成員會形成空位,且不會影響length

  1. 類似陣列的物件:如果一個物件的所有鍵名都是正整數或零,并且有length屬性,則這個物件語法上稱為"類似陣列的物件"(array-like object),

"類似陣列的物件"并不是陣列,它們不具備陣列特有的方法,

如下,obj就是一個類似陣列的物件

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

obj[0] // 'a'
obj[1] // 'b'
obj.length // 3
obj.push('d') // TypeError: obj.push is not a function

"類似陣列的物件"的根本特征,就是具有length屬性,只要有length屬性,就可以認為這個物件類似于陣列,但這種length屬性不是動態值

典型的"類似陣列的物件"是函式的arguments物件,以及大多數DOM元素集,還有字串,

// arguments物件
function args() { return arguments }
var arrayLike = args('a', 'b');

arrayLike[0] // 'a'
arrayLike.length // 2
arrayLike instanceof Array // false

// DOM元素集
var elts = document.getElementsByTagName('h3');
elts.length // 3
elts instanceof Array // false

// 字串
'abc'[1] // 'b'
'abc'.length // 3
'abc' instanceof Array // false

陣列的slice方法可以將"類似陣列的物件"變成真正的陣列,

var arr = Array.prototype.slice.call(arrayLike);

除了轉為真正的陣列,還可以通過call()把陣列的方法放到物件上面,從而讓"類似陣列的物件"可以使用陣列的方法,

Array.prototype.forEach.call(arrayLike, function (value, index) {
  console.log(index + ' : ' + value);
});

這種方法比直接使用陣列原生的forEach要慢,所以可以先轉為真正的陣列,在呼叫方法

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/25036.html

標籤:JavaScript

上一篇:GeoServer能不能切出Google Map Tiles呢?

下一篇:HTML5 Canvas小游戲基礎:用戶互動

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more