浏览器:在浏览器环境里是没有问题的,全局声明的函数放在了 window 对象下,foo 函数里面的 this 代指的是 window 对象,在全局环境中并没有声明变量 a,因此在 bar 函数中的 this.a 自然没有定义,输出 undefined。
Node.js:在 Node.js 环境下,声明的 function 不会放在 global 全局对象下,因此在 foo 函数里调用 this.bar 函数会报 TypeError: this.bar is not a function 错误。要想运行不报错,调用 bar 函数时省去前面的 this。
This 四种绑定规则
默认绑定
当函数调用属于独立调用,无法调用其他规则时,我们给它一个称呼“默认绑定”。
非严格模式下调用, 浏览器会将 a 绑定到 window.a,以下代码使用 var 声明的变量 a 会输出 1.
以下代码使用 let 或 const 声明变量 a 结果会输出 undefined
在举例子的时候其实想要重点说明 this 的默认绑定关系的,但是你会发现上面两种代码因为分别使用了 var、let 进行声明导致的结果也是不一样的,归其原因涉及到 顶层对象的概念
顶层对象(浏览器环境指 window、Node.js 环境指 Global)的属性和全局变量属性的赋值是相等价的,使用 var 和 function 声明的是顶层对象的属性,而 let 就属于 ES6 规范了,但是 ES6 规范中 let、const、class 这些声明的全局变量,不再属于顶层对象的属性。
function demo() {
console.log(this.a); // 1
}
var a = 1;
demo();
function demo() {
console.log(this.a); // undefined
}
let a = 1;
demo();
function child() {
console.log(this.name);
}
let parent = {
name: "zhangsan",
child,
};
parent.child(); // zhangsan
function test(...arg) {
console.log(this.variable + arg);
}
var obj = {
variable: 1,
};
test();
test.apply(obj, [2, 2, 3]);
test.call(obj, 2);
var c = test.bind(obj, 3);
c();
function Fruit(name) {
this.name = name;
}
const f1 = new Fruit("apple");
const f2 = new Fruit("banana");
console.log(f1.name, f2.name); // apple banana
function fruit() {
return () => {
console.log(this.name);
};
}
var apple = {
name: "苹果",
};
var banana = {
name: "香蕉",
};
var fruitCall = fruit.call(apple);
fruitCall.call(banana); // 苹果
function Fruit(name) {
this.name = name;
}
Fruit.prototype.info = () => {
console.log(this.name);
};
var name = "Banana";
const f1 = new Fruit("Apple");
f1.info(); // Banana
function Fruit(name) {
this.name = name;
}
Fruit.prototype.info = function () {
console.log(this.name);
};
var name = "Banana";
const f1 = new Fruit("Apple");
f1.info(); // Apple