// 示例一: var name = "windowsName"; function a() { var name = "Cherry"; console.log(this) // window console.log(this.name); // windowsName console.log("inner:" + this); // inner: Window } a(); // 至關於 window.a() console.log("outer:" + this) // outer:Window // 示例二: var name = "windowsName"; var a = { name: "Cherry", fn : function () { console.log(this) // a console.log(this.name); // Cherry } } window.a.fn(); // 至關於 a.fn() // 示例三: var name = "windowsName"; var a = { name: "Cherry", fn : function () { console.log(this) // window console.log(this.name); // windowsName } } var f = a.fn; f(); // 至關於 window.f() // 示例四: var name = "windowsName"; function fn() { var name = 'Cherry'; console.log(this) // window console.log(this.name); // windowsName innerFunction(); } function innerFunction () { console.log(this.name); // windowsName } fn() // 至關於 window.fn()
匿名函數的 this 永遠指向 window
注意,這裏咱們沒有使用嚴格模式,若是使用嚴格模式的話,全局對象就是 undefined,會報錯 Uncaught TypeError: Cannot read property 'name' of undefined。javascript
var name = "windowsName"; var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { console.log(this) // a setTimeout(function () {// 匿名函數的 this 永遠指向 window console.log(this) //window this.func1() },100); } }; a.func2() // this.func1 is not a function
1.箭頭函數的 this 始終指向函數定義時的 this,而非執行時。
箭頭函數中沒有 this 綁定,必須經過查找做用域鏈來決定其值,若是箭頭函數被非箭頭函數包含,則 this 綁定的是最近一層非箭頭函數的 this,不然,this 爲 undefinedjava
var name = "windowsName"; var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { setTimeout( () => { console.log(this) // a, 不是window this.func1() },100); } }; a.func2() // Cherry
2.在函數內部使用 _this = this。先將調用這個函數的對象保存在變量 _this 中,而後在函數中都使用這個 _this,這樣 _this 就不會改變windows
var name = "windowsName"; var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { var _this = this; setTimeout( function() { _this.func1() },100); } }; a.func2() // Cherry
3.使用 apply、call、bind 函數也是能夠改變 this 的指向。
3.1 apply
語法:fun.apply(thisArg[, argsArray])
含義:該方法調用一個函數, 使用該函數(fun)的方法,同時改變函數中this的指向爲thisArg。
參數:具備一個指定的this值,以及做爲一個數組(或相似數組的對象)提供的參數
thisArg:在 fun 函數運行時指定的 this 值。注意:指定的 this 值並不必定是該函數執行時真正的 this 值,若是這個函數處於非嚴格模式下,則指定爲 null 或 undefined 時會自動指向全局對象(瀏覽器中就是window對象),同時值爲原始值(數字,字符串,布爾值)的 this 會指向該原始值的自動包裝對象。
argsArray:一個數組或者類數組對象,其中的數組元素將做爲單獨的參數傳給 fun 函數。若是該參數的值爲null 或 undefined,則表示不須要傳入任何參數。從ECMAScript 5 開始可使用類數組對象。數組
var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { setTimeout( function () { this.func1() }.apply(a),100); // 此處省略第二個參數 } }; a.func2() // Cherry
3.2 call
語法:fun.call(thisArg[, arg1, arg2,....])
注:與apply用法相似,不一樣之處:第二個參數爲參數列表,使用逗號分割瀏覽器
var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { setTimeout( function () { this.func1() }.call(a),100); // 此處省略第二個參數 } }; a.func2() // Cherry
3.3 bind
語法:fun.bind(thisArg[, arg1, arg2, ...])()
含義:bind()方法建立一個新的函數, 當被調用時,將其this關鍵字設置爲提供的值,在調用新函數時,在任何提供以前提供一個給定的參數序列app
// 示例一: var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { setTimeout( function () { this.func1() }.bind(a)(),100); } }; a.func2() // Cherry // 示例二: var a ={ name : "Cherry", fn : function (a,b) { console.log( a + b) } } var b = a.fn; b.bind(a,1,2)() // 3
對於不支持 bind 的瀏覽器,兼容性寫法:函數
Function.prototype.bind = Function.prototype.bind || function(context) { var self = this; // console.log(this, context) return function() { console.log(arguments); // console [3,4] if ie<6-8> return self.apply(context, arguments); } } // 調用 var obj = { a: 1, b: 2, getCount: function(c, d) { return this.a + this.b + c + d; } }; window.a = window.b = 0; var func = obj.getCount.bind(obj)(3, 4); var apply = obj.getCount.apply(obj, [3, 4]); var call = obj.getCount.call(obj, 3, 4); console.log(func, apply, call) // 10 // 或者: Function.prototype.bind = Function.prototype.bind || function( context ){ var self = this; // 保存原函數 - 調用者 context = [].shift.call( arguments ), // 須要綁定的 this 上下文 args = [].slice.call( arguments ); 剩餘的參數轉化爲數組 return function(){ // 返回一個新的函數 return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) ); // 執行新的函數的時候,會把以前傳入context看成新函數體內的this // 而且組合兩次分別傳入的參數,做爲新的函數的參數 } }; // 調用 var obj = { name: 'sven' }; var func = function( a, b, c, d ){ alert ( this.name ); // sven alert ( [ a, b, c, d ] ) // [ 1, 2, 3, 4 ] }.bind( obj, 1, 2 ); // obj ==> context func( 3, 4 );
4.構造函數Sum,若是咱們直接調用這個構造函數Sum(),那麼這個this表明window對象;可是咱們對它進行實例化var obj = new Sum(),這樣this.a上的this表明當前對象obj;this
function Sum(a, b){ console.log(this); // 1=>window; 2=>實例化對象obj this.a = a; this.b = b; this.add = function(){ console.log(this) // obj.add()=>實例化對象obj return this.a+this.b; } } // 1.直接調用: Sum(2, 3); console.log(a, b); // 2, 3 // 2.實例化: var obj = new Sum(2, 3); var num = obj.add(); console.log(num); // 5
new 的過程:prototype
function Person(name,age){ this.name = name this.age = age return [1,2,3] } var p = new Person('taurus_wood', 20) // [1, 2, 3] // 數組的類型是對象 function Person2(name,age){ this.name = name this.age = age return 1 } var p2 = new Person2('taurus_wood', 20) // {name:'taurus_wood', age: 20}
代碼顯示實例化過程code
var a = new myFunction("Li","Cherry"); // 僞代碼表示: new myFunction{ var obj = {}; obj.__proto__ = myFunction.prototype; //創建了obj對象的原型鏈:obj->Animal.prototype->Object.prototype->null var result = myFunction.call(obj,"Li","Cherry"); return typeof result === 'obj'? result : obj; } // 或者: Function.method('new', function() { // this指向Function對象 // that是構造器對象 var that = Object.create(this.prototype); // other是調用構造器以後生成的對象,跟這行代碼一個意思: var other = new Person() var other = this.apply(that, arguments); // 若是它返回的不一個對象,就返回該新對象 return (typeof other === 'object' && other) || that; })
1.單純的函數調用
// 如上例: var name = "windowsName"; function a() { var name = "Cherry"; console.log(this.name); // windowsName console.log("inner:" + this); // inner: Window } a(); // 單純的函數調用 console.log("outer:" + this) // outer: Window
2.函數做爲對象的方法調用‘
// 如上例: var a = { name : "Cherry", func1: function () { console.log(this.name) }, func2: function () { setTimeout( function () { this.func1() }.bind(a)(),100); } }; a.func2() // Cherry 做爲a對象的方法調用
3.使用構造函數調用函數 如上例 4.做爲函數方法調用函數(call、apply) 在 JavaScript 中, 函數是對象。 JavaScript 函數有它的屬性和方法。 call() 和 apply() 是預約義的函數方法。 兩個方法可用於調用函數,兩個方法的第一個參數必須是對象自己