目录
一、this在全局作用域下被使用
先看以下代码:
// 在浏览器运行
// 在node环境下运行
console.log(this)
1.两种情况:
- 在浏览器中:this指向window
- 在Node环境中:this指向一个空对象{}
node环境下的执行顺序:node会将这个文件当成一个module,然后加载这个模块,然后进行编译,再将这些代码放到一个函数中,然后执行这个函数,再用call绑定一个空对象,所以node环境下的this是一个空对象
function foo() {
console.log(this)
}
// 1.直接调用这个函数
foo()
// 2.创建一个对象, 对象中的函数指向foo
var obj = {
name: 'why',
foo: foo
}
obj.foo()
// 3.apply调用
foo.apply("abc")
2.总结:
- 函数在调用时,JavaScript会默认给this绑定一个值;
- this的绑定和定义的位置没有关系;
- this的绑定和调用方式以及调用的位置有关系;
- this是在运行时被绑定的;
二、this的四个绑定规则
1.默认绑定(独立函数调用)
默认绑定相当于独立函数的调用,我们可以理解成函数没有被绑定到某个对象上进行调用
代码示例:
// 1.例子一
function foo() {
console.log(this)
}
foo() // 输出window
// 2.例子二
var obj = {
name: "why",
foo: function() {
console.log(this)
}
}
var bar = obj.foo
bar() // window
2. 隐式绑定(通过某个对象调用)
是通过某个对象进行调用的 ,也就是它的调用位置中,是通过某个对象发起的函数调用 。
代码示例:
// 1.例子一:
var obj = {
name: "why",
foo: foo
}
obj.foo() // obj对象
// 2.例子二:
var obj1 = {
name: "obj1",
foo: function() {
console.log(this)
}
}
var obj2 = {
name: "obj2",
bar: obj1.foo
}
obj2.bar()
3.显示绑定(call/apply/bind)
call/apply在执行函数时,是可以明确的绑定this,这个绑定规则称为显示绑定
显示调用:我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用,使用call和 apply方法 ,call/apply是可以指定this的绑定对象
代码示例:(apply/call)
function sum(num1, num2, num3) {
console.log(num1 + num2 + num3, this)
}
sum.call("call", 20, 30, 40)
sum.apply("apply", [20, 30, 40])
代码示例:(bind,如果我们希望一个函数总是显示的绑定到一个对象上,那么就使用bind)
解析:foo.bind('aaa'), this绑定了字符串aaa,然后返回一个函数,调用这个函数,这个函数的this都是指向字符串aaa
function foo() {
console.log(this)
}
var newFoo = foo.bind("aaa")
newFoo()
newFoo()
newFoo()
注意:默认绑定和显示绑定bind冲突:优先级(显示绑定) ,如上图
4.new绑定
JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字
使用new关键字来调用函数是,会执行如下的操作:
(1) 创建一个全新的对象;
(2) 这个新对象会被执行prototype连接;
(3) 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
(4) 如果函数没有返回其他对象,表达式会返回这个新对象;
代码示例:
function Person(name, age) {
this.name = name
this.age = age
}
var p1 = new Person("why", 18)
console.log(p1.name, p1.age)
var p2 = new Person("kobe", 30)
console.log(p2.name, p2.age)
三、四个规则的优先级
1.默认规则的优先级最低
2.显示绑定优先级高于隐式绑定
obj.foo.apply('abc')
obj.foo.call('abc')
3.new绑定优先级高于隐式绑定
var obj = {
name: "obj",
foo: function() {
console.log(this)
}
}
var f = new obj.foo()
4.new绑定优先级高于bind
function foo() {
console.log(this)
}
var bar = foo.bind("aaa")
var obj = new bar()
四、this的其他特殊绑定
1. 如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则
function foo() {
console.log(this)
}
foo.apply(null)
foo.apply(undefined)
var bar = foo.bind(null)
bar()
2.创建一个函数的 间接引用,这种情况使用默认绑定规则 ,因为赋值(obj2.foo = obj1.foo)的结果是foo函数
var obj1 = {
name: "obj1",
foo: function() {
console.log(this)
}
}
var obj2 = {
name: "obj2"
};
(obj2.bar = obj1.foo)()
3.箭头函数的this绑定
箭头函数并不绑定this对象,那么this引用就会从上层作用于中找到对应的this
var name = "why"
var foo = () => {
console.log(this)
}
foo()
var obj = {foo: foo}
obj.foo()
foo.call("abc")