摘要:深入淺出的理解問題的由來寫法一寫法二雖然和指向同一個函數(shù),但是執(zhí)行結(jié)果可能不一樣。該變量由運行環(huán)境提供。所以,就出現(xiàn)了,它的設計目的就是在函數(shù)體內(nèi)部,指代函數(shù)當前的運行環(huán)境。
深入淺出this的理解 問題的由來
var obj = { foo: function(){} } var foo = obj.foo; // 寫法一 obj.foo(); // 寫法二 foo();
雖然obj.foo和foo指向同一個函數(shù),但是執(zhí)行結(jié)果可能不一樣。
var obj = { foo: function() { conosle.log(this.bar) }, bar: 2 }; var foo = obj.foo; var bar = 3; obj.foo(); // 2 foo(); // 3
這種差異的原因就是因為內(nèi)部使用了this關鍵字,this指向的是函數(shù)運行的所在環(huán)境,對于obj.foo()來說,this執(zhí)行obj,對于foo()來說,this指向window全局環(huán)境
this的原理 內(nèi)存的數(shù)據(jù)結(jié)構JavaScript 語言之所以有this的設計,跟內(nèi)存里面的數(shù)據(jù)結(jié)構有關系。
var obj = {foo: 5}
也就是或變量obj是一個地址,后面讀取obj.foo引擎先從obj拿到地址,然后再從該地址讀取原始對象,返回它的屬性值。
原始的對象以字典結(jié)構保存,每一個屬性名都對應一個屬性描述對象。舉例來說,上面例子的foo屬性,實際上是以下面的形式保存的。
函數(shù)這樣的結(jié)構是很清晰的,問題在于屬性的值可能是一個函數(shù)。
var obj = { foo: function () {} };
這時,引擎會將函數(shù)多帶帶保存在內(nèi)存中,然后再將函數(shù)的地址賦值給foo屬性的value屬性。
由于函數(shù)是一個多帶帶的值,所以它可以在不同的環(huán)境(上下文)執(zhí)行。
var f = function () {}; var obj = { f: f }; // 多帶帶執(zhí)行 f() // obj 環(huán)境執(zhí)行 obj.f()環(huán)境變量
var f = function () { console.log(x); };
上面代碼中,函數(shù)體里面使用了變量x。該變量由運行環(huán)境提供。
現(xiàn)在問題就來了,由于函數(shù)可以在不同的運行環(huán)境執(zhí)行,所以需要有一種機制,能夠在函數(shù)體內(nèi)部獲得當前的運行環(huán)境(context)。所以,this就出現(xiàn)了,它的設計目的就是在函數(shù)體內(nèi)部,指代函數(shù)當前的運行環(huán)境。
var f = function () { console.log(this.x); } var x = 1; var obj = { f: f, x: 2, }; // 多帶帶執(zhí)行 f() // 1 // obj 環(huán)境執(zhí)行 obj.f() // 2
在obj環(huán)境執(zhí)行,this.x指向obj.x。
函數(shù)f在全局環(huán)境執(zhí)行,this.x指向全局環(huán)境的x。
回到我們最初的問題 obj.foo()是通過obj找到foo,所以就是在obj環(huán)境執(zhí)行。一旦var foo = obj.foo,變量foo就直接指向函數(shù)本身,所以foo()就變成在全局環(huán)境執(zhí)行。
阮一峰老師的 this原理
繼續(xù)我們的thisthis在js中一直是謎一樣的存在著,在面試中也是經(jīng)常會被問道
this的指向在函數(shù)創(chuàng)建的時候是決定不了的,在調(diào)用的時候才能決定
全局范圍內(nèi)
this; //在全局范圍內(nèi)使用`this`,它將會指向全局對象 var name="zhoulujun"; function say(){ console.log(this.name) } say(); //zhoulujun
當執(zhí)行 say函數(shù)的時候, JavaScript 會創(chuàng)建一個 Execute context (執(zhí)行上下文),執(zhí)行上下文中就包含了 say函數(shù)運行期所需要的所有信息。 Execute context 也有自己的 Scope chain, 當函數(shù)運行時, JavaScript 引擎會首先從用 say函數(shù)的作用域鏈來初始化執(zhí)行上下文的作用域鏈。
函數(shù)調(diào)用
foo(); //this指向全局對象
方法調(diào)用*
test.foo(); //this指向test對象
調(diào)用構造函數(shù)*
new foo(); //函數(shù)與new一塊使用即構造函數(shù),this指向新創(chuàng)建的對象
顯式的設置this*
function foo(a, b, c) {} var bar = {}; foo.apply(bar, [1, 2, 3]); //this被設置成bar foo.call(bar, 1, 2, 3); //this被設置成bar從函數(shù)調(diào)用理解this
實例1
myObj3={ site:"zhoulujun.cn", andy:{ site:"www.zhoulujun.cn", fn:function(){ console.log(this) console.log(this.site) } } }; var site="111"; var fn=myObj3.andy.fn; fn(); // 這里的調(diào)用環(huán)境是window // Window?{postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window,?…} // 111
實例2
如果一個函數(shù)中有this,這個函數(shù)中包含多個對象,盡管這個函數(shù)是被最外層的對象所調(diào)用,this指向的也只是它上一級的對象
myObj3={ site:"zhoulujun.cn", andy:{ site:"www.zhoulujun.cn", fn:function(){ console.log(this) console.log(this.site) } } }; var site="111"; myObj3.andy.fn(); VM51:6 {site: "www.zhoulujun.cn", fn: ?} VM51:7 www.zhoulujun.cn
實例3
document.getElementById( "div1" ).onclick = function(){ console.log( this.id );// 輸出: div1 var func = function(){ console.log ( this.id );// 輸出: undefined } func(); }; //修正后 document.getElementById( "div1" ).onclick = function(){ var func = function(){ console.log ( this.id );// 輸出: div1 } func.call(this); };
實例4
var A = function( name ){ this.name = name; }; var B = function(){ A.apply(this,arguments); }; B.prototype.getName = function(){ return this.name; }; var b=new B("sven"); console.log( b.getName() ); // 輸出: "sven"
實例5
function foo() { console.log( this.a ); } var obj1 = { a: 2, foo: foo }; var obj2 = { a: 3, foo: foo }; obj1.foo(); // 2 obj2.foo(); // 3 obj1.foo.call( obj2 ); // 3 obj2.foo.call( obj1 ); // 2apply、call
因為apply、call存在于Function.prototype中,所以每個方法都有這兩個屬性。
call
函數(shù)名.call(對象,arg1....argn) //功能: //1.調(diào)用函數(shù) //2.將函數(shù)內(nèi)部的this指向第一個參數(shù)的對象 //3.將第二個及以后所有的參數(shù),作為實參傳遞給函數(shù)
apply主要用途是直接用數(shù)組傳參
函數(shù)名.apply(對象, 數(shù)組/偽數(shù)組); //功能: //1.調(diào)用函數(shù) //2.將函數(shù)內(nèi)部的this指向第一個參數(shù)的對象 //3.將第二個參數(shù)中的數(shù)組(偽數(shù)組)中的元素,拆解開依次的傳遞給函數(shù)作為實參 //案例求數(shù)組中最大值 var a=Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ); console.log(a);// 輸出:5
call應用(將偽數(shù)組轉(zhuǎn)為數(shù)組)
var arrayLike = {0: "name", 1: "age", 2: "sex", length: 3 } Array.prototype.join.call(arrayLike, "&"); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice可以做到類數(shù)組轉(zhuǎn)數(shù)組 Array.prototype.map.call(arrayLike, function(item){ return item.toUpperCase(); }); // ["NAME", "AGE", "SEX"] console.log( Object.prototype.toString.call(num), Object.prototype.toString.call(str), Object.prototype.toString.call(bool), Object.prototype.toString.call(arr), Object.prototype.toString.call(json), Object.prototype.toString.call(func), Object.prototype.toString.call(und), Object.prototype.toString.call(nul), Object.prototype.toString.call(date), Object.prototype.toString.call(reg), Object.prototype.toString.call(error) ); // "[object Number]" "[object String]" "[object Boolean]" "[object Array]" "[object Object]" // "[object Function]" "[object Undefined]" "[object Null]" "[object Date]" "[object RegExp]" "[object Error]"
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/96796.html
摘要:繼承繼承子類可以使用父類的所有功能,并且對這些功能進行擴展。類繼承父類父類添加共有方法子類繼承父類子類添加共有方法其中最核心的一句代碼是將原型指向了父類的原型對象。 繼承 繼承:子類可以使用父類的所有功能,并且對這些功能進行擴展。繼承的過程,就是從一般到特殊的過程。 類繼承 // 父類 var supperClass = function() { var id = 1; thi...
摘要:封裝常見的封裝類中的共有和私有執(zhí)行結(jié)果如下原因是調(diào)用的時候,指向的其實是,因此沒有輸出解決辦法更改指向工廠函數(shù)也有對于程序員來說這三個關鍵字應該是很熟悉的哈,但是在中,并沒有類似于這樣的關鍵字,但是我們又希望我們定義的屬性和方法有一定的訪問 封裝 常見的封裝 function Person (name,age,sex){ this.name = name; this.a...
摘要:理解的函數(shù)基礎要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統(tǒng)的類繼承還要強大。中文指南基本操作指南二繼續(xù)熟悉的幾對方法,包括,,。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權,非商業(yè)轉(zhuǎn)載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:,開始我們的第一篇單一職責。通過解耦可以讓每個職責工更加有彈性地變化。關于本文本文轉(zhuǎn)自大叔的深入理解系列。深入理解系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現(xiàn)將其重新整理發(fā)布。 前言 Bob大叔提出并發(fā)揚了S.O.L.I.D五大原則,用來更好地進行面向?qū)ο缶幊蹋宕笤瓌t分別是: The Single Responsibility Princi...
閱讀 3198·2023-04-26 01:30
閱讀 665·2021-11-08 13:15
閱讀 1774·2021-09-24 10:35
閱讀 998·2021-09-22 15:41
閱讀 1929·2019-08-30 15:44
閱讀 593·2019-08-30 13:22
閱讀 1004·2019-08-30 13:06
閱讀 1197·2019-08-29 13:22