作用:表示函数执行时的环境
值:一个对象
特点:动态性
函数的this在执行时才能确定
可作实参、返回值、数据赋值进行传递
1. 函数是复杂数据类型
2. 变量可获取函数值--引用地址
3. 函数调用时,该调用名字是该函数此次调用时的标识符
唯一能确定this的途径:函数的调用标识符
是:this就指向该对象
否:宽松模式是window;严格模式是未定义
在函数体内使用严格关键词
class方法与模块方法自动运行在严格模式中
不包括方法简写
// 伪代码 //以下fn均表示一個宽松环境的函数, obj表示一个对象 fn(); // window obj1.fn(); // obj1 obj2.obj3.fn() // obj3 fn.call(obj4) // obj4 new fn() // 实例
函数
fn
执行时,其调用标识符均是fn
每个标识符
fn
所属的对象都不同,其this
就不同
fn()
: 调用标识符fn不属于任何对象:this
是window
obj1.fn()
: 调用标识符fn属於对象obj1
的成员:
this
是obj1
obj2.obj3.fn()
: 调用标识符fn属於对象obj2
的成员:
this
是obj3
未使用绑定时,函数的调用标识符属于对象的一个成员时,其
this
就是该对象
确定 this 值 :
只要查看该函数调用时的标识符
该标识符决定当前函数执行时的this值
调用标识符是该函数本身的标识符
该标识符不属于任何对象的属性
此时this指向
宽松模式:全局对象
window、global(node环境)·
严格模式: this为未定义
立即执行函数也是函数自我调用,
其调用标识符是anonymou
其this,永远是window/未定义
函数的引用地址被赋值给一个对象的属性
函数调用时: 若调用标识符属于对象的一个成员
this就指向该对象
例:
1.函数作为数据进行赋值
// 伪代码: 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值
分析表
调用形式
调用标识符
标识符所属对象
this
fn0()
fn0
无
window
A.fn()
fn()
A
A
B.b1()
b1()
B
B
B.b2.fn()
fn()
b2
,b2
的值是A
A
c()
c()
无
window
2. 函数作为数据进行赋值
var obj = {
y: function fn1(x) {
console.log(this);
while (x) {
fn1(x - 1);
break;
}
},
z: function fn2(x) {
console.log(this);
while (x) {
obj.z(x - 1);
break;
}
},
};
obj.y(1); //obj 、 window"
obj.z(1); //obj 、window"
调用形式
调用标识符
标识符所属对象
this
obj.y(1)
y()
obj
obj
fn1(x - 1)
fn1()
无
window
obj.z(1)
z()
obj
obj
obj.z(x-1)
z()
obj
obj
3.函数作为参数传入
1.参数传递是一种隐式赋值
2.传参:类似于:
argument = A.fn ;
参数cb获取了函数fn的引用
// 伪代码: fn表示宽松模式的下的函数
let A = {
fn,
fn2: (function () {
console.log(this);
})()
},
B = {};
function b(cb) {
console.log(this); // window
B.fn = cb;
cb(); // window
B.fn(); // B
}
A.fn(); // A
b(fn);
调用形式
调用标识符
标识符所属对象
this
A.fn()
fn()
A
A
b(fn)
b()
无
window
cb()
cb()
无
window
B.fn()
fn()
B
B
3.参数所属对象要看情况
1.如在浏览器方法中的定时器
其回调函数参数是属于window
对象的成员
回调函数this
是window
对象
var obj = {
fo: function fo() {
'use strict'
console.log(this);
}
};
obj.fo(); // obj
setTimeout(obj.fo, 100); // window
2.如事件监听
其回调参数所属对象是元素本身
其他
function fn() { };
let obj = {};
Function.prototype.f1 = function () {
console.log(this);
return function f2() {
console.log(this);
}
}
Function.prototype.x(); // Function.prototype
Function.x() // Function
obj.f = fn.f1(); //fn
obj.f(); // obj
fn.f1()(); // window
let f2 = fn.f1();
f2(); // window
调用形式
调用标识符
标识符所属对象
this
Fn.proto.x()
x()
Fn.proto
Fn.proto
fn.f1()
f1()
fn
fn
f2的this,同样只能在其被调用时决定
不在于它被赋值给谁
调用形式
调用标识符
标识符所属对象
this
obj.f()
f()
obj
obj
fn.f1()()
匿名函数()
无
window
f2()
f2()
无
window
内联事件:
function fn(v) {
console.log(this, v); // window、 button-AMTF
}
let obj = { fn }; // obj、 button-JLSJ
document.getElementsByTagName("button")[0]
.onclick = function () {
console.log(this); // button-AMTF
}
外联事件与事件监听
btn.addEventListener('click', fn);
function fn(e) {
if (e.target == this) {
// 只在元素本身被觸發時執行
// doSomething...
console.log(e.target, this);
}
}
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;
});
}
// 或者使用绑定
function attachEvent(elm, event, cb) {
elm.attachEvent(("on" + event), cb.bing(elm, window.event));
}
确定this值: 绑定关键字指定对象即为this值
同样只能在函数执行时确定
四个绑定关键词: new、call、apply、bing
call
与apply
直接指定一个对象作为 this 的值
可使用apply
来展开一个数组
ES5:可传入类数组对象
bing
原理
function fakeBind(fn, obj) {
return function () {
return fn.apply(obj, arguments);
};
}
在使用了bing
的函数是尚未执行的,
其this
是不确定的: 只能在执行时确定
使用new调用:为
new
创建的对象没使用new调用:为
bing
绑定的对象只会被
new
改变
new
绑定一定會用新创建的实例对象替换原來的this
无论该函数是否已被其他绑定字绑定过
JS、库、宿主环境的内置函数,提供一个参数
用于绑定 this值
例:数组的forEach
的参数2
Object.create(null);
null / undefined
- 宽松模式:绑定到全局对象
- 严格模式:
null / undefined
new String、new Boolean、new Number
let o = {
a: function () {
console.log(this);
}
};
o.a(); // o
o.a.call(null); // window
o.a.call(1); // Number(1)
确定this值 :
箭头函数没有this值
通过引用其上属函数的this值
若该箭头函数没有上属函数,则其this值为未定义
无法使用绑定关键词修改箭头函数的this值
因为他没有this值
唯一修改this值:
给他套上普通函数,再修改该普通函数的this
function x() {
return (a) => {
//this 取自 x()
console.log(this.a);
};
}
var oA = { a: 2 };
var oB = { a: 3 };
var y = x.call(oA);
y.call(oB); // 2
由于x
的 this
绑定到 oA
箭头函数的this
指向 oA
: y的this
也指向 oA
确定箭头函数的this
:
this
在一个函数中返回另一个函数
function f1() {
console.log(this);
return function f2() {
console.log(this);
}
}
f1()();
函数f1返回的函数的this值,由调用时决定
f1( )( )·
:两次this
都是指向了window
f2执行时,如立即执行函数
const obj = {};
obj.y = f1();
obj.y();
let fn = fn1();
fn();
把f1的返回值,赋值给一个变量
f2的this:调用时决定--fn()、obj.y()
调用标识符所属的对象不相同
其 f2的this也不相同
反柯里化:让对象去借用一个原本不属于它的方法
普通函數寫法
Function.prototype.uncurrying = function () {
var self = this;
return function () {
let thisArg = [].shift.call(arguments);
return self.apply(thisArg, arguments);
}
}
箭頭函數寫法
Function.prototype.uncurrying = function () {
return (...args) => this.call( ...args)
}
箭头函数的this是取值其外层函数的this,
外层函数uncurrying
的this值,决定于调用时的
let push = Array.prototype.push.uncurrying();
此时uncurrying
的调用者是push
函数
则此时的this
是指向push
函数
工具函数
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))
);
对apply
参数1的定制,可实现多种绑定
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
的this為obj1
f3.call(obj2)
:
f3
是箭頭函數--this綁定無效,但其沒有所屬的函數,所以f2.call(this)
的this值為未定義
而在寬鬆模式下的綁定到未定義會改爲绑定到全局对象
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));
立即执行函数的this
在函数中返回一个对象,进行链式调用
let x = function () {
let obj = { y, z }
return obj; // 等效于 return { y, z };
function y() { console.log(this); return this }
function z() { console.log(this); return this }
};
x().y().z();
因为返回的是对象
x() === obj
,而x().y() === obj.y()
x().y() === obj
,而x().y().z()=== obj.z()
手机扫一扫
移动阅读更方便
你可能感兴趣的文章