一. 函数中的this指向
function foo() {
console.log(this)
}
foo()
var obj = {
var name: "zxx",
var age: 22,
foo: foo
}
obj.foo()
foo.call("abc")
这个案例可以给到我们什么样的启示呢?
1.函数在调用时,JS会默认给this绑定一个值
2.this的绑定和定义位置(编写的位置)没有关系
3.this的绑定和调用方式以及调用的位置有关系
4.this是在运行时被绑定的
1. 默认绑定
什么情况下使用默认绑定?: 独立函数调用
独立的函数调用可以理解成函数没有被绑定到某个对象上进行调用
function foo() {
console.log("foo function")
}
foo()
var obj = {
name: "zxx",
bar: function() {
console.log("bar", this)
}
}
var barFn = obj.bar
barFn()
function baz(fn) {
fn()
}
baz(foo)
2.隐式绑定
隐式绑定: 通过某个对象发起的函数调用
隐式绑定有一个前提条件:
必须在调用的对象内部有一个对函数的引用(比如一个属性)
如果没有这样的引用,在进行调用时会报找不到该函数的错误
正是通过这个引用,间接的将thos绑定到了这个对象上
function foo() {
console.log("foo",this)
}
var obj = {
name: "zxx",
foo: foo
}
obj.foo()
var obj2 = {
name: "obj2",
foo: foo
}
var obj3 = {
name: "obj3",
bar: obj2
}
obj3.bar.foo()
var obj = {
name: "obj",
foo: foo
}
var bar = obj.foo
bar()
3.new绑定this
JS中的函数可以当做一个类的构造函数来使用,也就是new关键字
使用new关键字来调用函数时会执行如下操作
1.创建一个全新的空对象
2.这个新对象会被执行prototype连接
3.这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成)
4.如果函数没有返回其他对象,会默认返回这个新对象
function Person(name) {
console.log(this) Person{}
this.name = name Person {name: "why"}
}
var p = new Person("zxx")
console.log(p)
4.显示绑定
如果不希望在对象内部包含这个函数的引用,同时又希望在这个对象上进行强制调用,可以使用显式绑定
JS中所有的函数都可以使用call和apply方法
第一个参数是相同的,要求传入一个对象, 这个对象的作用就是给this准备的,在调用这个函数时,会将
this绑定到传入的这个对象上
后面的参数: apply为数组,call为参数列表
fn.call(thisArg, [argsArray])
fn.apply(thisArg, arg1, arg2...)
function foo() {
console.log("foo function", this)
}
var obj = {
name: "zxx"
}
obj.foo = foo
obj.foo()
foo.call(obj)
foo.apply(obj)
上面的过程,明确的绑定了this指向的对象,所以称之为显式绑定
5.call/apply/bind的额外补充
function foo(name, age, height) {
console.log("foo函数被调用", this)
console.log("name", name, "age", age, "height", height)
}
foo.apply(666, [kobe, 22, 2.88])
foo.call("james", 20, 1.99)
var obj = {
name: "zxx"
}
var bar = foo.bind(obj)
bar() this指向obj
6.内置函数的调用this绑定
<button class="btn">按钮</button>
setTimeout(function() {
console.log(this)
}, 1000)
var btnEl = document.querySelector(".btn")
btnEl.onclick = function() {
console.log(this)
}
btnEl.addEventListener("click", function() {
console.log("btn的点击", this)
})
var names = ["abc", "cba", "nba"]
names.forEach(function() {
console.log("forEach", this)
}, "zxx")
7.this绑定的优先级比较
function test1() {
console.log("test1", this)
}
var obj = { foo: test1 }
obj.foo.apply("zxx")
obj.foo.call("abc")
function test2() {
console.log("test2", this)
}
var bar1 = test2.bind("aaa")
var obj = {
name: "zxx",
bar: bar1
}
obj.bar()
function test3() {
console.log("test3", this)
}
var obj = {
name: "zxx",
test3: function() {
console.log("test3",this)
console.log("test3",this === obj)
}
}
new obj.test3()
function test4() {
console.log("test4", this)
}
var bindFn = test4.bind("ccc")
bindFn()
new bindFn
function test5() {
console.log("test5", this)
}
var bindFn2 = test5.bind("ddd")
bindFn2()
bindFn2.call("hhh")
bindFn2.apply("kkk")
8.this几种绑定规则之外的情况
function foo() {
console.log("foo",this)
}
foo.apply("aaa")
foo.apply(null)
foo.apply(undefined)
var obj1 = {
name: "obj1",
foo: function() {
console.log("foo",this)
}
}
var obj2 = {
name: "obj2"
};
(obj2.foo = obj1.foo)()
9.this面试题
1.
var name = "window"
var person = {
name: "person",
sayName: function() {
console.log(this.name)
}
};
function sayName() {
var sss = person.sayName
sss();
person.sayName();
(person.sayName)();
(b = person.sayName)();
}
sayName()
2.
var name = "window"
var person1 = {
name: "person1",
foo1: function() {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function() {
return function() {
console.log(this.name)
}
},
foo4: function() {
return () => {
console.log(this.name)
}
}
}
var person2 = { name: "person2" }
person1.foo1()
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
perosn1.foo3().call(person2)
person1.foo4()()
person1.foo4().call(person2)()
person1.foo4().call(person2)