【JavaScript 教程】數據類型-函數

2021-12-24 web前端開發

作者 | 阮一峰

函數是一段可以反覆調用的代碼塊。函數還能接受輸入的參數,不同的參數會返回不同的值。

1、概述


1.1、函數的聲明

JavaScript 有三種聲明函數的方法。

(1)function 命令

function命令聲明的代碼區塊,就是一個函數。function命令後面是函數名,函數名後面是一對圓括號,裡面是傳入函數的參數。函數體放在大括號裡面。

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

上面的代碼命名了一個print函數,以後使用print()這種形式,就可以調用相應的代碼。這叫做函數的聲明(Function Declaration)。

(2)函數表達式

除了用function命令聲明函數,還可以採用變量賦值的寫法。

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

這種寫法將一個匿名函數賦值給變量。這時,這個匿名函數又稱函數表達式(Function Expression),因為賦值語句的等號右側只能放表達式。

採用函數表達式聲明函數時,function命令後面不帶有函數名。如果加上函數名,該函數名只在函數體內部有效,在函數體外部無效。

var print = function x(){  console.log(typeof x);};xprint()

上面代碼在函數表達式中,加入了函數名x。這個x只在函數體內部可用,指代函數表達式本身,其他地方都不可用。這種寫法的用處有兩個,一是可以在函數體內部調用自身,二是方便除錯(除錯工具顯示函數調用棧時,將顯示函數名,而不再顯示這裡是一個匿名函數)。因此,下面的形式聲明函數也非常常見。

var f = function f() {};

需要注意的是,函數的表達式需要在語句的結尾加上分號,表示語句結束。而函數的聲明在結尾的大括號後面不用加分號。總的來說,這兩種聲明函數的方式,差別很細微,可以近似認為是等價的。

(3)Function 構造函數

第三種聲明函數的方式是Function構造函數。

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

上面代碼中,Function構造函數接受三個參數,除了最後一個參數是add函數的「函數體」,其他參數都是add函數的參數。

你可以傳遞任意數量的參數給Function構造函數,只有最後一個參數會被當做函數體,如果只有一個參數,該參數就是函數體。

var foo = new Function(  
'return "hello world";');
function foo() {  return 'hello world';}

Function構造函數可以不使用new命令,返回結果完全一樣。

總的來說,這種聲明函數的方式非常不直觀,幾乎無人使用。

1.2、函數的重複聲明


如果同一個函數被多次聲明,後面的聲明就會覆蓋前面的聲明。

function f() {  console.log(1);}f() function f() {  console.log(2);}f()

上面代碼中,後一次的函數聲明覆蓋了前面一次。而且,由於函數名的提升(參見下文),前一次聲明在任何時候都是無效的,這一點要特別注意。

1.3、圓括號運算符,return 語句和遞歸

調用函數時,要使用圓括號運算符。圓括號之中,可以加入函數的參數。

function add(x, y) {  return x + y;}add(1, 1)

上面代碼中,函數名後面緊跟一對圓括號,就會調用這個函數。

函數體內部的return語句,表示返回。JavaScript 引擎遇到return語句,就直接返回return後面的那個表達式的值,後面即使還有語句,也不會得到執行。也就是說,return語句所帶的那個表達式,就是函數的返回值。return語句不是必需的,如果沒有的話,該函數就不返回任何值,或者說返回undefined。

函數可以調用自身,這就是遞歸(recursion)。下面就是通過遞歸,計算斐波那契數列的代碼。

function fib(num) {  
if (num === 0) return 0;  
if (num === 1) return 1;  
return fib(num - 2) + fib(num - 1);}fib(6)

上面代碼中,fib函數內部又調用了fib,計算得到斐波那契數列的第6個元素是8。

1.4、第一等公民

JavaScript 語言將函數看作一種值,與其它值(數值、字符串、布爾值等等)地位相同。凡是可以使用值的地方,就能使用函數。比如,可以把函數賦值給變量和對象的屬性,也可以當作參數傳入其他函數,或者作為函數的結果返回。函數只是一個可以執行的值,此外並無特殊之處。

由於函數與其他數據類型地位平等,所以在 JavaScript 語言中又稱函數為第一等公民。

function add(x, y) {  return x + y;}var operator = add;
function a(op){  return op;}a(add)(1, 1)


1.5、函數名的提升

JavaScript 引擎將函數名視同變量名,所以採用function命令聲明函數時,整個函數會像變量聲明一樣,被提升到代碼頭部。所以,下面的代碼不會報錯。

f();function f() {}

表面上,上面代碼好像在聲明之前就調用了函數f。但是實際上,由於「變量提升」,函數f被提升到了代碼頭部,也就是在調用之前已經聲明了。但是,如果採用賦值語句定義函數,JavaScript 就會報錯。

f();var f = function (){};

上面的代碼等同於下面的形式。

var f;f();f = function () {};

上面代碼第二行,調用f的時候,f只是被聲明了,還沒有被賦值,等於undefined,所以會報錯。因此,如果同時採用function命令和賦值語句聲明同一個函數,最後總是採用賦值語句的定義。

var f = function () {  console.log('1');}function f() {  console.log('2');}f()


2、函數的屬性和方法


2.1、name 屬性

函數的name屬性返回函數的名字。

function f1() {}f1.name

如果是通過變量賦值定義的函數,那麼name屬性返回變量名。

var f2 = function () {};f2.name

但是,上面這種情況,只有在變量的值是一個匿名函數時才是如此。如果變量的值是一個具名函數,那麼name屬性返回function關鍵字之後的那個函數名。

var f3 = function myName() {};f3.name

上面代碼中,f3.name返回函數表達式的名字。注意,真正的函數名還是f3,而myName這個名字只在函數體內部可用。

name屬性的一個用處,就是獲取參數函數的名字。

var myFunc = function () {};
function test(f) {  console.log(f.name);}test(myFunc)

上面代碼中,函數test內部通過name屬性,就可以知道傳入的參數是什麼函數。

2.2、length 屬性

函數的length屬性返回函數預期傳入的參數個數,即函數定義之中的參數個數。

function f(a, b) {}f.length

上面代碼定義了空函數f,它的length屬性就是定義時的參數個數。不管調用時輸入了多少個參數,length屬性始終等於2。

length屬性提供了一種機制,判斷定義時和調用時參數的差異,以便實現面向對象編程的」方法重載「(overload)。

2.3、toString()

函數的toString方法返回一個字符串,內容是函數的源碼。

function f() {  a();  b();  c();}f.toString()

函數內部的注釋也可以返回。

function f() {}f.toString()

利用這一點,可以變相實現多行字符串。

var multiline = function (fn) {
 var arr = fn.toString().split('\n');  
 return arr.slice(1, arr.length - 1).join('\n');};function f() {}multiline(f);
 


3、函數作用域3.1、定義

作用域(scope)指的是變量存在的範圍。在 ES5 的規範中,Javascript 只有兩種作用域:一種是全局作用域,變量在整個程序中一直存在,所有地方都可以讀取;另一種是函數作用域,變量只在函數內部存在。ES6 又新增了塊級作用域,本教程不涉及。

函數外部聲明的變量就是全局變量(global variable),它可以在函數內部讀取。

var v = 1;function f()
{  console.log(v);}f()

上面的代碼表明,函數f內部可以讀取全局變量v。

在函數內部定義的變量,外部無法讀取,稱為「局部變量」(local variable)。

function f(){  var v = 1;}v

上面代碼中,變量v在函數內部定義,所以是一個局部變量,函數之外就無法讀取。

函數內部定義的變量,會在該作用域內覆蓋同名全局變量。

var v = 1;function f(){
 var v = 2;  console.log(v);}f() v

上面代碼中,變量v同時在函數的外部和內部有定義。結果,在函數內部定義,局部變量v覆蓋了全局變量v。

注意,對於var命令來說,局部變量只能在函數內部聲明,在其他區塊中聲明,一律都是全局變量。

if (true) {  var x = 5;}console.log(x);  

上面代碼中,變量x在條件判斷區塊之中聲明,結果就是一個全局變量,可以在區塊之外讀取。

3.2、函數內部的變量提升

與全局作用域一樣,函數作用域內部也會產生「變量提升」現象。var命令聲明的變量,不管在什麼位置,變量聲明都會被提升到函數體的頭部。

function foo(x) {  
if (x > 100) {    var tmp = x - 100;  }}function foo(x) {  var tmp;  if (x > 100) {    tmp = x - 100;  };}

3.3、函數本身的作用域

函數本身也是一個值,也有自己的作用域。它的作用域與變量一樣,就是其聲明時所在的作用域,與其運行時所在的作用域無關。

var a = 1;var x = function () {
 console.log(a);};function f() {  var a = 2;  x();}f()

上面代碼中,函數x是在函數f的外部聲明的,所以它的作用域綁定外層,內部變量a不會到函數f體內取值,所以輸出1,而不是2。

總之,函數執行時所在的作用域,是定義時的作用域,而不是調用時所在的作用域。

很容易犯錯的一點是,如果函數A調用函數B,卻沒考慮到函數B不會引用函數A的內部變量。

var x = function () {  console.log(a);};function y(f) {  var a = 2;  f();}y(x)

上面代碼將函數x作為參數,傳入函數y。但是,函數x是在函數y體外聲明的,作用域綁定外層,因此找不到函數y的內部變量a,導致報錯。

同樣的,函數體內部聲明的函數,作用域綁定函數體內部。

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

上面代碼中,函數foo內部聲明了一個函數bar,bar的作用域綁定foo。當我們在foo外部取出bar執行時,變量x指向的是foo內部的x,而不是foo外部的x。正是這種機制,構成了下文要講解的「閉包」現象。

4、參數


4.1、概述

函數運行的時候,有時需要提供外部數據,不同的外部數據會得到不同的結果,這種外部數據就叫參數。

function square(x) {  return x * x;}square(2) square(3)

上式的x就是square函數的參數。每次運行的時候,需要提供這個值,否則得不到結果。

4.2、參數的省略

函數參數不是必需的,Javascript 允許省略參數。

function f(a, b) {  return a;}f(1, 2, 3) f(1) f() f.length

上面代碼的函數f定義了兩個參數,但是運行時無論提供多少個參數(或者不提供參數),JavaScript 都不會報錯。省略的參數的值就變為undefined。需要注意的是,函數的length屬性與實際傳入的參數個數無關,只反映函數預期傳入的參數個數。

但是,沒有辦法只省略靠前的參數,而保留靠後的參數。如果一定要省略靠前的參數,只有顯式傳入undefined。

function f(a, b) {  return a;}f( , 1)
f(undefined, 1)

上面代碼中,如果省略第一個參數,就會報錯。

4.3、傳遞方式

函數參數如果是原始類型的值(數值、字符串、布爾值),傳遞方式是傳值傳遞(passes by value)。這意味著,在函數體內修改參數值,不會影響到函數外部。

var p = 2;function f(p) {  p = 3;}f(p);p

上面代碼中,變量p是一個原始類型的值,傳入函數f的方式是傳值傳遞。因此,在函數內部,p的值是原始值的拷貝,無論怎麼修改,都不會影響到原始值。

但是,如果函數參數是複合類型的值(數組、對象、其他函數),傳遞方式是傳址傳遞(pass by reference)。也就是說,傳入函數的原始值的地址,因此在函數內部修改參數,將會影響到原始值。

var obj = { p: 1 };function f(o) {  o.p = 2;}f(obj);obj.p

上面代碼中,傳入函數f的是參數對象obj的地址。因此,在函數內部修改obj的屬性p,會影響到原始值。

注意,如果函數內部修改的,不是參數對象的某個屬性,而是替換掉整個參數,這時不會影響到原始值。

var obj = [1, 2, 3];function f(o) {  o = [2, 3, 4];}f(obj);obj

上面代碼中,在函數f內部,參數對象obj被整個替換成另一個值。這時不會影響到原始值。這是因為,形式參數(o)的值實際是參數obj的地址,重新對o賦值導致o指向另一個地址,保存在原地址上的值當然不受影響。

4.4、同名參數

如果有同名的參數,則取最後出現的那個值。

function f(a, a) {  console.log(a);}f(1, 2)

上面代碼中,函數f有兩個參數,且參數名都是a。取值的時候,以後面的a為準,即使後面的a沒有值或被省略,也是以其為準。

function f(a, a) {  console.log(a);}f(1)

調用函數f的時候,沒有提供第二個參數,a的取值就變成了undefined。這時,如果要獲得第一個a的值,可以使用arguments對象。

function f(a, a) {  
console.log(arguments[0]);}f(1)


4.5、arguments 對象

(1)定義

由於 JavaScript 允許函數有不定數目的參數,所以需要一種機制,可以在函數體內部讀取所有參數。這就是arguments對象的由來。

arguments對象包含了函數運行時的所有參數,arguments[0]就是第一個參數,arguments[1]就是第二個參數,以此類推。這個對象只有在函數體內部,才可以使用。

var f = function (one) {  
console.log(arguments[0]);  
console.log(arguments[1]);
 console.log(arguments[2]);}f(1, 2, 3)

正常模式下,arguments對象可以在運行時修改。

var f = function(a, b) {  
arguments[0] = 3;  arguments[1] = 2;  return a + b;}f(1, 1)

上面代碼中,函數f調用時傳入的參數,在函數內部被修改成3和2。

嚴格模式下,arguments對象是一個只讀對象,修改它是無效的,但不會報錯。

var f = function(a, b) {
 'use strict';  arguments[0] = 3;  arguments[1] = 2;  return a + b;}f(1, 1)

上面代碼中,函數體內是嚴格模式,這時修改arguments對象就是無效的。

通過arguments對象的length屬性,可以判斷函數調用時到底帶幾個參數。

function f() {  return arguments.length;}f(1, 2, 3) f(1) f()

(2)與數組的關係

需要注意的是,雖然arguments很像數組,但它是一個對象。數組專有的方法(比如slice和forEach),不能在arguments對象上直接使用。

如果要讓arguments對象使用數組方法,真正的解決方法是將arguments轉為真正的數組。下面是兩種常用的轉換方法:slice方法和逐一填入新數組。

var args = Array.prototype.slice.call(arguments);
var args = [];for (var i = 0; i < arguments.length; i++) {  args.push(arguments[i]);}

(3)callee 屬性

arguments對象帶有一個callee屬性,返回它所對應的原函數。

var f = function () {
 console.log(arguments.callee === f);}f()

可以通過arguments.callee,達到調用函數自身的目的。這個屬性在嚴格模式裡面是禁用的,因此不建議使用。

5、函數的其他知識點5.1、閉包

閉包(closure)是 Javascript 語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。

理解閉包,首先必須理解變量作用域。前面提到,JavaScript 有兩種作用域:全局作用域和函數作用域。函數內部可以直接讀取全局變量。

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

上面代碼中,函數f1可以讀取全局變量n。

但是,函數外部無法讀取函數內部聲明的變量。

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

上面代碼中,函數f1內部聲明的變量n,函數外是無法讀取的。

如果出於種種原因,需要得到函數內的局部變量。正常情況下,這是辦不到的,只有通過變通方法才能實現。那就是在函數的內部,再定義一個函數。

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

上面代碼中,函數f2就在函數f1內部,這時f1內部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內部的局部變量,對f1就是不可見的。這就是 JavaScript 語言特有的"鏈式作用域"結構(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立。

既然f2可以讀取f1的局部變量,那麼只要把f2作為返回值,我們不就可以在f1外部讀取它的內部變量了嗎!

function f1() {
 var n = 999;
  function f2() {  
    console.log(n);  }  return f2;}var result = f1();result();

上面代碼中,函數f1的返回值就是函數f2,由於f2可以讀取f1的內部變量,所以就可以在外部獲得f1的內部變量了。

閉包就是函數f2,即能夠讀取其他函數內部變量的函數。由於在 JavaScript 語言中,只有函數內部的子函數才能讀取內部變量,因此可以把閉包簡單理解成「定義在一個函數內部的函數」。閉包最大的特點,就是它可以「記住」誕生的環境,比如f2記住了它誕生的環境f1,所以從f2可以得到f1的內部變量。在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。

閉包的最大用處有兩個,一個是可以讀取函數內部的變量,另一個就是讓這些變量始終保持在內存中,即閉包可以使得它誕生環境一直存在。請看下面的例子,閉包使得內部變量記住上一次調用時的運算結果。

function createIncrementor(start) {  
return function () {
   return start++;  };}var inc = createIncrementor(5);inc() inc() inc()

上面代碼中,start是函數createIncrementor的內部變量。通過閉包,start的狀態被保留了,每一次調用都是在上一次調用的基礎上進行計算。從中可以看到,閉包inc使得函數createIncrementor的內部環境,一直存在。所以,閉包可以看作是函數內部作用域的一個接口。

為什麼會這樣呢?原因就在於inc始終在內存中,而inc的存在依賴於createIncrementor,因此也始終在內存中,不會在調用結束後,被垃圾回收機制回收。

閉包的另一個用處,是封裝對象的私有屬性和私有方法。

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()

上面代碼中,函數Person的內部變量_age,通過閉包getAge和setAge,變成了返回對象p1的私有變量。

注意,外層函數每次運行,都會生成一個新的閉包,而這個閉包又會保留外層函數的內部變量,所以內存消耗很大。因此不能濫用閉包,否則會造成網頁的性能問題。

5.2、立即調用的函數表達式(IIFE)

在 Javascript 中,圓括號()是一種運算符,跟在函數名之後,表示調用該函數。比如,print()就表示調用print函數。

有時,我們需要在定義函數之後,立即調用該函數。這時,你不能在函數的定義之後加上圓括號,這會產生語法錯誤。

function(){

}();

產生這個錯誤的原因是,function這個關鍵字即可以當作語句,也可以當作表達式。

function f() {}
var f = function f() {}

為了避免解析上的歧義,JavaScript 引擎規定,如果function關鍵字出現在行首,一律解釋成語句。因此,JavaScript 引擎看到行首是function關鍵字之後,認為這一段都是函數的定義,不應該以圓括號結尾,所以就報錯了。

解決方法就是不要讓function出現在行首,讓引擎將其理解成一個表達式。最簡單的處理,就是將其放在一個圓括號裡面。

(function(){

}());
(function(){

})();

上面兩種寫法都是以圓括號開頭,引擎就會認為後面跟的是一個表示式,而不是函數定義語句,所以就避免了錯誤。這就叫做「立即調用的函數表達式」(Immediately-Invoked Function Expression),簡稱 IIFE。

注意,上面兩種寫法最後的分號都是必須的。如果省略分號,遇到連著兩個 IIFE,可能就會報錯。

(function(){ }())(function(){ }())

上面代碼的兩行之間沒有分號,JavaScript 會將它們連在一起解釋,將第二行解釋為第一行的參數。

推而廣之,任何讓解釋器以表達式來處理函數定義的方法,都能產生同樣的效果,比如下面三種寫法。

var i = function(){ return 10;
}();
true && function(){

}();0, function(){

}();

甚至像下面這樣寫,也是可以的。

!function () { }();~function () { }();-function () { }();+function () { }();

通常情況下,只對匿名函數使用這種「立即執行的函數表達式」。它的目的有兩個:一是不必為函數命名,避免了汙染全局變量;二是 IIFE 內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量。

var tmp = newData;processData(tmp);storeData(tmp);
(function () {  var tmp = newData;  processData(tmp);  storeData(tmp);}());

上面代碼中,寫法二比寫法一更好,因為完全避免了汙染全局變量。

6、eval 命令


6.1、基本用法

eval命令接受一個字符串作為參數,並將這個字符串當作語句執行。

eval('var a = 1;');a

上面代碼將字符串當作語句運行,生成了變量a。

如果參數字符串無法當作語句運行,那麼就會報錯。

eval('3x')

放在eval中的字符串,應該有獨自存在的意義,不能用來與eval以外的命令配合使用。舉例來說,下面的代碼將會報錯。

eval('return;');

上面代碼會報錯,因為return不能單獨使用,必須在函數中使用。

如果eval的參數不是字符串,那麼會原樣返回。

eval(123)

eval沒有自己的作用域,都在當前作用域內執行,因此可能會修改當前作用域的變量的值,造成安全問題。

var a = 1;eval('a = 2');a

上面代碼中,eval命令修改了外部變量a的值。由於這個原因,eval有安全風險。

為了防止這種風險,JavaScript 規定,如果使用嚴格模式,eval內部聲明的變量,不會影響到外部作用域。

(function f() {
 'use strict';  
eval('var foo = 123');  
console.log(foo);  
})()

上面代碼中,函數f內部是嚴格模式,這時eval內部聲明的foo變量,就不會影響到外部。

不過,即使在嚴格模式下,eval依然可以讀寫當前作用域的變量。

(function f() {
 'use strict';  var foo = 1;  eval('foo = 2');
 console.log(foo);  
 })()

上面代碼中,嚴格模式下,eval內部還是改寫了外部變量,可見安全風險依然存在。

總之,eval的本質是在當前作用域之中,注入代碼。由於安全風險和不利於 JavaScript 引擎優化執行速度,所以一般不推薦使用。通常情況下,eval最常見的場合是解析 JSON 數據的字符串,不過正確的做法應該是使用原生的JSON.parse方法。

6.2、eval 的別名調用

前面說過eval不利於引擎優化執行速度。更麻煩的是,還有下面這種情況,引擎在靜態代碼分析的階段,根本無法分辨執行的是eval。

var m = eval;m('var x = 1');x

上面代碼中,變量m是eval的別名。靜態代碼分析階段,引擎分辨不出m('var x = 1')執行的是eval命令。

為了保證eval的別名不影響代碼優化,JavaScript 的標準規定,凡是使用別名執行eval,eval內部一律是全局作用域。

var a = 1;function f() {  var a = 2;  var e = eval;  e('console.log(a)');}f()

上面代碼中,eval是別名調用,所以即使它是在函數中,它的作用域還是全局作用域,因此輸出的a為全局變量。這樣的話,引擎就能確認e()不會對當前的函數作用域產生影響,優化的時候就可以把這一行排除掉。

eval的別名調用的形式五花八門,只要不是直接調用,都屬於別名調用,因為引擎只能分辨eval()這一種形式是直接調用。

eval.call(null, '...')window.eval('...')(1, eval)('...')(eval, eval)('...')

上面這些形式都是eval的別名調用,作用域都是全局作用域。

本章節完~

推薦閱讀

【JavaScript 教程】入門篇-導論

【JavaScript 教程】入門篇-JavaScript 語言的歷史

【JavaScript 教程】入門篇-JavaScript 的基本語法

【JavaScript 教程】數據類型-null, undefined 和布爾值

【JavaScript 教程】數據類型-數值

【JavaScript 教程】數據類型-字符串

【JavaScript 教程】數據類型-對象


相關焦點

  • JavaScript 數據類型與類型判斷詳解
    JavaScript 數據類型有兩種,分別是基本數據類型和引用數據類型。
  • JavaScript 函數參數 | JavaScript 教程
    函數顯式參數(Parameters)與隱式參數(Arguments)在先前的教程中,我們已經學習了函數的顯式參數:functionName(parameter1, parameter2, parameter3) {  // 要執行的代碼……}函數顯式參數在函數定義時列出。函數隱式參數在函數調用時傳遞給函數真正的值。
  • 在javascript程式語言中,數據類型boolean的應用場景
    在javascript編程中,數據類型布爾是最常見的一種類型。此種類型邏輯上比較簡單,只有兩個值:true和false。布爾數據類型與計算機底層的電路開與關有著密切的關聯。但是,布爾值true不一定是1,false不一定是0。
  • javascript之常用數據類型及判斷方法
    前端工作者學習之路對於剛開始入門的前端人員來說,javascript中的數據類型是既熟悉又籠統的概念,不論在php,還是c語言抑或java,他們的數據類型都各不相同,大家也千萬不用混淆,今天,我們來具體重新了解下javascript中的常見數據類型以及他們的判斷方法。
  • JavaScript 中 Eval 函數的前世今生,執行代碼字符串
    因此我們不能從外部訪問在 eval 中聲明的函數和變量:// 提示:本教程所有可運行的示例都默認啟用了嚴格模式 'use strict'eval("let x = 5; function f() {}");alert(typeof x); // undefined(沒有這個變量)// 函數 f 也不可從外部進行訪問
  • 【JavaScript 教程】第二章基礎知識04—JavaScript Number
    /譯文 | 楊小愛那麼,在今天的教程中,我們將一起來學習了解 JavaScript Number類型及其有效處理數字的有用方法。JavaScript 數字類型介紹除了原始數字類型,JavaScript 還為數值提供了 Number 引用類型。
  • 12 個 GitHub 上超火的 JavaScript 奇技淫巧項目,找到寫 JavaScript 的靈感!
    目錄調用堆棧原始類型值類型和引用類型隱式, 顯式, 名義和鴨子類型== 與 ===, typeof 與 instanceofthis, call, apply 和 bind函數作用域, 塊級作用域和詞法作用域閉包map
  • JavaScript入門教程
    起源javascript前身叫做livescript,sun公司推出java,netspace公司引進java的概念,重新設計livescript,並更名javascript。發明者,布蘭登.艾克,表單驗證原先要經過伺服器,伺服器壓力大,等待時間長,js僅在客戶端就可完成。是什麼是一種腳本語言,是一種輕量級的程式語言。
  • 浪漫javascript程式設計師:用浪漫的方式教你模仿函數重載
    浪漫javascript程式設計師:用浪漫的方式教你模仿函數重載。浪漫是一種生活儀式,不分年齡,不分職業,不分地位。現在,且看程式設計師的浪漫模式。在javascript語言中,函數是沒有重載功能的。也就是說,在javascript函數中,無法通過識別參數的個數及數據類型調用有不同功能的同名函數。但是,程式設計師可以藉助javascript函數中的arguments對象的特性,模仿實現函數的重載,在一定程度上彌補了該程式語言中函數功能的不足。
  • 經常被面試官考的 JavaScript 數據類型知識你真的懂嗎?
    本篇文章會以一個面試官問問題的角度來進行分析講解js中的數據類型面試官問:說一說javascript中有哪些數據類型?JavaScript 中共有七種內置數據類型,包括基本類型和對象類型。這五種類型統稱為原始類型(Primitive),表示不能再細分下去的基本類型symbol是ES6中新增的數據類型,symbol 表示獨一無二的值,通過 Symbol 函數調用生成,由於生成的 symbol 值為原始類型,所以 Symbol 函數不能使用 new 調用;null 和 undefined 通常被認為是特殊值,這兩種類型的值唯一,就是其本身。
  • 【第1745期】現代 JavaScript 教程 - 類型檢測:"instanceof"
    這種檢測在多數情況下還是比較有用的,下面,我們就用它來構建一個具備 多態 性的函數,這個函數能識別出參數類型,從而作出不同的處理。instanceof用法:obj instanceof Class如果 obj 隸屬於 Class 類(或者是 Class 類的衍生類),表達式將返回 true。
  • 走近 (javascript, 函數式)
    在這裡,「名詞」是第一詞彙,我們將程序視為一系列自上而下的命令,去不斷修改其中的數據,我們更專注於描述不同數據結構之間的關係。其中,我們把一類相關的數據和命令封裝在一起,形成了類和對象,形成了面向對象的編程方式。函數式編程卻屬於聲明式的編程方式,這種範式會描述一系列的操作,而不去暴露它們是如何實現的,以及數據是如何從中間穿過。
  • JavaScript函數的6個基本術語
    Lambda expressions(匿名函數表達式) 是函數式編程的基石。如果它對你有所幫助,只需將它視為函數的新縮短語法就行。然而,在對象或類中使用它們時要注意this的指向。什麼是first-class functions(頭等函數)?First-class type 意味著,該類型可以用作變量的值。
  • 七天學會javascript第一天javascript介紹
    javascript介紹javascript數據類型javascript運算符javascript對象javascriptjavascript :客戶端編程。javascript是由客戶端去解釋運行的。怎麼引入javascript 呢?
  • 【JavaScript】Promise函數的用法
    javascript
  • 從 JavaScript 到 TypeScript - 聲明類型
    ]enumT,定義枚舉類型 T,可理解為集中對數值常量進行命名interfaceT,接口, T 是一種接口類型classT,類, T 是一種類型any,代表任意類型void,表示沒有類型,用於聲明函數類型never,表示函數不可返回的神奇類型……具體的類型這裡就不詳述了,官方 Handbook
  • 【JavaScript 教程】標準庫—Math 對象
    Math.random() 任意範圍的隨機數生成函數如下。2.10、三角函數方法Math對象還提供一系列三角函數方法。】入門篇-導論【JavaScript 教程】入門篇-JavaScript 語言的歷史【JavaScript 教程】入門篇-JavaScript 的基本語法【JavaScript 教程】數據類型-概述【JavaScript 教程】數據類型-null, undefined 和布爾值【JavaScript 教程】數據類型-數值
  • JavaScript數據類型轉換
    雖然變量的數據類型是不確定的,但是各種運算符對數據類型是有要求的。如果運算符發現,運算子的類型與預期不符,就會自動轉換類型。本文主要介紹數據類型強制轉換和自動轉換,自動轉換是基於強制轉換之上。強制轉換主要指使用Number、String和Boolean三個函數,手動將各種類型的值,分布轉換成數字、字符串或者布爾值。
  • 用 JavaScript 框架繞過 XSS 防禦
    一次性進群,長期免費索取教程,沒有付費教程。
  • Excel VBA入門教程1.1 數據和數據類型
    類似的要使用vba,也要入鄉隨俗,了解他的構成,簡單的說vba包含數據類型、 變量/常量、對象和常用的語句結構。不過呢在量和複雜度上遠低於英語,不用那麼痛苦的記單詞了,所以vba其實很簡單的。熟悉了規則之後剩下就是查官方函數啦,查Excel提供的可操作對象啦。順帶一提的是,函數其實也很容易理解,方便使用。