JS函数中的this指向(下)
1、内置函数的this绑定(一些函数的this分析)
1.1 setTimeout (独立函数调用)
setTimeout(function () {
console.log(this); // window
}, 2000);
1.2 监听点击(隐式绑定)
<body>
<div class="box"></div>
</body>
//监听点击
const boxDiv = document.querySelector(".box");
boxDiv.onclick = function () {
console.log(this); //<div class="box"></div>
};
boxDiv.addEventListener("click", function () {
console.log(this); //<div class="box"></div>
});
1.3 数组的forEach (若没有绑定,默认window)
// 数组.forEach/map/filter/find
var names = ["abc", "cba", "nba"];
names.forEach(function (item) {
console.log(item, this);
}, "abc");
//abc String {'abc'}
//cba String {'abc'}
//nba String {'abc'}
names.map(function (item) {
console.log(item, this);
}, "cba");
//abc String {'cba'}
//cba String {'cba'}
//nba String {'cba'}
2、规则优先级
①默认绑定的优先级最低
②call/apply的显示绑定高于隐式绑定
③bind的优先级高于隐式绑定
④new的优先级高于隐式绑定,高于bind
默认绑定(独立函数调用) < 隐式绑定(obj.foo()) < 显示绑定(apply/call/bind) < new绑定
注意:
new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
new绑定可以和bind一起使用,new绑定优先级更高
//bind的优先级高于隐式绑定
function foo() {
console.log(this);
}
var obj = {
name: "obj",
foo: foo.bind("aaa"),
};
obj.foo(); //String {'aaa'}
var obj = {
name: "obj",
foo: function () {
console.log(this);
},
};
// new的优先级高于隐式绑定
var f = new obj.foo(); //foo {}
// new的优先级高于bind
function foo() {
console.log(this);
}
var bar = foo.bind("aaa");
var obj = new bar(); //foo {}
3、this规则之外
3.1 忽略显示绑定:
如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定
会被忽略,使用默认绑定规则
function foo() {
console.log(this);
}
foo.apply("abc"); // String {'abc'}
foo.apply({}); //{}
// apply/call/bind: 当传入null/undefined时, 自动将this绑定成全局对象
foo.apply(null); //Window
foo.apply(undefined); //Window
var bar = foo.bind(null);
bar(); //Window
3.2、 间接函数引用:
创建一个函数的 间接引用,这种情况使用默认绑定规则
var obj1 = {
name: "obj1",
foo: function () {
console.log(this);
},
};
var obj2 = {
name: "obj2",
};
obj2.bar = obj1.foo;
obj2.bar(); //obj2对象
(obj2.bar = obj1.foo)(); //Window
//赋值(obj2.foo = obj1.foo)的结果是foo函数
//foo函数被直接调用,那么是默认绑定
3.3、 ES6箭头函数
(1)
①箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据上层作用域来决定this。
②定义对象的时候没有产生作用域
注意:箭头函数不会绑定this,arguments属性
不能作为构造函数来使用(不能和new一起使用,会抛出错误)
(2)箭头函数中this的指向
var name = "why";
var foo = () => {
console.log(this);
};
foo(); //Window
var obj = { foo: foo };
obj.foo(); //Window
foo.call("abc"); //Window
// 2.应用场景
var obj = {
data: [],
getData: function () {
console.log(this); //obj对象
// 发送网络请求, 将结果放到上面data属性中
// 在箭头函数之前的解决方案
// var _this = this
// setTimeout(function() {
// var result = ["abc", "cba", "nba"]
// _this.data = result
// }, 2000);
// 箭头函数之后
setTimeout(() => {
console.log(this); //obj对象
var result = ["abc", "cba", "nba"];
this.data = result;
}, 2000);
},
};
obj.getData(); //到上层作用域中,找到getData函数作用域,绑定的是obj对象
//因此这里第15行绑定的也是obj对象
(3)箭头函数有一些常见的简写:
//简写一: 如果参数只有一个, ()可以省略
nums.forEach(item => {
console.log(item)
})
// 简写二: 如果函数执行体只有一行代码, 那么{}也可以省略
// 强调: 并且它会默认将这行代码的执行结果作为返回值
nums.forEach(item => console.log(item))
var newNums = nums.filter(item => item % 2 === 0)
console.log(newNums)
// filter/map/reduce
var result = nums.filter(item => item % 2 === 0)
.map(item => item * 100)
.reduce((preValue, item) => preValue + item)
console.log(result)
// 简写三: 如果一个箭头函数, 只有一行代码, 并且返回一个对象, 这个时候如何编写简写
//在对象外面加上一个小括号()
// var bar = () => {
// return { name: "why", age: 18 }
// }
var bar = () => ({ name: "why", age: 18 })