成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【2】this

Alex / 2648人閱讀

摘要:否則如果是或,則設(shè)綁定為全局對象。令為解釋執(zhí)行的結(jié)果。返回一個值類型的引用,其基值為且其引用名為,嚴格模式標記為。進入函數(shù)代碼,為,非嚴格模式下將賦值為全局對象。內(nèi)置函數(shù)如何使用的內(nèi)置函數(shù)修改是通過給的內(nèi)置方法傳遞來實現(xiàn)的。

this

說到this,需要明確三方面內(nèi)容:

this何時被賦值

this被賦了什么值

內(nèi)置函數(shù)如何使用this的

this何時被賦值 進入函數(shù)代碼

當(dāng)控制流根據(jù)一個函數(shù)對象 F、調(diào)用者提供的 thisArg 以及調(diào)用者提供的 argumentList,進入函數(shù)代碼的執(zhí)行環(huán)境時,執(zhí)行以下步驟:

如果函數(shù)代碼是嚴格模式下的代碼,設(shè) this 綁定 為 thisArg。

否則如果 thisArg 是 null 或 undefined ,則設(shè) this 綁定為全局對象。

……

以上信息來源:進入函數(shù)代碼

從上訴信息中可以知道

this 與調(diào)用者提供的 thisArg 密切相關(guān)

this 在嚴格模式下為 thisArg

this 在非嚴格模式下為 thisArg 或 全局對象

那么 thisArg 又是怎么來的呢?下面來看下函數(shù)調(diào)用過程:

函數(shù)調(diào)用

令 ref 為解釋執(zhí)行 MemberExpression 的結(jié)果。

令 func 為 GetValue(ref)。

令 argList 為解釋執(zhí)行 Arguments 的結(jié)果,產(chǎn)生參數(shù)值們的內(nèi)部列表(參見 11.2.4)。

如果 Type(func) 不是 Object,拋出一個 TypeError 異常。

如果 IsCallable(func) 為 false,拋出一個 TypeError 異常。

如果 Type(ref) 為 Reference,那么

如果 IsPropertyReference(ref) 為 true,

那么令 thisValue 為 GetBase(ref)。

否則,ref 的基值是一個環(huán)境記錄項。

令 thisValue 為調(diào)用 GetBase(ref) 的 ImplicitThisValue 具體方法的結(jié)果。

否則,Type(ref) 不是 Reference。

令 thisValue 為 undefined。

返回調(diào)用 func 的 [[Call]] 內(nèi)置方法的結(jié)果,傳入 thisValue 作為 this 值和列表 argList 作為參數(shù)列表。

以上信息來源:函數(shù)調(diào)用

從上訴信息中可以知道

thisArg 即 thisValue

thisValue 與 ref 的類型密切相關(guān)

如果 ref 的類型是 Reference(引用規(guī)范類型)

如果 ref 是屬性引用,通過 GetBase(ref)(返回引用值ref的基值部分) 獲取 thisValue

否則,通過 ImplicitThisValue 方法獲取 thisValue

否則,thisValue 為 undefined

那么,了解到這里可能有許多新的疑問,比如:

Reference 是怎樣的類型

ref 是怎么來的

ref 什么時候是 Reference,什么時候不是。

GetBase(ref) 和 ImplicitThisValue 是如何產(chǎn)生結(jié)果的

Reference 是怎樣的類型

首先先解釋下 Reference。

其實ES中的類型分為ECMAScript語言類型和規(guī)范類型

ECMAScript語言類型對應(yīng)的是程序員使用 ECMAScript 語言直接操作的值,如 Undefined、Null、Boolean、String、Number、Object等。
規(guī)范類型可用來描述 ECMAScript 表達式運算的中間結(jié)果,但這樣的值不能儲存為對象的屬性或 ECMAScript 語言的變量值。引用尤雨溪的解釋:

這里的 Reference 是一個 Specification Type,也就是 “只存在于規(guī)范里的抽象類型”。它們是為了更好地描述語言的底層行為邏輯才存在的,但并不存在于實際的 js 代碼中。
ref 是怎么來的

從上訴函數(shù)調(diào)用中可以知道,ref 是解釋執(zhí)行 MemberExpression 的結(jié)果。
下面詳細看下 MemberExpression 的解析過程:

產(chǎn)生式 CallExpression : MemberExpression Arguments 按照下面的過程執(zhí)行 :

令 baseReference 為解釋執(zhí)行 MemberExpression 的結(jié)果。

令 baseValue 為 GetValue(baseReference)。

令 propertyNameReference 為解釋執(zhí)行 Expression 的結(jié)果。

令 propertyNameValue 為 GetValue(propertyNameReference)。

調(diào)用 CheckObjectCoercible(baseValue)。

令 propertyNameString 為 ToString(propertyNameValue)。

如果正在執(zhí)行中的語法產(chǎn)生式包含在嚴格模式代碼當(dāng)中,令 strict 為 true,否則令 strict 為 false。

返回一個值類型的引用,其基值為 baseValue 且其引用名為 propertyNameString,嚴格模式標記為 strict。

從上訴信息中分析可以知道

解釋執(zhí)行 MemberExpression 的結(jié)果是一個引用規(guī)范類型(Reference)

這個引用規(guī)范類型包含三部分信息:

baseValue

propertyNameString

strict

thisValue 的值取決于 baseValue

baseValue 是調(diào)用 GetValue 獲得的。

GetValue 得到的基值是 undefined、Object、Boolean、String、Number、環(huán)境記錄項中的任意一個(詳見:引用規(guī)范類型),而不是引用規(guī)范類型。

GetValue 詳細過程見:GetValue
ref 什么時候是 Reference,什么時候不是 Reference

一般來說,ref 是MemberExpression解析的結(jié)果,都將是 Reference。
但是,如果 MemberExpression 是其函數(shù)表達式的一部分,則可能將改變最終解析結(jié)果的類型。
而改變解析結(jié)果類型的主要原因取決于是否調(diào)用了 GetValue 方法,如果調(diào)用了 GetValue ,函數(shù)中間值 ref 將是 Object 類型。

那么哪些表達式不使用 GetValue 呢?

標識符引用 : 標識符執(zhí)行的結(jié)果總是一個 Reference 類型的值。

群組表達式:本算法不在執(zhí)行 Expression 后使用 GetValue。這主要的目的是讓 delete 與 typeof 運算符可以作用在被括號括起來的表達式。

成員表達式

調(diào)用表達式

更多表達式詳見:表達式
GetBase(ref) 和 ImplicitThisValue 是如何產(chǎn)生結(jié)果的

GetBase:返回引用值ref的基值部分

ImplicitThisValue : 聲明式環(huán)境記錄項永遠將 undefined 作為其 ImplicitThisValue 返回。

this被賦了什么值

其實在 this何時被賦值 部分已經(jīng)介紹了 this被賦了什么值。下面總結(jié)三種賦值過程:

第一種this賦值過程:
var v = 1; 
var obj = {
    v: 2,
    fn: function(){
        console.log(this.v);
    }
}
obj.fn(); // 2
(obj.fn)(); // 2

調(diào)用表達式解析 obj.fn ,返回引用規(guī)范類型,baseValue 為 obj。

函數(shù)調(diào)用,由于 1 過程返回的為引用規(guī)范類型,且為屬性引用,調(diào)用 GetBase 將 baseValue (obj) 作為返回值,返回給 thisValue。

進入函數(shù)代碼,thisArg 為 obj,將其賦值給 this。

如果對步驟1中,baseValue 為 obj 有疑問,詳見屬性訪問, 產(chǎn)生式 MemberExpression : MemberExpression [ Expression ] 執(zhí)行過程。
相當(dāng)于有兩個過程:

解析obj,baseValue 為聲明式環(huán)境記錄項。

解析obj.fn,baseValue 為 obj。

第二種this賦值過程:
function foo(){
    console.log(this);
}
foo(); // Window

調(diào)用表達式解析 foo, 返回引用規(guī)范類型,baseValue 為聲明式環(huán)境記錄項(函數(shù)聲明時綁定)。

函數(shù)調(diào)用,由于 1 過程返回的為引用規(guī)范類型,且不為屬性引用,調(diào)用 ImplicitThisValue 方法,返回 undefined 。

進入函數(shù)代碼,thisArg 為 undefined,非嚴格模式下將 this 賦值為全局對象。

第三種this賦值過程:
var v = 1; 
var obj = {
    v: 2,
    fn: function(){
        console.log(this.v);
    }
}
var fn2 = obj.fn;
fn2(); // 1
(obj.fn, obj.fn)(); // 1

調(diào)用表達式解析 fn2,(obj.fn, obj.fn) ,由于賦值表達式、逗號表達式都使用了 GetValue 方法,返回函數(shù)(Object 類型)。

函數(shù)調(diào)用,由于 1 過程返回的不是引用規(guī)范類型,所以 thisValue 為 undefined`。

進入函數(shù)代碼,thisArg 為 undefined,非嚴格模式下將 this 賦值為全局對象。

內(nèi)置函數(shù)如何使用this的

內(nèi)置函數(shù)修改 this 是通過給 func 的 [[Call]] 內(nèi)置方法傳遞 thisArg 來實現(xiàn)的。

內(nèi)置方法

Function.prototype.apply (thisArg, argArray)

Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )

Function.prototype.bind (thisArg [, arg1 [, arg2, …] ] )

Array.prototype.every ( callbackfn [ , thisArg ] )

Array.prototype.some ( callbackfn [ , thisArg ] )

Array.prototype.forEach ( callbackfn [ , thisArg ] )

Array.prototype.map ( callbackfn [ , thisArg ] )

Array.prototype.filter ( callbackfn [ , thisArg ] )

new 運算符 使用內(nèi)置方法 [[Construct]] 實現(xiàn)this指定

內(nèi)置方法模擬實現(xiàn)

使用成員表達式模擬內(nèi)置方法[[Call]]的效果:

apply
Function.prototype.apply_ = function (context, arr) { 
    var context = Object(context) || window;
    var result;

    // 臨時記錄需要調(diào)用的function 
    context.fn = this;
      
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push("arr[" + i + "]");
        }
        // 使用成員表達式指定context.fn執(zhí)行時this為context 
        result = eval("context.fn(" + args + ")")
    }

    delete context.fn
    return result;
}
call
Function.prototype.call_ = function (context) {
    var context = context || window;
    context.fn = this;

    var args = [];
    // 獲取參數(shù)列表 
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push("arguments[" + i + "]");
    } 
    // 使用成員表達式指定context.fn執(zhí)行時this為context  
    var result = eval("context.fn(" + args +")");

    delete context.fn
    return result;
}  
bind
Function.prototype.bind_  = function (context) {
    // 記錄bind的函數(shù) 
    var self = this;
    var args = [];
    // 獲取綁定的參數(shù)列表 
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push("arguments[" + i + "]");
    } 

    // 創(chuàng)建新函數(shù) 
    var fbound = function () {
        // 獲取未綁定的參數(shù)列表 
        var bindArgs = Array.prototype.slice.call(arguments);
        // fbound被當(dāng)做構(gòu)造函數(shù)使用,this指向?qū)嵗?。否則,指向 context
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    } 
    // 維護原型關(guān)系   
    fbound.prototype = self.prototype || new Function().prototype ;
    return fbound;
}
參考文檔

【1】冴羽的深入理解系列

【2】ES5 Wiki

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102001.html

相關(guān)文章

  • canvas之轉(zhuǎn)盤抽獎

    摘要:最近工作中重構(gòu)了抽獎轉(zhuǎn)盤,給大家提供一個開發(fā)轉(zhuǎn)盤抽獎的思路需求轉(zhuǎn)盤根據(jù)獎品數(shù)量不同而有變化目錄結(jié)構(gòu)由于業(yè)務(wù)需要所以開發(fā)了兩個版本抽獎,和,不過部分只能替換圖片,沒有功能邏輯。 最近工作中重構(gòu)了抽獎轉(zhuǎn)盤,給大家提供一個開發(fā)轉(zhuǎn)盤抽獎的思路 需求 1、轉(zhuǎn)盤根據(jù)獎品數(shù)量不同而有變化 2、canvas 目錄結(jié)構(gòu) showImg(https://segmentfault.com/img/bVbwL...

    _ang 評論0 收藏0
  • 構(gòu)建二叉樹進行數(shù)值數(shù)組的去重及優(yōu)化

    摘要:構(gòu)建二叉樹進行數(shù)值數(shù)組的去重及優(yōu)化常見兩層循環(huán)實現(xiàn)數(shù)組去重構(gòu)建二叉樹實現(xiàn)去重僅適用于數(shù)值類型的數(shù)組將先前遍歷過的元素,構(gòu)建成二叉樹,樹中每個結(jié)點都滿足左子結(jié)點的值當(dāng)前結(jié)點的值右子結(jié)點的值這樣優(yōu)化了判斷元素是否之前出現(xiàn)過的過程若元素比當(dāng)前結(jié)點 構(gòu)建二叉樹進行數(shù)值數(shù)組的去重及優(yōu)化 常見兩層循環(huán)實現(xiàn)數(shù)組去重 let arr = [11, 12, 13, 9, 8, 7, 0, 1, 2, 2...

    sarva 評論0 收藏0
  • ionic 2+ 手勢解鎖界面

    摘要:手勢解鎖界面一些對安全要求比較高的少不了鎖屏頁面,而手勢解鎖對于用戶來說使用方便,對于程序員來說小有挑戰(zhàn),怎么有棄之不用的道理。 ionic 2+ 手勢解鎖界面 一些對安全要求比較高的app少不了鎖屏頁面,而手勢解鎖對于用戶來說使用方便,對于程序員來說小有挑戰(zhàn),怎么有棄之不用的道理。 效果圖 效果圖處理短,方便大家閱讀showImg(https://segmentfault.co...

    Hancock_Xu 評論0 收藏0
  • JS+canvas實現(xiàn)五子棋人機大戰(zhàn)

    摘要:五子棋人機大戰(zhàn)創(chuàng)建實例是否結(jié)束我電腦所有棋子已經(jīng)落下的棋子贏法總數(shù)所有贏法統(tǒng)計我的贏法統(tǒng)計電腦贏法統(tǒng)計初始化初始化生成棋盤棋盤初始化鼠標移動聚焦功能實現(xiàn)算法初始化落子功能實現(xiàn)生成棋盤初始化生成不是的倍數(shù)棋盤列初始化棋盤棋盤初始化畫棋盤畫 JS+canvas五子棋人機大戰(zhàn) 1. 創(chuàng)建實例 function Gobang () { this.over = false; // 是否結(jié)...

    sutaking 評論0 收藏0
  • js數(shù)據(jù)結(jié)構(gòu)-二叉樹(二叉堆)

    摘要:二叉樹二叉樹是一種樹形結(jié)構(gòu),它的特點是每個節(jié)點最多只有兩個分支節(jié)點,一棵二叉樹通常由根節(jié)點,分支節(jié)點,葉子節(jié)點組成。 二叉樹 二叉樹(Binary Tree)是一種樹形結(jié)構(gòu),它的特點是每個節(jié)點最多只有兩個分支節(jié)點,一棵二叉樹通常由根節(jié)點,分支節(jié)點,葉子節(jié)點組成。而每個分支節(jié)點也常常被稱作為一棵子樹。 showImg(https://segmentfault.com/img/bVbmEd...

    ningwang 評論0 收藏0

發(fā)表評論

0條評論

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