11. this指向与call、apply、bind、箭头函数
参考:文章
函数调用
全局上下文
非严格模式和严格模式中this都是指向顶层对象(浏览器中是window)
js
this === window // true
'use strict'
this === window // true
函数上下文
普通函数调用模式
js
var name = 'window'
var doSth = function() {
console.log(this.name)
}
doSth() // 'window'
//
let name2 = 'window'
let doSth2 = function() {
console.log(this === window)
console.log(this.name2)
}
doSth2() // true undefined
var
会将变量挂在顶层对象(浏览器window)中,而let
不会。
可以类比为(默认绑定)
js
doSth.call(undefined)
doSth.apply(undefined)
对象中函数的调用方式
js
var name = 'window'
var doSth = function() {
console.log(this.name)
}
var student = {
name: '若川'
doSth: doSth,
other: {
name: 'other',
doSth: doSth
}
}
student.doSth() // '若川' -> student.doSth.call(student)
student.other.doSth() // 'other' -> student.other.doSth.call(student.other)
有时,把对象中的函数赋值给一个变量,就变成普通函数的规则(默认绑定)
js
var studentDoSth = student.doSth
studentDoSth() // 'window'
// 类比: studentDoSth.call(window)
call、apply、bind
调用模式
call、apply
方法
语法:
js
fun.call(thisArg, arg1, arg2, ...)
fun.apply(thisArg, argsArray)
- thisArg:非严格模式,null和undefined可以被替换为window。如果是原始值,会直接指向该原始值的自动包装对象。
- arg1,argsArray: 指定调用函数时的参数
返回值是调用方法的返回值,若没有,则返回undefined
bind
方法
语法:
js
const f = func.bind(thisArg, arg1, arg2, ...)
f()
与call类似,但是返回值是一个函数
构造函数调用模式
js
function Student(name){
this.name = name;
console.log(this); // {name: '若川'}
// 相当于返回了
// return this;
}
var result = new Student('若川');
new操作符调用后,this指向生成的新对象
原型链中的调用模式
js
function Student(name){
this.name = name;
}
var s1 = new Student('若川');
Student.prototype.doSth = function(){
console.log(this.name);
}
s1.doSth(); // '若川'
同对象调用模式
箭头函数调用模式
箭头函数
- 没有自己的this、super、arguments
- 不能使用new调用
- 没有原型对象
- 不可以改变this绑定
- 形参名称不可以重复
箭头函数没有this
绑定,必须通过查找作用域链来决定值
- 如果箭头函数被非箭头函数包含,则
this
绑定的是最近一层非箭头函数的this
- 否则,
this
值为全局对象
js
var name = 'window';
var student = {
name: '若川',
doSth: function(){
// var self = this;
var arrowDoSth = () => {
// console.log(self.name);
console.log(this.name);
}
arrowDoSth();
},
arrowDoSth2: () => {
console.log(this.name);
}
}
student.doSth(); // '若川'
student.arrowDoSth2(); // 'window'
DOM事件处理函数调用
addEventListener、attachEvent、onClick
js
<button class="button">onclick</button>
<ul class="list">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var button = document.querySelector('button');
button.onclick = function(ev){
console.log(this);
console.log(this === ev.currentTarget); // true
}
var list = document.querySelector('.list');
list.addEventListener('click', function(ev){
console.log(this === list); // true
console.log(this === ev.currentTarget); // true
console.log(this);
console.log(ev.target);
}, false);
</script>
onclick
和addEventListener
指向绑定事件的元素
currentTarget和target
- currentTarget是绑定事件的元素
- target是当前触发事件的元素
内联事件处理函数
js
<button class="btn1" onclick="console.log(this === document.querySelector('.btn1'))">点我呀</button>
<button onclick="console.log((function(){return this})());">再点我呀</button>
手写
call和apply类似
js
Function.prototype.mycall = function(thisArg, ...args) {
// 1. Let func be the this value. 将当前函数赋值给fun变量
let func = this
// 2. If IsCallable(func) is false, throw a TypeError exception. 判断当前函数是否可执行
if(!func instanceof Function) {
throw new TypeError(`${this} is not a function`)
}
thisArg.func = func
return thisArg.func()
}