1. this在全局作用域的指向
在全局作用域下
浏览器:window(globalObject)
Node环境下:{}(因为node源码在实现this绑定时 通过call({})绑定的是空对象)
2. this的绑定指向规则
this的绑定和定义的位置没有关系
this的绑定和调用方式以及调用的位置有关
this是在运行时被绑定的
this的绑定规则
① 默认绑定
独立的函数调用可以理解为没有被绑定到某个对象上进行调用--默认绑定
function foo() {
console.log(this)
}
foo() //window
function foo1() {
console.log(this) //window
}
function foo2() {
console.log(this) //window
foo1()
}
function foo3() {
console.log(this) //window
foo2()
}
function foo() {
function bar() {
console.log(this)
}
return bar
}
var fn = foo()
fn() //window
var obj = {
name: "why",
eating: fn
}
obj.eating() //window 获取到函数后独立调用 指向window
只要函数最后时独立调用 输出都是window
② 隐式绑定
function foo() {
console.log(this)
}
var obj = {
name: "gaofeng"
foo: foo
}
obj.foo() // 输出obj对象
隐式绑定的前提是进行调用时,调用的对象内部有对一个函数的引用
③ 显示绑定
call() apply() bind()(bind回返回一个新函数,apply传入的参数以数组方式传递,call直接逗号传递)
unction foo() {
console.log("函数被调用了", this)
}
// 1.foo直接调用和call/apply调用的不同在于this绑定的不同
foo直接调用指向的是全局对象(window)
foo()
var obj = {
name: "obj"
}
call/apply是可以指定this的绑定对象
foo.call(obj)
foo.apply(obj)
foo.apply("aaaa")
// 2.call和apply有什么区别?
function sum(num1, num2, num3) {
console.log(num1 + num2 + num3, this)
}
sum.call("call", 20, 30, 40)
sum.apply("apply", [20, 30, 40])
// 3.call和apply在执行函数时,是可以明确的绑定this, 这个绑定规则称之为显示绑定
④ new绑定
执行操作:
①创建一个全新的对象;
②这个新对象会被执行prototype连接;
③这个新对象会被绑定到函数调用的this上;
④如果函数没有返回其他对象,表达式会返回这个新对象;
通过一个new关键字调用一个函数时(构造器),这个时候this是在调用这个构造器时创建出来的对象
this = 创建出来的对象
这个绑定过程就是new绑定
function Person(name, age) {
this.name = name
this.age = age
}
var p = new Person("gaofeng", 18)
console.log(p.name, p.age) //gaofeng 18
3. this的指向问题其他补充
3.1 一些函数的this分析
①setTimeout(内部实现是将传入的函数独立调用,所以this指向全局,即window,若传入箭头函数,则是根据上层作用域绑定)
②dom的监听事件(绑定的是监听的对象)
③内置API数组.forEach/map/filter/find,默认绑定window,可以传入第二个参数,即绑定this指向
var names = ["abc", "cba", "nba"]
names.forEach(function(item) {
console.log(item, this) //window
})
names.forEach(function(item) {
console.log(item, this) //abc "abc"
}, "abc")
names.map(function(item) {
console.log(item, this) //abc "cba"
}, "cba")
4. 绑定规则的优先级
默认绑定优先级最低
显示绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定
5. 特殊绑定-忽略显示绑定
function foo(){
console.log(this)
}
foo.apply("abc") //abc
foo.apply({}) //{}
// 传入null/underfined 自动绑定成全局对象
foo.apply(null) // window
foo.apply(underfined) // window
间接函数引用
var obj1 = {
name: "obj1",
foo: function() {
log(this)
}
}
var obj2 = {
name: "obj2"
};
(obj2.bar = obj1.foo)() // 属于独立调用 window
6. ES6的箭头函数指向
箭头函数不使用this的四种标准规则(也就是不绑定this), 而是根据外层作用域来决定this
对象没有作用域,this指向的是全局,函数有函数的作用域
7. this相关面试题
var name = "window"
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.asyName;
sss(); // 函数独立调用 this->window 输出"window"
person.sayName(); // 隐式调用 输出 "person"
(person.sayName)(); // person: 隐式调用 "person"
(b = person.sayName)(); //间接函数引用(独立函数调用) 输出window:赋值表达式
}
sayName();