JS 函数调用 4 种模式
Function Invocation Pattern
- 无论在哪 直接调用函数名 this 指向 windows
- 箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this
function printThis() {
console.log(this)
let print = function () { console.log(this) };
print();
}
printThis() // 第一行打印 window,第二行打印window
printThis.call([1]); // 第一行打印[1],第二行打印window
printThis.call([2]); // 第一行打印[2],第二行打印window
function printThis() {
console.log(this)
let print = () => console.log(this);
print();
}
printThis() // 第一行打印 window,第二行打印window
printThis.call([1]); // 第一行打印[1],第二行打印[1]
printThis.call([2]); // 第一行打印[2],第二行打印[2]
Method Invocation Pattern
- 被调用的函数作为一个对象的属性出现
- 函数的 this 永远是调用前的那个对象
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
// 区分
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
var j = o.b.fn; // 只是定义,并未调用执行,真正的调用执行在下面的j()
j(); // undefined
Constructor Pattern
- new foo()这种形式的调用被称为Constructor Pattern
- foo函数内部的this永远是new foo()返回的对象
function Foo () {
this.x = 1;
}
Foo.prototype.print = function () {
console.log(this.x);
}
let foo = new Foo();
foo.print(); // 1
foo.print.call({x: 2}); // 2
function Foo () {
this.x = 1;
// 返回一个对象 返回值会被该对象 替换掉
return {x: 2};
}
Foo.prototype.print = function () {
console.log(this.x);
}
let foo = new Foo();
console.log(foo.x); // 2
foo.print(); // funciton print undefined
function Foo () {
this.x = 1;
// 返回一个值
return 1;
}
Foo.prototype.print = function () {
console.log(this.x);
}
let foo = new Foo();
console.log(foo.x); // 1
foo.print(); // 1
var x = 0;
function Foo () {
this.x = 1;
}
// 我们知道箭头函数不包含this,它的this为执行上下文中的this。而且箭头函数的执行上下文的判定,就在其定义的时刻决定,我们发现,它是在脚本中定义的,此时的作用域为全局,因此此时,前两条打印和后两条打印一样,都为0和window
Foo.prototype.print = () => {
console.log(this);
console.log(this.x);
(function () {
console.log(this);
console.log(this.x)
})()
}
let foo = new Foo();
foo.print.call({x: 2});
Apply Pattern
- foo.call(thisObject)和foo.apply(thisObject)的形式被称为Apply Pattern,使用了内置的call和apply函数
- call和apply的第一个参数就是foo函数体内的this,如果thisObject是null或undefined,那么会变成window对象