成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

函數(shù) 閉包eeva iife

AnthonyHan / 3323人閱讀

摘要:概述函數(shù)的聲明命令函數(shù)表達式變量賦值命令后面不帶有函數(shù)名。如果加上函數(shù)名,該函數(shù)名只在函數(shù)體內部有效,在函數(shù)體外部無效。同樣的,函數(shù)體內部聲明的函數(shù),作用域綁定函數(shù)體內部。可以通過,達到調用函數(shù)自身的目的。

函數(shù)

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

1.概述
1.1函數(shù)的聲明
1.2函數(shù)的重復聲明
1.3圓括號運算符,return 語句和遞歸
1.4第一等公民
1.5函數(shù)名的提升
2函數(shù)的屬性和方法
2.1name 屬性
2.2length 屬性
2.3toString()
3函數(shù)作用域
3.1定義
3.2函數(shù)內部的變量提升
3.3函數(shù)本身的作用域
4參數(shù)
4.1概述
4.2參數(shù)的省略
4.3傳遞方式
4.4同名參數(shù)
4.5arguments 對象
5.函數(shù)的其他知識點
5.1閉包
5.2立即調用的函數(shù)表達式(IIFE)
6eval 命令
6.1基本用法
6.2eval 的別名調用

函數(shù)

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

1.概述
1.1函數(shù)的聲明
(1)function 命令
(2)函數(shù)表達式 變量賦值

var print = function(s) {}

function命令后面不帶有函數(shù)名。如果加上函數(shù)名,該函數(shù)名只在函數(shù)體內部有效,在函數(shù)體外部無效。

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

x
// ReferenceError: x is not defined

print()
// function

用處有兩個,一是可以在函數(shù)體內部調用自身,二是方便除錯(除錯工具顯示函數(shù)調用棧時,將顯示函數(shù)名,而不再顯示這里是一個匿名函數(shù))。

(3)Function 構造函數(shù)
var add = new Function(
"x",
"y",
"return x + y"
);除了最后一個參數(shù)是add函數(shù)的“函數(shù)體”,其他參數(shù)都是add函數(shù)的參數(shù)

// 等同于
function add(x, y) {
return x + y;
}

1.2函數(shù)的重復聲明
由于函數(shù)名的提升
后面的聲明就會覆蓋前面的聲明

1.3圓括號運算符,return 語句和遞歸
圓括號用于調用函數(shù)a()
遇到return后面句子都不執(zhí)行,沒有就返回undefined

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

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

fib(6) // 8

1.4第一等公民
函數(shù)只是一個可以執(zhí)行的值

函數(shù)只是一個可以執(zhí)行的值

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

// 將函數(shù)賦值給一個變量
var operator = add;

// 將函數(shù)作為參數(shù)和返回值
function a(op){
return op;
}
a(add)(1, 1)
// 2

1.5函數(shù)名的提升
視為變量名,所以采用function命令聲明函數(shù)時,整個函數(shù)會像變量聲明一樣
表達式形式是匿名函數(shù)
f();
var f = function (){};
// TypeError: undefined is not a function
上面的代碼等同于下面的形式。

var f;
f();
f = function () {};
上面代碼第二行,調用f的時候,f只是被聲明了,還沒有被賦值,等于undefined,所以會報錯。因此,如果同時采用function命令和賦值語句聲明同一個函數(shù),最后總是采用賦值語句的定義。 因為兩個都是聲明 ,然后賦值 function形式是聲明 var聲明 最后賦值

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

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

f() // 1

2函數(shù)的屬性和方法
2.1name 屬性
2.1.1function f1() {}
f1.name // "f1"
如果是通過變量賦值定義的函數(shù),那么name屬性返回變量名。

2.2.2var f2 = function () {};
f2.name // "f2"

如果變量的值是一個具名函數(shù),那么name屬性返回function關鍵字之后的那個函數(shù)名。

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

f3.name返回函數(shù)表達式的名字。注意,真正的函數(shù)名還是f3,而myName這個名字只在函數(shù)體內部可用

2.2.4name屬性的一個用處,就是獲取參數(shù)函數(shù)的名字。
var myFunc = function () {};

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

test(myFunc) // myFunc

2.2length 屬性
函數(shù)定義之中的參數(shù)個數(shù)。

2.3toString()
返回一個字符串,內容是函數(shù)的源碼。
Math.sqrt.toString()
// "function sqrt() { [native code] }
利用這一點,可以變相實現(xiàn)多行字符串。

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

function f() {/*
這是一個
多行注釋
*/}

multiline(f);
// " 這是一個
// 多行注釋"

3函數(shù)作用域
3.1定義
3.1.1全局 一直存在在內存 到處可讀取

3.1.2 函數(shù)作用域 變量只在函數(shù)種存在
對于var命令來說,局部變量只能在函數(shù)內部聲明,在其他區(qū)塊中聲明,一律都是全局變量。

3.2函數(shù)內部的變量提升
函數(shù)作用域內部也會產生“變量提升”現(xiàn)象。var命令聲明的變量,不管在什么位置,變量聲明都會被提升到函數(shù)體的頭部

3.3函數(shù)本身的作用域
作用域只與聲明的地方有關
函數(shù)本身也是一個值,也有自己的作用域。它的作用域與變量一樣,就是其聲明時所在的作用域,與其運行時所在的作用域無關
var a = 1;
var x = function () {
console.log(a);
};

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

f() // 1

函數(shù)x是在函數(shù)f的外部聲明的,所以它的作用域綁定外層,內部變量a不會到函數(shù)f體內取值,所以輸出1,而不是2。
3.3.1同樣的,函數(shù)體內部聲明的函數(shù),作用域綁定函數(shù)體內部。

function foo() {
var x = 1;
function bar() {

console.log(x);

}
return bar;
}

var x = 2;
var f = foo();
f() // 1
上面代碼中,函數(shù)foo內部聲明了一個函數(shù)bar,bar的作用域綁定foo。當我們在foo外部取出bar執(zhí)行時,變量x指向的是foo內部的x,而不是foo外部的x。正是這種機制,構成了下文要講解的“閉包”現(xiàn)象。

4參數(shù)
4.1概述

4.2參數(shù)的省略
4.1.1無論提供多少個參數(shù)(或者不提供參數(shù)),JavaScript 都不會報錯。省略的參數(shù)的值就變?yōu)閡ndefined。需要注意的是,函數(shù)的length屬性與實際傳入的參數(shù)個數(shù)無關
4.1.2沒有辦法只省略靠前的參數(shù),而保留靠后的參數(shù)。如果一定要省略靠前的參數(shù),只有顯式傳入undefined。

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

f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined
上面代碼中,如果省略第一個參數(shù),就會報錯。

4.3傳遞方式
4.3.1函數(shù)參數(shù)如果是原始類型的值(數(shù)值、字符串、布爾值),傳遞方式是傳值傳遞。在函數(shù)里面的是復制的另外一個值了

在函數(shù)體內修改參數(shù)值,不會影響到函數(shù)外部

var p = 2;

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

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

4.3.2如果函數(shù)參數(shù)是復合類型的值(數(shù)組、對象、其他函數(shù)),傳遞方式是傳址傳遞

傳入函數(shù)的原始值的地址,因此在函數(shù)內部修改參數(shù),將會影響到原始值。

var obj = { p: 1 };

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

obj.p // 2
上面代碼中,傳入函數(shù)f的是參數(shù)對象obj的地址。因此,在函數(shù)內部修改obj的屬性p,會影響到原始值。(外面和里面指向同一個地址)

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

var obj = [1, 2, 3];

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

obj // [1, 2, 3]

形式參數(shù)(o)的值實際是參數(shù)obj的地址,重新對o賦值導致o指向另一個地址,保存在原地址上的值當然不受影響。(外面和里面指向不同地址了)
4.4同名參數(shù)

如果有同名的參數(shù),則取最后出現(xiàn)的那個值

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

f(1, 2) // 2

取值的時候,以后面的a為準,即使后面的a沒有值或被省略,也是以其為準。

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

f(1) // undefined

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

f(1) // 1

4.5arguments 對象
4.5.1只能在函數(shù)體內用
正常可以修改 嚴格無效
有l(wèi)ength屬性

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

f(1, 1) // 5

4.5.2與數(shù)組的關系
數(shù)組專有的方法(比如slice和forEach),不能在arguments對象上直接使用

兩種常用的轉換方法:slice方法和逐一填入新數(shù)組。

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

// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}

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

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

f() // true
可以通過arguments.callee,達到調用函數(shù)自身的目的。這個屬性在嚴格模式里面是禁用的,因此不建議使用。
5.函數(shù)的其他知識點
5.1閉包
定義在函數(shù)內的函數(shù)
用處 1.讀取函數(shù)內的變量

2.讓這些變量始終保存在內存中

function createIncrementor(start) {
return function () {

return start++;

};
}

var inc = createIncrementor(5);

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

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

因為inc是全局的,使得閉包可以一直存在同時訪問內部變量

3封裝私有變量

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
上面代碼中,函數(shù)Person的內部變量_age,通過閉包getAge和setAge,變成了返回對象p1的私有變量

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

5.2立即調用的函數(shù)表達式(IIFE)
()是運算符 表達式
function(){ / code / }();
// SyntaxError: Unexpected token (
產生這個錯誤的原因是,function這個關鍵字即可以當作語句,也可以當作表達式。
如果function關鍵字出現(xiàn)在行首,一律解釋成語句。因此,JavaScript 引擎看到行首是function關鍵字之后,認為這一段都是函數(shù)的定義,不應該以圓括號結尾

// 語句
function f() {}

// 表達式
var f = function f() {}

5.2.1最簡單的處理,就是將其放在一個圓括號里面。

(function(){ / code / }());
// 或者
(function(){ / code / })();
上面兩種寫法都是以圓括號開頭,引擎就會認為后面跟的是一個表示式,而不是函數(shù)定義語句,所以就避免了錯誤。這就叫做“立即調用的函數(shù)表達式

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

var i = function(){ return 10; }();
true && function(){ / code / }();
0, function(){ / code / }();
甚至像下面這樣寫,也是可以的。

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

5.2.2目的
1.不必為函數(shù)命名,避免污染全局變量
2.封裝私有變量
// 寫法一
var tmp = newData;
processData(tmp);
storeData(tmp);

// 寫法二
(function () {
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
上面代碼中,寫法二比寫法一更好,因為完全避免了污染全局變量

6eval() 命令
6.1接受一個字符串當參數(shù)并當語錄執(zhí)行 否則報錯
eval("var a = 1;");
a // 1

eval("3x") // Uncaught SyntaxError: Invalid or unexpected token
6.2
放在eval中的字符串,應該有獨自存在的意義,不能用來與eval以外的命令配合使用。舉例來說,下面的代碼將會報錯。

eval("return;"); // Uncaught SyntaxError: Illegal return statement

6.3如果eval的參數(shù)不是字符串,那么會原樣返回。

eval(123) // 123

6.4作用域
var a = 1;
eval("a = 2");

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

如果使用嚴格模式,(自己聲明的不會影響,上面的問題依然有)eval內部聲明的變量,不會影響到外部作用域。

(function f() {
"use strict";
eval("var foo = 123");
console.log(foo); // ReferenceError: foo is not defined
})()

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

eval最常見的場合是解析 JSON 數(shù)據(jù)的字符串,不過正確的做法應該是使用原生的JSON.parse方法

6.1基本用法
6.2eval 的別名調用
1.eval不利于引擎優(yōu)化執(zhí)行速度

2.引擎在靜態(tài)代碼分析的階段,根本無法分辨執(zhí)行
的是eval。

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

為了保證eval的別名不影響代碼優(yōu)化改進:用別名的話,里面都是全局變量

var a = 1;

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

f() // 1

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

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

eval.call(null, "...")
window.eval("...")
(1, eval)("...")
(eval, eval)("...")
上面這些形式都是eval的別名調用,作用域都是全局作用域。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://m.hztianpu.com/yun/105995.html

相關文章

  • 重讀你不知道的JS (上) 第一節(jié)五章

    摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關,即使本身并不會真的使用閉包。而上面的創(chuàng)建一個閉包,本質上這是將一個塊轉換成一個可以被關閉的作用域。結合塊級作用域與閉包模塊這個模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Jav...

    worldligang 評論0 收藏0
  • 作用域閉包

    摘要:由于聲明在函數(shù)內部,所以它擁有涵蓋內部作用域的閉包,使得該作用域能夠一直存活,以便在以后的任何時間進行引用。盡管本身并不是觀察閉包的恰當例子,但他的確創(chuàng)建了一個封閉的作用域,并且也是最常用來創(chuàng)建被封閉起來的閉包的工具。 在講解作用域閉包的內容之前,需要對以下概念有所掌握: JavaScript具有兩種作用域:全局作用域和函數(shù)作用域,至于塊作用域也不能說沒有,比如說: try .....

    Anleb 評論0 收藏0
  • 講清楚之 javascript 函數(shù)

    摘要:中函數(shù)是一等公民。小明小明調用函數(shù)時,傳遞給函數(shù)的值被稱為函數(shù)的實參值傳遞,對應位置的函數(shù)參數(shù)名叫作形參。所以不推薦使用構造函數(shù)創(chuàng)建函數(shù)因為它需要的函數(shù)體作為字符串可能會阻止一些引擎優(yōu)化也會引起瀏覽器資源回收等問題。 函數(shù) 之前幾節(jié)中圍繞著函數(shù)梳理了 this、原型鏈、作用域鏈、閉包等內容,這一節(jié)梳理一下函數(shù)本身的一些特點。 javascript 中函數(shù)是一等公民。 并且函數(shù)也是對象,...

    Keagan 評論0 收藏0
  • Effective JavaScript讀書筆記(二)

    摘要:盡可能的使用局部變量,少用全局變量。正確的實現(xiàn)就是在函數(shù)體內部使用將聲明成局部變量。在新特性中,引入了塊級作用域這個概念,因此還可以使用,來聲明局部變量。它們共享外部變量,并且閉包還可以更新的值。 變量作用域 作用域,對于JavaScript語言來說無處不在,變量作用域,函數(shù)作用域(運行時上下文和定義時上下文),作用域污染等等都跟作用域息息相關,掌握JavaScript作用于規(guī)則,可以...

    Yuqi 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<