国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

重讀javascript之Function

txgcwm / 3283人閱讀

摘要:函數用于指定對象的行為。命名函數的賦值表達式另外一個特殊的情況是將命名函數賦值給一個變量。這是由于的命名處理所致,函數名在函數內總是可見的。該方法返回一個表示當前函數源代碼的字符串。

函數包含一組語句,它們是JavaScript的基礎模塊單元,用于代碼的復用、信息隱藏和組合調用。函數用于指定對象的行為。一般來說,所謂編程,就是將一組需求分解成函數與數據結構的技能。

JavaScript中函數被作為“一等公民”,函數也屬于對象,不同的是只有函數可以被調用。

函數聲明與表達式 函數聲明
function foo() {}

上面的方法會在執行前被 解析(hoisted),因此它存在于當前上下文的任意一個地方, 即使在函數定義體的上面被調用也是對的。

foo(); // 正常運行,因為foo在代碼運行前已經被創建
function foo() {}
函數賦值表達式
var foo = function() {};

這個例子把一個匿名的函數賦值給變量 foo。

foo; // "undefined"
foo(); // 出錯:TypeError
var foo = function() {};

由于 var 定義了一個聲明語句,對變量 foo 的解析是在代碼運行之前,因此 foo 變量在代碼運行時已經被定義過了。

但是由于賦值語句只在運行時執行,因此在相應代碼執行之前, foo 的值缺省為 undefined

命名函數的賦值表達式

另外一個特殊的情況是將命名函數賦值給一個變量。

var foo = function bar() {
    bar(); // 正常運行
}
bar(); // 出錯:ReferenceError

bar 函數聲明外是不可見的,這是因為我們已經把函數賦值給了 foo; 然而在 bar 內部依然可見。這是由于 JavaScript 的 命名處理 所致, 函數名在函數內總是可見的。[注意]:在IE8及IE8以下版本瀏覽器bar在外部也是可見的,是因為瀏覽器對命名函數賦值表達式進行了錯誤的解析, 解析成兩個函數 foo 和 bar.

函數的調用

調用一個函數會暫停當前函數的執行,傳遞控制權和參數給新的函數。除了聲明時定義的形式參數外,還傳遞兩個隱式的參數:this和arguments.this的值取決于調用模式(方法調用,函數調用,構造函數調用,apply調用)。當實際參數和形式參數不匹配時不會報錯,如果實際參數大于形式參數,多的值會忽略。如果實際參數小于形式參數,多的形式參數會設undefine.

方法調用
var Obj = {
    value: 0,
    increment: function(inc){
        this.value += typeof inc === "number" ? inc : 1; 
    }
};
Obj.increment();  // 1
Obj.increment(2); //3

方法可以使用this訪問自己所屬的對象,所以它能從對象中取值和對對象進行修改,this到對象的綁定發生在調用的時候。

函數調用
//給Obj加一個double方法
Obj.double = function(){
    var add = function(){
        var val = this.value;
        if(typeof val === "number"){
            this.value = val * 2;
        }
    }
    add();
}
Obj.double();

以上代碼達不到目的,因為以此模式調用時,this被綁定到了全局變量。這是語言設計上的一個錯誤,倘若語言設計正確,那么當內部函數被調用時,this應該綁定到外部函數的this變量。這個設計錯誤的后果就是方法不能利用內部函數來幫助它工作,因為內部函數的this被綁定了錯誤的值,所以不能共享該方法對對象的訪問權。幸運的是,有一個很容易的解決方案:如果該方法定義了一個變量并給他賦值this,那么內部函數就可以通過那個變量訪問到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();
構造函數調用

如果在一個函數前面帶上new 來調用,那么背地里將會創建一個連接到該函數的prototype成員的新對象,同時this會綁定到那個對象上。new前綴也改變了return語句的行為。

var Obj = function(val){
    this.value = val;
}
var myObj = new Obj();
Apply調用模式

apply方法讓我門構建一個參數數組傳遞給調用函數。它也允許選擇this的值。類似的還有call.

Object.prototype.toString.call({}); //"[object Object]"
屬性 prototype

Function.prototype 屬性存儲了構造函數的原型對象。可以使用該屬性實現繼承:

function Animal(name){
    this.name = name;
}
function Bird(){
}
bird.porototype = new Animal(); //bird的原型指向Animal的原型,繼承Animal的屬性。

這個屬性和對象的內部屬性[[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}});

以上實際是通過對象的內部屬性[[prototype]]實現繼承。

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

用構造函數實現繼承,構造函數的原型鏈如下圖:

arguments

function.arguments 已經被廢棄很多年了,現在推薦的做法是使用函數內部可用的 arguments 對象來訪問函數的實參。所以主要講述一下arguments的特性:arguments 是一個類數組對象。代表傳給一個function的參數列表。,arguments 對象是函數內部的本地變量;arguments 已經不再是函數的屬性了。arguments 對象并不是一個真正的Array。它類似于數組,但沒有數組所特有的屬性和方法,除了 length。例如,它沒有 pop 方法。不過可以將其轉換成數組。

length

length 屬性指明函數的形參個數。數量不包括剩余參數[ES6]。相比之下, arguments.length 是函數被調用時實際傳參的個數。

非標準屬性

name: name 屬性返回所屬函數的函數名。name 屬性返回一個函數的名稱, 如果是匿名函數, 則返回空字符串。

caller: 返回調用指定函數的函數。如果一個函數f是在全局作用域內被調用的,則f.caller為null,相反,如果一個函數是在另外一個函數作用域內被調用的,則f.caller指向調用它的那個函數。

displayName: 獲取函數的顯示名字。

方法 Function.prototype.bind()方法

bind()方法會創建一個新函數,稱為綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()方法的第一個參數作為 this,傳入 bind() 方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。

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

我們需要為回調函數的執行保持對 myObj 對象上下文的引用。 調用 that.specialFunction()讓我們能夠維持作用域上下文并且正確執行我們的函數。 然而使用 Function.prototype.bind() 可以有更加簡潔干凈的方式:

render: function () {
 
    this.getAsyncData(function () {
 
        this.specialFunction();
 
        this.anotherSpecialFunction();
 
    }.bind(this));
 
}
ecma-262規范:

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兼容舊瀏覽器的實現:

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;
  };
}

上述算法和實際的實現算法還有許多其他的不同。

Function.prototype.apply()

apply() 方法在指定 this 值和參數(參數以數組或類數組對象的形式存在)的情況下調用某個函數。

/* 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值和若干個指定的參數值的前提下調用某個函數或方法。該方法的作用和 apply() 方法類似,只有一個區別,就是call()方法接受的是若干個參數的列表,而apply()方法接受的是一個包含多個參數的數組。

Function.prototype.toString()

該 toString() 方法返回一個表示當前函數源代碼的字符串。Function 對象覆蓋了從 Object 繼承來的 Object.prototype.toString 方法。函數的 toString 方法會返回一個表示函數源代碼的字符串。具體來說,包括 function關鍵字,形參列表,大括號,以及函數體中的內容。

非標準方法

Function.prototype.isGenerator(): 斷一個函數是否是一個生成器.

Function.prototype.toSource(): 返回函數的源代碼的字符串表示。

閉包 作用域鏈

函數創建時,當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量。

函數執行時,會創建一個被稱為“運行期上下文”內部對象,運行期上下文定義了函數的執行環境。每個運行期上下文都有自己的作用域鏈,用于標識符的解析。當運行期上下文被創建時,它的作用域鏈會被初始化為當前運行函數的[[scope]]所包含的對象。

這些值按照它們出現在函數中的順序被復制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。[注:]內部函數的執行上下文中this指向全局變量,見方法調用。

閉包的概念

一個擁有許多變量和綁定了這些變量的環境的表達式(通常是一個函數)。可以讀取函數外部的變量,讓這些執行環境始終保持在內存中。

function test(){
    for(var i = 0; i < 10 ; i++){
        setTimeout(function(){
            console.log(i)
        }, 0);
    }
}
test(); // 10...10(10個)

以上函數原本想輸出0到9,結果輸出了10個10。原因是test()執行時會創建一個運行時期的上下文,而setTimeout內部的函數會放在for循環隊列之后,等到for循環執行完之后才開始執行。function(){console.log(i)}執行是首先會尋找函數內部的i標示符。此時找不到i,再尋找test中的i(閉包的概念:訪問函數外的變量,這些變量只有等到閉包不使用才會被銷毀),而此時的i值已經變為了10,所以十次執行都會輸出10。解決這個問題可以在作用域鏈上增加一個節點,保存i變量。

function test(){
    for(var i = 0; i < 10 ; i++){
        (function(li){
            setTimeout(function(){
                console.log(li)
            }, 0);
        })(i);
    }
}
test(); // 0...9(0到9)

通過增加一個變量保存每次執行需要輸出的i值,實現0到9的輸出。

閉包的運用

JavaScript在es6之前沒有模塊的概念,使用閉包和匿名自執行函數實現模塊化,使用閉包可以從外部放問函數內部的屬性:

(function (){
    //內部屬性
    var Number = 0;
    //方法
    var Utils = function(){};
    Util.porototype.display = function(){
        console.log(Number); //訪問函數外部的變量
    };
    //返回
    return Util;
})()

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

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

相關文章

  • 重讀《學習JavaScript數據結構與算法-第三版》-第2章 ECMAScript與TypeScr

    摘要:第二種接口的概念和面向對象編程相關接口視為一份合約,在合約里可以定義這份合約的類或接口的行為接口告訴類,它需要實現一個叫做的方法,并且該方法接收一個參數。 定場詩 八月中秋白露,路上行人凄涼; 小橋流水桂花香,日夜千思萬想。 心中不得寧靜,清早覽罷文章, 十年寒苦在書房,方顯才高志廣。 前言 洛伊安妮·格羅納女士所著的《學習JavaScript數據結構與算法》第三版于2019年的5月份...

    TZLLOG 評論0 收藏0
  • 重讀JavascriptObject

    摘要:對象是中最常的內置對象之一。為了節省內存,使用一個共享的構造器使用更安全的引用如果不是或,拋出一個異常。使創建的一個新的對象為,就和通過表達式創建一個新對象一樣,是標準內置的構造器名設置的內部屬性為。方法返回一個該對象的字符串表示。 Object 對象是Javascript中最常的內置對象之一。除了null 和 undefined,其他的所有的都可以轉換為對象。可以把對象看成含有鍵值一...

    Alex 評論0 收藏0
  • 重讀你不知道的JS (上) 第一節五章

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

    worldligang 評論0 收藏0
  • 重讀你不知道的JS (上) 第一節四章

    摘要:如果提升改變了代碼執行的順序,會造成非常嚴重的破壞。聲明本身會被提升,而包括函數表達式的賦值在內的賦值操作并不會提升。要注意避免重復聲明,特別是當普通的聲明和函數聲明混合在一起的時候,否則會引起很多危險的問題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Ja...

    chanjarster 評論0 收藏0
  • 重讀 JavaScript DOM 編程藝術(一)--DOM 的增刪改查

    摘要:在很久之前讀過編程藝術,現在重讀又有新的體會,遂記錄下。唯一沒有被其他元素包含的元素是元素,它是的根元素。是節點內的第一個子節點,所以將是一個值,應該寫成才能得到。操作操作無非是增刪改查,我們先看查和改。 在很久之前讀過JavaScript Dom 編程藝術,現在重讀又有新的體會,遂記錄下。 什么是DOM 對于這種英文縮寫,首先看它的英文全拼--Document Object Mode...

    songze 評論0 收藏0

發表評論

0條評論

txgcwm

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<