摘要:深入淺出的理解問題的由來寫法一寫法二雖然和指向同一個函數,但是執行結果可能不一樣。該變量由運行環境提供。所以,就出現了,它的設計目的就是在函數體內部,指代函數當前的運行環境。
深入淺出this的理解 問題的由來
var obj = { foo: function(){} } var foo = obj.foo; // 寫法一 obj.foo(); // 寫法二 foo();
雖然obj.foo和foo指向同一個函數,但是執行結果可能不一樣。
var obj = { foo: function() { conosle.log(this.bar) }, bar: 2 }; var foo = obj.foo; var bar = 3; obj.foo(); // 2 foo(); // 3
這種差異的原因就是因為內部使用了this關鍵字,this指向的是函數運行的所在環境,對于obj.foo()來說,this執行obj,對于foo()來說,this指向window全局環境
this的原理 內存的數據結構JavaScript 語言之所以有this的設計,跟內存里面的數據結構有關系。
var obj = {foo: 5}
也就是或變量obj是一個地址,后面讀取obj.foo引擎先從obj拿到地址,然后再從該地址讀取原始對象,返回它的屬性值。
原始的對象以字典結構保存,每一個屬性名都對應一個屬性描述對象。舉例來說,上面例子的foo屬性,實際上是以下面的形式保存的。
函數這樣的結構是很清晰的,問題在于屬性的值可能是一個函數。
var obj = { foo: function () {} };
這時,引擎會將函數多帶帶保存在內存中,然后再將函數的地址賦值給foo屬性的value屬性。
由于函數是一個多帶帶的值,所以它可以在不同的環境(上下文)執行。
var f = function () {}; var obj = { f: f }; // 多帶帶執行 f() // obj 環境執行 obj.f()環境變量
var f = function () { console.log(x); };
上面代碼中,函數體里面使用了變量x。該變量由運行環境提供。
現在問題就來了,由于函數可以在不同的運行環境執行,所以需要有一種機制,能夠在函數體內部獲得當前的運行環境(context)。所以,this就出現了,它的設計目的就是在函數體內部,指代函數當前的運行環境。
var f = function () { console.log(this.x); } var x = 1; var obj = { f: f, x: 2, }; // 多帶帶執行 f() // 1 // obj 環境執行 obj.f() // 2
在obj環境執行,this.x指向obj.x。
函數f在全局環境執行,this.x指向全局環境的x。
回到我們最初的問題 obj.foo()是通過obj找到foo,所以就是在obj環境執行。一旦var foo = obj.foo,變量foo就直接指向函數本身,所以foo()就變成在全局環境執行。
阮一峰老師的 this原理
繼續我們的thisthis在js中一直是謎一樣的存在著,在面試中也是經常會被問道
this的指向在函數創建的時候是決定不了的,在調用的時候才能決定
全局范圍內
this; //在全局范圍內使用`this`,它將會指向全局對象 var name="zhoulujun"; function say(){ console.log(this.name) } say(); //zhoulujun
當執行 say函數的時候, JavaScript 會創建一個 Execute context (執行上下文),執行上下文中就包含了 say函數運行期所需要的所有信息。 Execute context 也有自己的 Scope chain, 當函數運行時, JavaScript 引擎會首先從用 say函數的作用域鏈來初始化執行上下文的作用域鏈。
函數調用
foo(); //this指向全局對象
方法調用*
test.foo(); //this指向test對象
調用構造函數*
new foo(); //函數與new一塊使用即構造函數,this指向新創建的對象
顯式的設置this*
function foo(a, b, c) {} var bar = {}; foo.apply(bar, [1, 2, 3]); //this被設置成bar foo.call(bar, 1, 2, 3); //this被設置成bar從函數調用理解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(); // 這里的調用環境是window // Window?{postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window,?…} // 111
實例2
如果一個函數中有this,這個函數中包含多個對象,盡管這個函數是被最外層的對象所調用,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
函數名.call(對象,arg1....argn) //功能: //1.調用函數 //2.將函數內部的this指向第一個參數的對象 //3.將第二個及以后所有的參數,作為實參傳遞給函數
apply主要用途是直接用數組傳參
函數名.apply(對象, 數組/偽數組); //功能: //1.調用函數 //2.將函數內部的this指向第一個參數的對象 //3.將第二個參數中的數組(偽數組)中的元素,拆解開依次的傳遞給函數作為實參 //案例求數組中最大值 var a=Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ); console.log(a);// 輸出:5
call應用(將偽數組轉為數組)
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可以做到類數組轉數組 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]"
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/96796.html
摘要:繼承繼承子類可以使用父類的所有功能,并且對這些功能進行擴展。類繼承父類父類添加共有方法子類繼承父類子類添加共有方法其中最核心的一句代碼是將原型指向了父類的原型對象。 繼承 繼承:子類可以使用父類的所有功能,并且對這些功能進行擴展。繼承的過程,就是從一般到特殊的過程。 類繼承 // 父類 var supperClass = function() { var id = 1; thi...
摘要:封裝常見的封裝類中的共有和私有執行結果如下原因是調用的時候,指向的其實是,因此沒有輸出解決辦法更改指向工廠函數也有對于程序員來說這三個關鍵字應該是很熟悉的哈,但是在中,并沒有類似于這樣的關鍵字,但是我們又希望我們定義的屬性和方法有一定的訪問 封裝 常見的封裝 function Person (name,age,sex){ this.name = name; this.a...
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:,開始我們的第一篇單一職責。通過解耦可以讓每個職責工更加有彈性地變化。關于本文本文轉自大叔的深入理解系列。深入理解系列文章,包括了原創,翻譯,轉載,整理等各類型文章,原文是大叔的一個非常不錯的專題,現將其重新整理發布。 前言 Bob大叔提出并發揚了S.O.L.I.D五大原則,用來更好地進行面向對象編程,五大原則分別是: The Single Responsibility Princi...
閱讀 3212·2023-04-26 01:30
閱讀 675·2021-11-08 13:15
閱讀 1796·2021-09-24 10:35
閱讀 1009·2021-09-22 15:41
閱讀 1934·2019-08-30 15:44
閱讀 603·2019-08-30 13:22
閱讀 1013·2019-08-30 13:06
閱讀 1203·2019-08-29 13:22