摘要:函數(shù)用于指定對象的行為。命名函數(shù)的賦值表達(dá)式另外一個特殊的情況是將命名函數(shù)賦值給一個變量。這是由于的命名處理所致,函數(shù)名在函數(shù)內(nèi)總是可見的。該方法返回一個表示當(dāng)前函數(shù)源代碼的字符串。
函數(shù)包含一組語句,它們是JavaScript的基礎(chǔ)模塊單元,用于代碼的復(fù)用、信息隱藏和組合調(diào)用。函數(shù)用于指定對象的行為。一般來說,所謂編程,就是將一組需求分解成函數(shù)與數(shù)據(jù)結(jié)構(gòu)的技能。
JavaScript中函數(shù)被作為“一等公民”,函數(shù)也屬于對象,不同的是只有函數(shù)可以被調(diào)用。
函數(shù)聲明與表達(dá)式 函數(shù)聲明function foo() {}
上面的方法會在執(zhí)行前被 解析(hoisted),因此它存在于當(dāng)前上下文的任意一個地方, 即使在函數(shù)定義體的上面被調(diào)用也是對的。
foo(); // 正常運(yùn)行,因?yàn)閒oo在代碼運(yùn)行前已經(jīng)被創(chuàng)建 function foo() {}函數(shù)賦值表達(dá)式
var foo = function() {};
這個例子把一個匿名的函數(shù)賦值給變量 foo。
foo; // "undefined" foo(); // 出錯:TypeError var foo = function() {};
由于 var 定義了一個聲明語句,對變量 foo 的解析是在代碼運(yùn)行之前,因此 foo 變量在代碼運(yùn)行時已經(jīng)被定義過了。
但是由于賦值語句只在運(yùn)行時執(zhí)行,因此在相應(yīng)代碼執(zhí)行之前, foo 的值缺省為 undefined。
命名函數(shù)的賦值表達(dá)式另外一個特殊的情況是將命名函數(shù)賦值給一個變量。
var foo = function bar() { bar(); // 正常運(yùn)行 } bar(); // 出錯:ReferenceError
bar 函數(shù)聲明外是不可見的,這是因?yàn)槲覀円呀?jīng)把函數(shù)賦值給了 foo; 然而在 bar 內(nèi)部依然可見。這是由于 JavaScript 的 命名處理 所致, 函數(shù)名在函數(shù)內(nèi)總是可見的。[注意]:在IE8及IE8以下版本瀏覽器bar在外部也是可見的,是因?yàn)闉g覽器對命名函數(shù)賦值表達(dá)式進(jìn)行了錯誤的解析, 解析成兩個函數(shù) foo 和 bar.
函數(shù)的調(diào)用調(diào)用一個函數(shù)會暫停當(dāng)前函數(shù)的執(zhí)行,傳遞控制權(quán)和參數(shù)給新的函數(shù)。除了聲明時定義的形式參數(shù)外,還傳遞兩個隱式的參數(shù):this和arguments.this的值取決于調(diào)用模式(方法調(diào)用,函數(shù)調(diào)用,構(gòu)造函數(shù)調(diào)用,apply調(diào)用)。當(dāng)實(shí)際參數(shù)和形式參數(shù)不匹配時不會報(bào)錯,如果實(shí)際參數(shù)大于形式參數(shù),多的值會忽略。如果實(shí)際參數(shù)小于形式參數(shù),多的形式參數(shù)會設(shè)undefine.
方法調(diào)用var Obj = { value: 0, increment: function(inc){ this.value += typeof inc === "number" ? inc : 1; } }; Obj.increment(); // 1 Obj.increment(2); //3
方法可以使用this訪問自己所屬的對象,所以它能從對象中取值和對對象進(jìn)行修改,this到對象的綁定發(fā)生在調(diào)用的時候。
函數(shù)調(diào)用//給Obj加一個double方法 Obj.double = function(){ var add = function(){ var val = this.value; if(typeof val === "number"){ this.value = val * 2; } } add(); } Obj.double();
以上代碼達(dá)不到目的,因?yàn)橐源四J秸{(diào)用時,this被綁定到了全局變量。這是語言設(shè)計(jì)上的一個錯誤,倘若語言設(shè)計(jì)正確,那么當(dāng)內(nèi)部函數(shù)被調(diào)用時,this應(yīng)該綁定到外部函數(shù)的this變量。這個設(shè)計(jì)錯誤的后果就是方法不能利用內(nèi)部函數(shù)來幫助它工作,因?yàn)閮?nèi)部函數(shù)的this被綁定了錯誤的值,所以不能共享該方法對對象的訪問權(quán)。幸運(yùn)的是,有一個很容易的解決方案:如果該方法定義了一個變量并給他賦值this,那么內(nèi)部函數(shù)就可以通過那個變量訪問到this. 按照約定,我們可以把那個變量命名that:
//給Obj加一個double方法 Obj.double = function(){ var that = this; var add = function(){ var val = that.value; if(typeof val === "number"){ that.value = val * 2; } } add(); } Obj.double();構(gòu)造函數(shù)調(diào)用
如果在一個函數(shù)前面帶上new 來調(diào)用,那么背地里將會創(chuàng)建一個連接到該函數(shù)的prototype成員的新對象,同時this會綁定到那個對象上。new前綴也改變了return語句的行為。
var Obj = function(val){ this.value = val; } var myObj = new Obj();Apply調(diào)用模式
apply方法讓我門構(gòu)建一個參數(shù)數(shù)組傳遞給調(diào)用函數(shù)。它也允許選擇this的值。類似的還有call.
Object.prototype.toString.call({}); //"[object Object]"屬性 prototype
Function.prototype 屬性存儲了構(gòu)造函數(shù)的原型對象。可以使用該屬性實(shí)現(xiàn)繼承:
function Animal(name){ this.name = name; } function Bird(){ } bird.porototype = new Animal(); //bird的原型指向Animal的原型,繼承Animal的屬性。
這個屬性和對象的內(nèi)部屬性[[prototype]]是有所不同的:
var a = { x: 10, calculate: function (z) { return this.x + this.y + z; } }; var b = Object.create(a, {y: {value: 20}}); var c = Object.create(a, {y: {value: 30}});
以上實(shí)際是通過對象的內(nèi)部屬性[[prototype]]實(shí)現(xiàn)繼承。
function Foo(y) { this.y = y; } Foo.prototype.x = 10; Foo.prototype.calculate = function (z) { return this.x + this.y + z; }; var b = new Foo(20); var c = new Foo(30);
用構(gòu)造函數(shù)實(shí)現(xiàn)繼承,構(gòu)造函數(shù)的原型鏈如下圖:
function.arguments 已經(jīng)被廢棄很多年了,現(xiàn)在推薦的做法是使用函數(shù)內(nèi)部可用的 arguments 對象來訪問函數(shù)的實(shí)參。所以主要講述一下arguments的特性:arguments 是一個類數(shù)組對象。代表傳給一個function的參數(shù)列表。,arguments 對象是函數(shù)內(nèi)部的本地變量;arguments 已經(jīng)不再是函數(shù)的屬性了。arguments 對象并不是一個真正的Array。它類似于數(shù)組,但沒有數(shù)組所特有的屬性和方法,除了 length。例如,它沒有 pop 方法。不過可以將其轉(zhuǎn)換成數(shù)組。
lengthlength 屬性指明函數(shù)的形參個數(shù)。數(shù)量不包括剩余參數(shù)[ES6]。相比之下, arguments.length 是函數(shù)被調(diào)用時實(shí)際傳參的個數(shù)。
非標(biāo)準(zhǔn)屬性name: name 屬性返回所屬函數(shù)的函數(shù)名。name 屬性返回一個函數(shù)的名稱, 如果是匿名函數(shù), 則返回空字符串。
caller: 返回調(diào)用指定函數(shù)的函數(shù)。如果一個函數(shù)f是在全局作用域內(nèi)被調(diào)用的,則f.caller為null,相反,如果一個函數(shù)是在另外一個函數(shù)作用域內(nèi)被調(diào)用的,則f.caller指向調(diào)用它的那個函數(shù)。
displayName: 獲取函數(shù)的顯示名字。
方法 Function.prototype.bind()方法bind()方法會創(chuàng)建一個新函數(shù),稱為綁定函數(shù),當(dāng)調(diào)用這個綁定函數(shù)時,綁定函數(shù)會以創(chuàng)建它時傳入 bind()方法的第一個參數(shù)作為 this,傳入 bind() 方法的第二個以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
example在下面的例子代碼中,我們可以名正言順地將上下文緩存到一個變量中:
var myObj = { specialFunction: function () { }, anotherSpecialFunction: function () { }, getAsyncData: function (cb) { cb(); }, render: function () { var that = this; this.getAsyncData(function () { that.specialFunction(); that.anotherSpecialFunction(); }); } }; myObj.render();
我們需要為回調(diào)函數(shù)的執(zhí)行保持對 myObj 對象上下文的引用。 調(diào)用 that.specialFunction()讓我們能夠維持作用域上下文并且正確執(zhí)行我們的函數(shù)。 然而使用 Function.prototype.bind() 可以有更加簡潔干凈的方式:
render: function () { this.getAsyncData(function () { this.specialFunction(); this.anotherSpecialFunction(); }.bind(this)); }ecma-262規(guī)范:
When the bind method is called with argument thisArg and zero or more args, it performs the following steps:
Let Target be the this value.
If IsCallable(Target) is false, throw a TypeError exception.
Let args be a new (possibly empty) List consisting of all of the argument values provided after thisArg in order.
Let F be BoundFunctionCreate(Target, thisArg, args).
ReturnIfAbrupt(F).
Let targetHasLength be HasOwnProperty(Target, "length").
ReturnIfAbrupt(targetHasLength).
If targetHasLength is true, then
Let targetLen be Get(Target, "length").
ReturnIfAbrupt(targetLen).
If Type(targetLen) is not Number, let L be 0.
Else,
Let targetLen be ToInteger(targetLen).
Let L be the larger of 0 and the result of targetLen minus the number of elements of args.
Else let L be 0.
Let status be DefinePropertyOrThrow(F, "length", PropertyDescriptor {[[Value]]: L, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).
Assert: status is not an abrupt completion.
Let targetName be Get(Target, "name").
ReturnIfAbrupt(targetName).
If Type(targetName) is not String, let targetName be the empty string.
Perform SetFunctionName(F, targetName, "bound").
Return F.
Function.prototype.bind 在IE8及以下的版本中不被支持,以下MDN兼容舊瀏覽器的實(shí)現(xiàn):
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }
上述算法和實(shí)際的實(shí)現(xiàn)算法還有許多其他的不同。
Function.prototype.apply()apply() 方法在指定 this 值和參數(shù)(參數(shù)以數(shù)組或類數(shù)組對象的形式存在)的情況下調(diào)用某個函數(shù)。
/* min/max number in an array */ var numbers = [5, 6, 2, 3, 7]; /* using Math.min/Math.max apply */ var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...) or Math.max(5, 6, ..) */ var min = Math.min.apply(null, numbers);Function.prototype.call()
call() 方法在使用一個指定的this值和若干個指定的參數(shù)值的前提下調(diào)用某個函數(shù)或方法。該方法的作用和 apply() 方法類似,只有一個區(qū)別,就是call()方法接受的是若干個參數(shù)的列表,而apply()方法接受的是一個包含多個參數(shù)的數(shù)組。
Function.prototype.toString()該 toString() 方法返回一個表示當(dāng)前函數(shù)源代碼的字符串。Function 對象覆蓋了從 Object 繼承來的 Object.prototype.toString 方法。函數(shù)的 toString 方法會返回一個表示函數(shù)源代碼的字符串。具體來說,包括 function關(guān)鍵字,形參列表,大括號,以及函數(shù)體中的內(nèi)容。
非標(biāo)準(zhǔn)方法Function.prototype.isGenerator(): 斷一個函數(shù)是否是一個生成器.
Function.prototype.toSource(): 返回函數(shù)的源代碼的字符串表示。
閉包 作用域鏈函數(shù)創(chuàng)建時,當(dāng)一個函數(shù)創(chuàng)建后,它的作用域鏈會被創(chuàng)建此函數(shù)的作用域中可訪問的數(shù)據(jù)對象填充。它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量。
函數(shù)執(zhí)行時,會創(chuàng)建一個被稱為“運(yùn)行期上下文”內(nèi)部對象,運(yùn)行期上下文定義了函數(shù)的執(zhí)行環(huán)境。每個運(yùn)行期上下文都有自己的作用域鏈,用于標(biāo)識符的解析。當(dāng)運(yùn)行期上下文被創(chuàng)建時,它的作用域鏈會被初始化為當(dāng)前運(yùn)行函數(shù)的[[scope]]所包含的對象。
這些值按照它們出現(xiàn)在函數(shù)中的順序被復(fù)制到運(yùn)行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數(shù)的所有局部變量、命名參數(shù)、參數(shù)集合以及this,然后此對象會被推入作用域鏈的前端,當(dāng)運(yùn)行期上下文被銷毀,活動對象也隨之銷毀。[注:]內(nèi)部函數(shù)的執(zhí)行上下文中this指向全局變量,見方法調(diào)用。
閉包的概念一個擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個函數(shù))。可以讀取函數(shù)外部的變量,讓這些執(zhí)行環(huán)境始終保持在內(nèi)存中。
function test(){ for(var i = 0; i < 10 ; i++){ setTimeout(function(){ console.log(i) }, 0); } } test(); // 10...10(10個)
以上函數(shù)原本想輸出0到9,結(jié)果輸出了10個10。原因是test()執(zhí)行時會創(chuàng)建一個運(yùn)行時期的上下文,而setTimeout內(nèi)部的函數(shù)會放在for循環(huán)隊(duì)列之后,等到for循環(huán)執(zhí)行完之后才開始執(zhí)行。function(){console.log(i)}執(zhí)行是首先會尋找函數(shù)內(nèi)部的i標(biāo)示符。此時找不到i,再尋找test中的i(閉包的概念:訪問函數(shù)外的變量,這些變量只有等到閉包不使用才會被銷毀),而此時的i值已經(jīng)變?yōu)榱?0,所以十次執(zhí)行都會輸出10。解決這個問題可以在作用域鏈上增加一個節(jié)點(diǎn),保存i變量。
function test(){ for(var i = 0; i < 10 ; i++){ (function(li){ setTimeout(function(){ console.log(li) }, 0); })(i); } } test(); // 0...9(0到9)
通過增加一個變量保存每次執(zhí)行需要輸出的i值,實(shí)現(xiàn)0到9的輸出。
閉包的運(yùn)用JavaScript在es6之前沒有模塊的概念,使用閉包和匿名自執(zhí)行函數(shù)實(shí)現(xiàn)模塊化,使用閉包可以從外部放問函數(shù)內(nèi)部的屬性:
(function (){ //內(nèi)部屬性 var Number = 0; //方法 var Utils = function(){}; Util.porototype.display = function(){ console.log(Number); //訪問函數(shù)外部的變量 }; //返回 return Util; })()
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/78418.html
摘要:第二種接口的概念和面向?qū)ο缶幊滔嚓P(guān)接口視為一份合約,在合約里可以定義這份合約的類或接口的行為接口告訴類,它需要實(shí)現(xiàn)一個叫做的方法,并且該方法接收一個參數(shù)。 定場詩 八月中秋白露,路上行人凄涼; 小橋流水桂花香,日夜千思萬想。 心中不得寧靜,清早覽罷文章, 十年寒苦在書房,方顯才高志廣。 前言 洛伊安妮·格羅納女士所著的《學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法》第三版于2019年的5月份...
摘要:對象是中最常的內(nèi)置對象之一。為了節(jié)省內(nèi)存,使用一個共享的構(gòu)造器使用更安全的引用如果不是或,拋出一個異常。使創(chuàng)建的一個新的對象為,就和通過表達(dá)式創(chuàng)建一個新對象一樣,是標(biāo)準(zhǔn)內(nèi)置的構(gòu)造器名設(shè)置的內(nèi)部屬性為。方法返回一個該對象的字符串表示。 Object 對象是Javascript中最常的內(nèi)置對象之一。除了null 和 undefined,其他的所有的都可以轉(zhuǎn)換為對象。可以把對象看成含有鍵值一...
摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會真的使用閉包。而上面的創(chuàng)建一個閉包,本質(zhì)上這是將一個塊轉(zhuǎn)換成一個可以被關(guān)閉的作用域。結(jié)合塊級作用域與閉包模塊這個模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復(fù)雜微妙技術(shù)的語言,即使是經(jīng)驗(yàn)豐富的 Jav...
摘要:如果提升改變了代碼執(zhí)行的順序,會造成非常嚴(yán)重的破壞。聲明本身會被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會提升。要注意避免重復(fù)聲明,特別是當(dāng)普通的聲明和函數(shù)聲明混合在一起的時候,否則會引起很多危險(xiǎn)的問題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復(fù)雜微妙技術(shù)的語言,即使是經(jīng)驗(yàn)豐富的 Ja...
摘要:在很久之前讀過編程藝術(shù),現(xiàn)在重讀又有新的體會,遂記錄下。唯一沒有被其他元素包含的元素是元素,它是的根元素。是節(jié)點(diǎn)內(nèi)的第一個子節(jié)點(diǎn),所以將是一個值,應(yīng)該寫成才能得到。操作操作無非是增刪改查,我們先看查和改。 在很久之前讀過JavaScript Dom 編程藝術(shù),現(xiàn)在重讀又有新的體會,遂記錄下。 什么是DOM 對于這種英文縮寫,首先看它的英文全拼--Document Object Mode...
閱讀 1648·2019-08-30 15:55
閱讀 973·2019-08-30 15:44
閱讀 866·2019-08-30 10:48
閱讀 2025·2019-08-29 13:42
閱讀 3179·2019-08-29 11:16
閱讀 1235·2019-08-29 11:09
閱讀 2053·2019-08-26 11:46
閱讀 611·2019-08-26 11:44