摘要:所謂閉包,是指詞法表示包括不必計算的變量的函數(shù)。回調(diào)函數(shù)回調(diào)函數(shù)執(zhí)行回調(diào)函數(shù)中的回調(diào)函數(shù)的返回值用來遍歷數(shù)組中的每一項數(shù)組中有幾項,那么傳遞進去的匿名回調(diào)函數(shù)就需要執(zhí)行幾次。
初始函數(shù)
Function類型,即函數(shù)的類型。
典型的JavaScript函數(shù)定義:
function 函數(shù)名稱(參數(shù)表){ //函數(shù)執(zhí)行部分 return ; } //注意:參數(shù)列表直接寫形參名即可
return語句:return返回函數(shù)的返回值并結(jié)束函數(shù)運行
函數(shù)也可以看做數(shù)據(jù)來進行傳遞
參數(shù)列表相當于函數(shù)入口,return 語句相當于函數(shù)出口
函數(shù)可以作為參數(shù)來傳遞。
function test ( a ) { a(); } test(function () { alert(1); });
函數(shù)可以嵌套定義
function test2(){ function test3(){ alert(1); } test3(); } test2();定義函數(shù)
三種定義函數(shù)的方式:
function語句形式
函數(shù)直接量形式
通過Function構造函數(shù)形式定義函數(shù)
//1 function 語句式 function test1 () { alert(1); } //2 函數(shù)直接量 (ECMAScript 推薦) var test2 = function () { alert(2); } //3 function 構造函數(shù)式 var test3 = new Function("a","b","return a+b;"); //最后一個參數(shù)是函數(shù)結(jié)構體 test3(10,20);
function語句 | Function構造函數(shù) | 函數(shù)直接量 | |
---|---|---|---|
兼容 | 完全 | js1.1以上 | js1.2以上版本 |
形式 | 句子 | 表達式 | 表達式 |
名稱 | 有名 | 匿名 | 匿名 |
性質(zhì) | 靜態(tài) | 動態(tài) | 靜態(tài) |
解析時機 | 優(yōu)先解析 | 順序解析 | 順序解析 |
作用域 | 具有函數(shù)的作用域 | 頂級函數(shù)(頂級作用域) | 具有函數(shù)作用域 |
靜態(tài)動態(tài)的區(qū)別
var d1 = new Date(); var t1 = d1.getTime(); for ( var i=0; i<10000000; i++ ) { // function test1 () {} // 342ms //在函數(shù)體只會被聲明一次 ,其它地方并不再解析,就可以調(diào)用 。 //靜態(tài) //只會編譯一次,放入內(nèi)存中。 var test2 = function () {} //354ms // var test3 = new Function(); //8400ms //每次執(zhí)行,都是重新new一個 函數(shù)。 //new 完之后, 就銷毀了。不占用內(nèi)存。動態(tài)創(chuàng)建一次。 } var d2 = new Date(); var t2 = d2.getTime(); console.log( t2 - d1 );
解析順序
function f () { return 1; } // 函數(shù)1 alert( f() ); //返回值為4 說明第1個函數(shù)被第4個函數(shù)覆蓋 var f = new Function("return 2;"); // 函數(shù)2 alert( f() ); //返回值為2 說明第4個函數(shù)被第2個函數(shù)覆蓋 var f = function () { return 3; } // 函數(shù)3 alert( f() ); //返回值為3 說明第2個函數(shù)被第3個函數(shù)覆蓋 function f () { return 4; } // 函數(shù)4 alert(f()); //返回值為3 說明第4個函數(shù)被第3個函數(shù)覆蓋 var f = new Function("return 5"); // 函數(shù)5 alert(f()); //返回值為5 說明第3個函數(shù)被第5個函數(shù)覆蓋 var f = function(){ return 6; } // 函數(shù)6 alert(f()); //返回值為6 說明第5個函數(shù)被第6個函數(shù)覆蓋
函數(shù)作用域
var k = 1 ; function t1(){ var k = 2 ; // function test(){return k ;} //2 // var test = function(){ return k}; //2 var test = new Function("return k;"); //1 //new Function(); 是會有頂級作用域 alert(test()); } t1();函數(shù)的參數(shù)arguments
arguments對象,是實參的副本
//js 中 函數(shù)分為 : 形參,實參 function test ( a,b,c,d ) { // console.log( test.length ); //獲取形參的個數(shù) 4 //函數(shù)的實際參數(shù) 內(nèi)部就是使用一個數(shù)組去接收實際參數(shù)。 類數(shù)組對象 //arguments 對象,只能在函數(shù)內(nèi)部使用。 //arguments 對象, 可以訪問函數(shù)的實際參數(shù) (實參的副本) // console.log( arguments.length ); //2 // console.log( arguments[0] ); //10 // // 第一種方式: // if ( test.length === arguments.length ) { // // return a + b; // // } //使用第二種 方式: if ( arguments.callee.length === arguments.length ) { return a + b; } //arguments對象, 使用得最多的還是使用遞歸操作 // arguments.callee; // 指向函數(shù)本身,函數(shù)體 } test(10,20);this對象的簡單理解
this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的
在全局函數(shù)中,this等于window,而當函數(shù)被作為某個對象的方法調(diào)用時,this等于那個對象。
也就是說this關鍵字總是指代調(diào)用者(誰調(diào)用了我,就指向誰)。
//this: this對象是指在運行時期基于執(zhí)行環(huán)境所綁定的 var k = 10; function test () { this.k = 20; } test(); console.log( test.k ); //undefinedcall和apply方法
每一個函數(shù)都包含兩個非繼承而來的方法:call、apply。這倆個方法的用途都是在特定的作用域中調(diào)用函數(shù),實際上等于設置函數(shù)體內(nèi)this對象的值。
call、apply的用途之一就是傳遞參數(shù),但事實上,它們真正強大的地方式能夠擴充函數(shù)賴以運行的作用域(使你的作用域不斷的去變化)。
使用call()、aplly()來擴充作用域的最大好處就是對象不需要與方法有任何耦合關系。
fn.call(obj);
讓fn以運行,并且fn中的this以obj身份運行
將一個函數(shù)綁定到一個特定的作用域中,然后傳遞特定作用域中的參數(shù)。
//call, apply 簡單 用法: 綁定一些函數(shù) 用于傳遞參數(shù) 調(diào)用 function sum ( x,y ) { return x + y; } function call1 ( num1,num2 ) { return sum.call(this,num1,num2); } function apply1 ( num1,num2 ) { return sum.apply(this,[num1,num2]) } //將一個函數(shù)綁定到一個特定的作用域中,然后傳遞特定作用域中的參數(shù)。 console.log( call1(10,10) ); console.log( apply1(20,10) );
//擴充作用域,底層也經(jīng)常使用這兩個方法,用于綁定不同的作用域。 //把一個函數(shù)賦給一個對象, 賦完之后,還可以重用,賦給另外一個對象。 window.color = "pink"; var obj = { color: "tan" } function showColor () { console.log( this.color ); } showColor.call(window); // showColor.call(this); showColor.apply(obj);
call方法簡單的實現(xiàn)
function test1 ( a,b ) { return a + b; } //自定義對象 function Obj ( x,y ) { return x * y; } var obj = new Obj(); //掛載到對象上 obj.method = test1; //執(zhí)行該函數(shù) obj.method(10,20); //執(zhí)行完后刪除 delete obj.method;bind
ES5中提供一個bind()方法。
為函數(shù)綁定一個執(zhí)行時候的作用域。
將該方法綁定Function的原型上,因此定義一個function就有該方法,bind()添加作用域的時候,方法沒有執(zhí)行,在方法執(zhí)行的時候,作用域會變成綁定兌現(xiàn)的作用域。
function b () { console.log(this.title); } function Book ( title ) { this.title = title; } var book = new Book("javascript"); // apply , call 特點:調(diào)用就執(zhí)行 // b.call(book); // b.apply(book); // 當執(zhí)行一個函數(shù)的時候更改作用域 var bBindfn = b.bind(book); // 執(zhí)行更改作用域 bBindfn();執(zhí)行環(huán)境和作用域鏈概念
執(zhí)行環(huán)境(execution context)是javascript中最為重要的一個概念。執(zhí)行環(huán)境定義了變量或函數(shù)有權訪問的其他數(shù)據(jù),決定了它們各自的行為。每一個執(zhí)行環(huán)境都有一個與之關聯(lián)的變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中。雖然我們的代碼無法訪問這個對象,但是解析器在處理數(shù)據(jù)時會在后臺執(zhí)行它。
全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境。根據(jù)ECMScript實現(xiàn)所在的宿主環(huán)境不同,表示執(zhí)行環(huán)境的對象也不一樣。
每一個函數(shù)都有自己的執(zhí)行環(huán)境。當執(zhí)行流進一個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中。而在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權返還給之前的執(zhí)行環(huán)境。當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈(scope chain)。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問(控制代碼的訪問權限)。
var color1 = "blue"; function changeColor () { var color2 = "red"; function swapColor () { var color3 = color2; //color3 = "red" color2 = color1; //color2 = "blue" color1 = color3; //color1 = "red" console.log( color1,color2,color3 ); } swapColor(); } changeColor(); //環(huán)境變量 可以一層一層的向上進行追溯 可以訪問它的上級 環(huán)境(變量和函數(shù)) // 作用域鏈 具有層級關系 //在大型程序中,全局變量,盡量少使用,因為全局變量總是最后一次搜索。 防止全局變量污染。//很少去定義全局變量,效率比較慢。垃圾收集和塊級作用域的概念 垃圾收集
javascript是一門具有自動垃圾收集機制的編程語言。開發(fā)人員不必關心內(nèi)存分配和回收問題。
垃圾回收器也是每隔一段時間去進行回收。
離開作用域的值將被自動標記為可以回收,因此將在垃圾收集期間被刪除。標記清除是目前主流的垃圾收集算法。這種思想是給當前不使用的值加上標記,然后回收其內(nèi)存。
//垃圾收集 ,標記清除 (模擬) function test () { var a = 10; //mark - 被使用 var b = 20; //mark - 被使用 } test(); //執(zhí)行完畢 之后 ,a,b又被標記使用。 mark - 沒有被使用 //在間隔時間中 回收。 如果mark 沒有被使用, 則回收。
//引用計數(shù)(模擬) //如果變量被引用 , count = 1; function test2 () { var a = 10; //count = 1; var b = 20; var c; c = a; //count++ = 2; //a 被 c 所使用 ,引用。 a = 50; //count--; //重新被賦值 count-- //等待 count 為 0 的時候, 垃圾回收機制 就回收 }塊級作用域
javascript里面沒有塊級作用域的概念,所以在使用if、for時候要格外的小心。
javascript模擬塊級作用域 (塊級作用域,相當于內(nèi)部的執(zhí)行體,一個執(zhí)行環(huán)境)
利用 IIEF的特性
//當函數(shù)執(zhí)行之后, 變量就被回收 function test () { (function () { //函數(shù)有一個多帶帶的作用域,外面無法訪問到 i for ( var i=0; i<=5; i++ ) { console.log( i ); } })(); console.log( i ); //報錯,無法找到 } test();閉包 Closure
閉包與函數(shù)有著緊密的關系,它是函數(shù)的代碼在運行過程中的一個動態(tài)環(huán)境,是一個運行期的、動態(tài)的概念。
所謂閉包,是指詞法表示包括不必計算的變量的函數(shù)。也就是說,該函數(shù)能夠使用函數(shù)外定義的變量。
在程序語言中,所謂閉包,是指語法域位于某個特定的區(qū)域,具有持續(xù)參照(讀寫)位于該區(qū)域內(nèi)自身范圍之外的執(zhí)行域上的非持久型變量值能力的段落。這些外部執(zhí)行域的非持久型變量神奇地保留它們在閉包最初定義(或創(chuàng)建)時的值
理解閉包,必須要對于作用域鏈的概念非常的清楚。
var name = "xiao A"; var obj = { name : "xiao B", getName: function(){ return function(){ return this.name; } } }; console.log(obj.getName()()); //xiao A //類似: //var zf = obj.getName();//全局作用域 //zf();
var name = "xiao A"; var obj = { name : "xiao B", getName: function(){ var self = this; return function(){ return self.name; } } }; //console.log( obj.getName().call(obj) ); console.log( obj.getName()() ); //閉包: 一個函數(shù), 可以訪問另外一個作用域中的變量 //封閉性,(類似食品包裝袋一樣,封閉起來,保質(zhì)期延長,變量的訪問范圍的延長) //private 起到一個保護變量的作用
//1 level function f(x){ //2 level var temp = x; //局部變量 //temp 標記 已經(jīng)沒有被使用 return function(x){ //3 level (function 有一個執(zhí)行域) temp += x; //temp 下一級作用域仍然被引用 , 標記為 使用 alert(temp); } } //js 垃圾回收機制,當函數(shù)執(zhí)行完畢后,內(nèi)部所有的局部變量都集體的被回收。 var a = f(50); a(5); //55 a(10); //65 a(20); //85回調(diào)函數(shù)
回調(diào)函數(shù)執(zhí)行
回調(diào)函數(shù)中的this
回調(diào)函數(shù)的返回值
forEach
// forEach:用來遍歷數(shù)組中的每一項 // 1. 數(shù)組中有幾項,那么傳遞進去的匿名回調(diào)函數(shù)就需要執(zhí)行幾次。 // 2. 每一次執(zhí)行匿名函數(shù)的時候,還傳遞了三個參數(shù)值:數(shù)組中的當前項item,當前項的索引index,原始的數(shù)組input // forEach方法中的this是arr,匿名函數(shù)回調(diào)函數(shù)的this默認是window var arr = [10, 234, 23, 76, 7666, 34]; arr.forEach(function(item, index, input) { input[index] = item * 10; // 操作之后,修改了原數(shù)組 console.log(arguments); }); var obj = {name: "zf"}; // arr.forEach(function(item, index) { // console.log(this); // }.call(obj)); // 給forEach賦值的是時候,首先把匿名函數(shù)執(zhí)行,把匿名函數(shù)中的this變?yōu)閛bj,把匿名函數(shù)執(zhí)行的返回結(jié)果undefined賦值給foreach arr.forEach(function(item, index) { console.log(this, "---"); }.bind(obj)); // bind 只是預先處理,先把this轉(zhuǎn)為參數(shù)的對象,到后續(xù)該執(zhí)行的時候才執(zhí)行。 // 不管是forEach,還是map都支持第二個參數(shù),第二個參數(shù)表示:把匿名函數(shù)中的this進行修改。 arr.forEach(function() { console.log(this, "this"); }, obj);
forEach兼容處理
// 兼容處理 Array.prototype._forEach = function(callback, context) { content = content || window; if ("forEach" in Array.prototype) { this.forEach(callback, context); return; } // IE6-8,執(zhí)行回調(diào)邏輯 for (var i=0; imap
var arr = [10, 234, 23, 76, 7666, 34]; arr.map(function(item, index, input) { // 原有數(shù)組不變 console.log(arguments); return item * 10; }); // map和forEach非常相似,都是用來遍歷數(shù)組中的每一項的值 // 區(qū)別:map的回調(diào)函數(shù)中支持return返回值,return的是什么,相當于把數(shù)組中的這一項改變?yōu)槭裁矗ǖ遣⒉挥绊懺瓉淼臄?shù)組,只是相當于把原數(shù)組克隆一份,把克隆的這一份的數(shù)組中的對應項改變)map兼容處理
Array.prototype._map = function(callback, context) { context = context || window; if ("map" in Array.prototype) { this.map(callback, context); return; } // IE6-8,執(zhí)行回調(diào)邏輯 var resArr = []; for (var i=0; i柯理化函數(shù)思想 柯理化函數(shù)思想:一個JS預處理思想
核心:利用函數(shù)執(zhí)行可以形成一個不銷毀的私有作用域的原理,把需要預先處理的內(nèi)容都存儲在這個不銷毀的作用域中,并且返回一個匿名函數(shù),執(zhí)行的都是匿名函數(shù),把匿名函數(shù)中,把之前的預先存儲的值進行相關操作處理即可。
var obj = {name: "zf"}; function fn(num1, num2) { console.log(this, num1, num2) } // 把傳遞進來的callback這個方法中的this預先處理為context function bind(callback, context) { context = context || window; var outArg = Array.prototype.slice.call(arguments, 2); return function(ev) { var innerArg = Array.prototype.slice.call(arguments, 0); callback.apply(context, outArg.concat(innerArg)); } } // document.body.onclick = fn; // fn 中的 this是document.body. num1是 MouseEven對象 document.body.onclick = fn.bind(obj, 100, 200); // 除了預先處理了this和需要手動傳遞的參數(shù)值以外,把瀏覽器默認給傳遞的鼠標事件對象也進行預先處理,傳遞到最后一個參數(shù)。 document.body.onclick = bind(obj, 100, 200) // document.body.onclick = function() { // console.log(this); // this --> document.body // } // window.setTimeout(fn.bind(obj), 0); // window.setTimeout(bind(fn, obj, 100, 20), 0); // 給定時器綁定方法,然后定時器到達時間的時候,讓fn執(zhí)行,并且讓fn中的this變?yōu)閛bj
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79728.html
摘要:對象在中,除了數(shù)字字符串布爾值這幾個簡單類型外,其他的都是對象。那么在函數(shù)對象中,這兩個屬性的有什么區(qū)別呢表示該函數(shù)對象的原型表示使用來執(zhí)行該函數(shù)時這種函數(shù)一般成為構造函數(shù),后面會講解,新創(chuàng)建的對象的原型。這時的函數(shù)通常稱為構造函數(shù)。。 本文原發(fā)于我的個人博客,經(jīng)多次修改后發(fā)到sf上。本文仍在不斷修改中,最新版請訪問個人博客。 最近工作一直在用nodejs做開發(fā),有了nodejs,...
摘要:如下所示在規(guī)范中,已經(jīng)正式把屬性添加到規(guī)范中也可以通過設置和獲取對象的原型對象對象之間的關系可以用下圖來表示但規(guī)范主要介紹了如何利用構造函數(shù)去構建原型關系。 前言 在軟件工程中,代碼重用的模式極為重要,因為他們可以顯著地減少軟件開發(fā)的成本。在那些主流的基于類的語言(比如Java,C++)中都是通過繼承(extend)來實現(xiàn)代碼復用,同時類繼承引入了一套類型規(guī)范。而JavaScript是...
摘要:構造函數(shù)和實例都通過屬性指向了原形。代碼示例是構造函數(shù)的實例的屬性與的屬性保存的值相等,即他們指向同一個對象原形。 講清楚之javascript原型 標簽: javascript javascript 中原形是一個比較難于理解的概念。javascript 權威指南在原形這一章也花了大量的篇幅進行介紹,也許你已經(jīng)讀過javascript 權威指南,或者已經(jīng)是讀第N篇了,然而這篇文章的目...
摘要:當談到語言與其他編程語言相比時,你可能會聽到一些令人困惑東西,其中之一是工廠函數(shù)和構造函數(shù)。好的,讓我們用構造函數(shù)做同樣的實驗。當我們使用工廠函數(shù)創(chuàng)建對象時,它的指向,而當從構造函數(shù)創(chuàng)建對象時,它指向它的構造函數(shù)原型對象。 showImg(https://segmentfault.com/img/bVbr58T?w=1600&h=900); 當談到JavaScript語言與其他編程語言...
摘要:我們已經(jīng)回答了的構造函數(shù)和原型都是誰的問題,現(xiàn)在牽扯出來一個,我們繼續(xù)檢查的構造函數(shù)是全局對象上屬性叫的對象的原型是個匿名函數(shù),按照關于構造函數(shù)的約定,它應該是構造函數(shù)的屬性我們給這個對象起個名字,叫。 我不確定JavaScript語言是否應該被稱為Object-Oriented,因為Object Oriented是一組語言特性、編程模式、和設計與工程方法的籠統(tǒng)稱謂,沒有一個詳盡和大家...
閱讀 1572·2021-11-25 09:43
閱讀 2476·2019-08-30 15:54
閱讀 2938·2019-08-30 15:53
閱讀 1087·2019-08-30 15:53
閱讀 747·2019-08-30 15:52
閱讀 2538·2019-08-26 13:36
閱讀 807·2019-08-26 12:16
閱讀 1210·2019-08-26 12:13