通过调用标识符确定this
阿弥陀佛
纲
- this代表函数执行时的环境,只能是在函数执行时才被确实的
- 不应该在函数没有执行时去关注this;因为此时函数根本没有执行,代表执行环境的this更是未知数
- 确定JS函数的this,只在该函数执行时
在函数执行时,确定this值
- 未使用绑定字:是否通过对象的方法来引用
- 是:this就指向该对象
- 否:宽松模式是window;严格模式是undefined
- 使用绑定词
- this是该绑定的对象(如new、call、apply)
- 特殊绑定词
- bind:只是绑定this,但没有执行函数,所以this不确定
- 两种情况:一是在使用new执行时,this是new出来的对象,其它情况则是bing绑定的对象
- super:this是实例本身
- bind:只是绑定this,但没有执行函数,所以this不确定
未使用绑定字
以下为宽松模式下
-
以下fn均表示一個宽松环境的函数, obj表示一個对象
fn(); // window obj1.fn(); // obj1 obj2.obj3.fn() // obj3 (function f1(){})() fn.call(obj4) // obj4 new fn() // 实例函数
fn执行时,是否通过对象的方法来引用fn(): 否 =》this是windowobj1.fn(): 是,通过对象obj1的方法来引用 =》this是obj1obj2.obj3.fn(): 是,通过对象obj2的方法来引用 =》this是obj3立即执行函数f1:否 =》this是window
执行函数时未使用绑定词,通过否通过对象的方法来引用以确定this
-
// 伪代码: fn表示宽松模式的下的函数 const A = { fn: fn }; const B = { b1: A.fn, b2: A }; var c = objA.fn; fn(); // window A.fn(); // A B.b1() // B B.b2.fn(); // A c(); // window分析表
调用形式 是否通过对象的方法来引用 对象 this fn0()否 无 windowA.fn()是 AAB.b1()是 BBB.b2.fn()是 b2,b2的值是AAc()否 无 window -
var obj = { y: function fn1(x) { console.log(this); x > 1 && fn1(x - 1); }, z: function fn2(x) { console.log(this); x > 1 && obj.z(x - 1); }, }; obj.y(2); //obj 、 window obj.z(2); //obj 、 obj分析表
调用形式 是否通过对象的方法来引用 对象 this obj.y(1)是 objobjfn1(x - 1)否 无 windowobj.z(1)是 objobjobj.z(x-1)是 objobj -
函数没有执行,this就不确定
let A = { fn: function () { console.log(this); }, fn2: (function () { console.log(this); return fn; })() }; let B = {}; function fn3(cb) { console.log(this); // window B.fn = cb; cb(); // window B.fn(); // B } A.fn(); fn3(A.fn);分析表
调用形式 是否通过对象的方法来引用 对象 this A.fn()是 AAfn3(A.fn)否 无 windowcb()否 无 windowB.fn()是 BB -
函数的this,同样只能在其被调用时决定,不在于函数被赋值给谁
function fn() { console.log(this) }; Function.prototype.fn = fn let obj = {}; Function.prototype.f1 = function () { console.log(this); return function f2() { console.log(this); } } Function.prototype.fn(); // Function.prototype obj.f = fn.f1(); // fn obj.f(); // obj fn.f1()(); // fn、 window let f2 = fn.f1(); f2(); // window
使用绑定
四个可以绑定this关键词: new、call、apply、bing
-
call与apply- 执行并且指定一个对象作为
this的值 - 可使用
apply来展开一个数组
ES5:可传入类数组对象
- 执行并且指定一个对象作为
-
硬绑定
bing-- 两种情况- 在使用new执行时,this是new出来的对象
- bing绑定的对象
- 原理
function fakeBind(fn, obj) { return function () { return fn.apply(obj, arguments); }; }- 返回一个新函数
- 新函数与原函数的函数体相同
- 但其this被绑定到指定的对象
绑定到空/原始值
- 空对象:
Object.create(null),这是一个对象 - 绑定到
null / undefined- 宽松模式:window
- 严格模式:
null、undefined
- 绑定到原始值(字符串类型、布尔类型或者数字类型)会封装成对应的对象
let o = { a: function () { console.log(this); } }; o.a(); // o o.a.call(null); // window o.a.call(1); // Number(1)
其他
事件处理
-
标签事件:
- 事件触发函数执行,该函数的调用标识符决定
this - 内联事件中的this是该事件的元素本身
<button id="btn1" onclick="fn(this)">AMTB</button> <!-- window、 btn1-AMTF --> <button id="btn2" onclick="obj.fn(this)">JLSJ</button> <!-- obj、 btn2-JLSJ -->function fn(v) { console.log(this, v); } let obj = { fn }; document.getElementById("btn1").onclick = fn // btn1 btn.addEventListener('click', fn); // btn1 - 事件触发函数执行,该函数的调用标识符决定
-
IE的
attachEvent的回调函数的this是window- 修改this:把函数赋值给对象,再执行这个对象的方法
function attachEvent (elm, event, cb) { elm.attachEvent(("on" + event), function () { elm.cb = cb; elm.cb(window.event); delete elm.cb; }); } -
事件监听
addEventListener、onclick之类:其this所属对象是元素本身 -
内联样式的中的
this:元素本身 -<button onclick="fn(this)" >AMTB</button>
自带绑定
- 如在浏览器方法中的定时器, 回调函数
this是window对象
function fo() {
'use strict'
console.log(this);
}
var obj = { fo: fo }
obj.fo(); // obj
setTimeout(obj.fo, 100); // window
setTimeout(fo, 100); // window
- 其他
- getter 与 setter函数同理
- 实例中继承的方法同理
class语法的super调用的方法中的thissuper是静态的,指向当前类的基类- 但是
super调用方法时,进行了绑定
把this绑定到当前实例
- 数组的forEach、map等等可以指定this
箭头函数
- 箭头函数没有this值,也无法使用绑定关键词修改
this - 通过引用其上属函数的
this- 若该箭头函数没有上属函数,则其this值为undefined
- 若上属函数是箭头函数,
- 该上属函数会引用它的上属函数
- 该上属函数所引用的
this作为箭头函数的this
- 唯一修改this值:给他套上普通函数,再修改该普通函数的this
由于function x() { return (a) => { //this 取自 x函数执行时的this console.log(this.a); }; } var oA = { a: 2 }; var oB = { a: 3 }; var y = x.call(oA); y.call(oB); // 2x的this绑定到oA
箭头函数的this指向oA: y的this也指向oA
例子
- 在一个函数中返回另一个函数
function f1() {
console.log(this);
return function f2() {
console.log(this);
}
}
f1()();
函数f1返回的函数的this值,由调用时决定
`f1( )( )·`:两次`this`都是指向了`window`
f2执行时,如立即执行函数
-
反柯里化:
- 普通写法
Function.prototype.uncurrying = function () { var self = this; return function () { let thisArg = [].shift.call(arguments); return self.apply(thisArg, arguments); } } - 箭頭函数写法
Function.prototype.uncurrying = function uncurrying() { return (...args) => this.call( ...args) }- 箭头函数的this是取值其外层函数的this,
- 外层函数
uncurrying的this值,决定于调用时的let push = Array.prototype.push.uncurrying();- 此时
uncurrying的调用者是push函数
则此时的this是指向push函数
- 此时
- 普通写法
-
bing的实现
-
工具函数
objectCreate = Object.create || function (proto) { var F = function () { }; F.prototype = proto; return new F(); } let slice = Array.prototype.slice.uncurrying(); let concat = Array.prototype.concat.uncurrying(); -
实现逻辑
Function.prototype.bind = function (thisArg) { if (typeof this !== "function") { throw new TypeError("被绑定的不是函数"); } var self = this; var baseArgs = slice(arguments, 1); var bind = function () { return self.apply( this instanceof self ? this : thisArg, concat(baseArgs, slice(arguments)) ); } bind.prototype = objectCreate(self.prototype); return bing; };
-
-
自定义绑定对象
例:修改例3的bind函数的返回值的apply的参数1
默认绑定:只当this指向全局对象或者undefined时,
把this绑定到默认的对象
return self.apply(
((!this || this === (window || global)) ?
thisArg :
this
),
concat(baseArg, slice(arguments))
);
- 多重
const obj1 = {
name: "obj1"
};
const obj2 = {
name: "obj2"
};
function f1() {
console.log(this);
}
function f2() {
f1.call(this);
}
const f3 = () => f2.call(this);
f2.call(obj1); // obj1
f3.call(obj2); // window
f2 .call(obj1 ):
f2的this被给到了obj1,所以f1.call(this)的this是obj1;使得f1的thisobj1
f3.call(obj2):
f3是箭头函数-- 其沒有所属的函数,所以f2.call(this)的this值 undefined
- 立即执行函数
-
未使用绑定时,永远是window/未定义
-
执行时使用绑定,是被绑定的对象
-
箭头函数,来自所属函数的
let o = { a: (function () { console.log(this); // window return function () { console.log(this); // 调用标识符决定 } })() }; (function (fn) { console.log(this); // o fn.call(this); // window (() => console.log(this))(); // o }).call(o, () => console.log(this));

浙公网安备 33010602011771号