- 為什么要使用this
- this 的使用誤解 (
2 種 指向誤解) - this 和詞法作用域的比較
- this 的指向正解
- this 的綁定方法(
call()、apply()、bind())
this 總是返回一個對象( fun 也是一個對象 ) + this 指向總是善變的
this 的三篇文章按照順序復習
this基本概念 -> this綁定規(guī)則 -> this 應用實例
基本概念
this 總是返回一個對象 即包含當前屬性或者方法函數(shù)的對象, 因為對象的屬性和方法函數(shù)可以賦予另一個對象,所有 this 指向的對象也是善變的。
function foo () {
console.log('name :' + this.name);
}
var obj = { name: "obj1", foo: foo };
var obj2 = { name: "obj2", foo: foo };
var obj3 = { name: "obj3" };
obj.foo() // obj1
obj2.foo() // obj2
- 為什么 使用this
-
this 提供了一種優(yōu)雅的方式來
傳遞一個對象的引用, 使用 this 能夠得到更加 簡介的 api.顯式的傳遞對象的引用(eg: 函數(shù)參數(shù)傳遞) 使得代碼變得混亂和難以維護(eg: 傳遞參數(shù)的個數(shù)就是個問題)。
使用 this 可以
自動引用合適的上下文環(huán)境,并且確定this當前指代的對象進而使用其屬性和方法函數(shù)** 我們使用 this 的最終目的是保證能夠
正確 + 便捷的使用 對象的屬性和方法函數(shù)處理數(shù)據(jù) **
-
this 的使用誤解 ( this 的指向誤解 )
this 并不指向函數(shù)自身
-
this 不一定指向定義它的函數(shù)作用域或者定義時的作用域
function foo() { var a = 2; this.bar = function() { console.log(this.a) } this.bar(); } foo();
-
this 和詞法作用域的比較
this 可以通過
參數(shù)傳遞或者直接的對象引用來代替。** 但是 this 因為有其更加靈活的特性才被大家所使用,總是使用詞法作用域容易讓你 回到編程的舒適區(qū) **
我們來記錄 foo 函數(shù)被調(diào)用的次數(shù)
function foo(num) {
console.log('foo ' + num);
// 記錄 foo 函數(shù)被調(diào)用的次數(shù)
this.count++;
}
foo.count = 0;
for(var i = 0; i < 5; i++) {
foo(i);
}
// 記錄 foo 函數(shù)被調(diào)用的次數(shù)
console.log(foo.count);
分析一下上面的 輸出 的值 和 this 的指向?
若需要你來改造 你應該怎么辦??
-
this 的指向正解 ( 請看 this 的 四種綁定策略 )
函數(shù)內(nèi)部的this 總是指向 函數(shù)本身被調(diào)用的位置。(
this 綁定規(guī)則有詳解)所以對于 this 的 指向就是 尋找函數(shù)的調(diào)用位置為首。(瀏覽器自帶的 開發(fā)者工具可以很方便的查看函數(shù)調(diào)用棧)
this 的 三種
強制綁定的 方法詳解
** javascript 提供了 call apply 和 bind 三個方法,用于固定 this 的指向 **
** call 和 apply bind 都是定義在 Function 上面的方法。**
** call apply 返回一個調(diào)用函數(shù)的執(zhí)行結(jié)果。 **
** bind 返回一個修改了內(nèi)部this的 包裝函數(shù)。 **
-
call 的 傳參解析 ( 4 種傳參的方式 )
call 參數(shù)使用正常的對象
call 參數(shù)為空、null、undefined 則默認傳入全局對象
var n = 'bar'; var obj = {n: 'foo'} function baz() { console.log(this.n) } baz.call(obj); // foo baz.call(window); baz.call(); baz.call(null), baz.call(undefined);call 傳入一個基本類型的數(shù)據(jù),這個基本類型的數(shù)據(jù)會被轉(zhuǎn)為包裝對象 賦值給 this
var f = function () { console.log(this); }; f.call(5) // Number {[[PrimitiveValue]]: 5}call 可以傳遞多個參數(shù),第一個參數(shù)為需要綁定的對象,后面的參數(shù) 依次是函數(shù)調(diào)用的傳參參數(shù)
apply ( 接受一個數(shù)組作為函數(shù)執(zhí)行時的參數(shù) )
-
bind 將函數(shù)體內(nèi)部的 this 強制綁定,返回一個新的經(jīng)過包裝的函數(shù)
// 自己實現(xiàn)的簡單功能的 bind 函數(shù) function bind(fun, obj) { return function() { // 這個 就是 bind 返回的函數(shù) fn.apply(obj); } }
apply call bind 使用全攻略 ( 4種使用場景 )
-
傳遞空對象 ** 參數(shù)柯里化 **( 看你傳遞的對象到底有多空 )
call apply bind 傳遞一個空對象常常用于參數(shù)的柯里化
function bar(a, b) { console.log(a + ',' + b); }直接使用 null / undefined 作為空 傳入
var baz = bar.call(null, 1, 4) // 1, 4 var bak = bar.bind(null, 10); bar(19) // 10,19傳遞進去一個 真空對象 var ? = Object.create(null);
var baz = bar.call(?, 1, 4) // 1, 4 -
自定義的兩種 bind 方法
-
創(chuàng)建自定義的 bind 方法函數(shù)
function bindCopy(fn, obj) { return function() { fn.apply(obj, arguments); // 這里主要依賴 call 方法 ** 注意不能少了函數(shù)參數(shù) ** } } -
擴展函數(shù)方法庫(** 重要知識點 **)
Function.prototype.bindCopy() { var fn = this; var obj = arguments[0]; var args = Array.prototype.slice(arguments, 1); return function() { fn.apply(obj, args) } }重要知識點:
函數(shù)使用 prototype 可以進行擴展( Function.ptototype.bindCopy )
使用 apply 可以將 類數(shù)組對象( 有 length 屬性的對象 ) 進行參數(shù)結(jié)構(gòu)
函數(shù)自身調(diào)用時也是使用 this 表示調(diào)用的上下文
注意 原函數(shù)本身的 參數(shù)不能少
-
-
apply 和 call 的妙用
-
將數(shù)組解構(gòu) (上面是將類數(shù)組對象解構(gòu))
var arr = [1, 4, 6, 7]; Math.max.apply(null, arr); // 7 -
使用 call 方法用在 對象繼承中 重新調(diào)用被子類覆蓋的父類方法;
function Parent() { this.a = 'super'; this.Super = function() { console.log('父類的 Super 方法' + this. a); } } var p = new Parent(); function Children (a) { this.a = a; Parent.call(this); // 調(diào)用 父類的構(gòu)造函數(shù) } var c = new Children(12); c.Super() // 使用子類 繼承過來的方法 c.Super.call(p) // 使用 call 重新調(diào)用父對象的方法
試著自己實現(xiàn)一個類似 于 forEach 的 方法吧
-
.