this是所有函数在被调用时,定义在函数的作用域中。是根据函数调用的方式决定的,并不是由书写的位置决定的。
1.默认绑定
直接调用,即是:不做this更改和作为对象属性调用时。this是全局对象,浏览器中则是Window对象。
function baz(){
console.log(this); // Window
bar();
}
function bar(){
console.log(this); // Window
foo();
}
function foo(){
console.log(this); // Window
}
baz();
上述代码在浏览器执行是打印都是Window,即使bar和foo函数是在baz和bar函数中被调用的,但是他与书写位置无关,都是指向window。
注意:函数内容在严格模式执行时this是undefined:
function baz(){
'use strict'
console.dir(this); // undefined
}
baz();
注意:函数在严格模式调用时是正常的:
function baz(){
'use strict'
// 在严格模式下执行,undefined
console.dir(this); // undefined
// 在严格模式下被调用Ok
bar();
}
function bar(){
console.dir(this); // Window
}
baz();
隐式绑定
作为对象的属性被调用时。则this会被绑定到该对象上。
// 函数属性
function baz(){
console.dir(this); // Window
}
baz.bar = function(){
console.dir(this); // f baz()
}
baz();
baz.bar();
// 对象属性
let obj = {
a: 1,
b:function() {
console.dir(this) // Object {a: 1, b: function}
console.log(this.a) // 1
}
}
obj.b();
注意:只绑定上一层(最后一层)
let obj1 = {
a: 1,
b:function() {
console.dir(this) // Object {a: 1, b: function}
console.log(this.a) // 1
}
}
let obj2 = {
a: 2,
obj1,
}
obj2.obj1.b();
注意:隐式丢失,当使用默认隐式绑定的函数被赋值给其他变量或者作为参数传递时。
// 赋值给其他变量
var a = 2
let obj1 = {
a: 1,
b:function() {
console.dir(this) // Window
console.log(this.a) // 2
}
}
let myB = obj1.b
myB()
// 作为参数传递
var a = 2
let obj1 = {
a: 1,
b:function() {
console.dir(this) // Window
console.log(this.a) // 2
}
}
function foo(fn) {
fn()
}
foo(obj1.b)
显示绑定
通过call、apply、bind改变this指向。
// call
var a = 1
var obj = {
a: 2
}
function foo() {
console.log(this) // Object { a: 2}
console.log(this.a) // 2
}
foo.call(obj)
// apply
var a = 1
var obj = {
a: 2
}
function foo() {
console.log(this) // Object { a: 2}
console.log(this.a) // 2
}
foo.apply(obj)
new 绑定
当使用new来调用函数,返回一个对象时:
1.创建一个全新的对象
2.这个对象的内部[[prototype]]特性被赋值为构造函数的prototype属性
3.构造函数内部的this被赋值为这个新对象
4.执行内部代码(给新对象添加属性)
5.如果返回非空对象,则返回该对象;否则,返回刚创建的新对象
function Foo() {
this.a = 1
}
let bar = new Foo()
console.log(bar.a) // 1
原生dom事件中的this
绑定原生事件可以有三种:
// 第一种
<input id="input" type="text" onchange="change()" />
function change() {}
// 第二种
var myInput = document.querySelector('#input')
document.getElementById("input").onchange = function() {}
// 第三种
var myInput = document.querySelector('#input')
myInput.addEventListener('change', function() {})
它们三种情况下this指向有何不同?
1.先看第一种:
var myInput = document.querySelector('#input')
function change() {
console.dir(this,'this')
console.dir(myInput,'myInput')
// 此时不能用this
document.getElementById("span").innerHTML = myInput.value
}
this是window。虽然函数赋值给了input对象的onchange属性,但this不是input对象。可见在事件触发时,至少不是通过input.onchange()调用的。
2.第二种:
var myInput = document.querySelector('#input')
myInput.onchange = function() {
console.dir(this)
console.dir(myInput)
// 此时可以通过this取得value值
document.getElementById("span").innerHTML = this.value
}
this是input。同时函数赋值给了input对象的onchange属性。
第三种情况:
var myInput = document.querySelector('#input')
myInput.addEventListener('change', function() {
console.dir(this)
console.dir(myInput)
document.getElementById('span').innerHTML = this.value
})
this是input。但函数并没有赋值给input对象的onchange对象,所以通过input.onchange()调用函数是行不通的。
那是如何把this绑定到input对象上的呢?**哈哈不知道!**需要注意在函数使用this或者操作dom对象本身时,这些不同情况的差异就好了。