目录
- 调用位置
- 默认绑定
- 隐式绑定
- 隐式丢失
- 显式绑定
- call
- apply
- bind
- new绑定
- 装箱
- 绑定优先级
- this规则之外
- 忽略显式绑定
- 间接函数引用
- 箭头函数
调用位置
从字面意思上来理解,this似乎是指向自己的
然而在JavaScript中,this并不是绑定到自身的
可以看这一个例子
function foo(num) {
console.log("num:" + num)
this.count++
}
foo.count = 0
for (var i = 0; i < 10; i++) {
if (i > 5) {
foo(i)
}
}
console.log(foo.count)
结果

显然从字面意思来理解this指向自身是错误的认知
事实上this并不是编写时绑定的,而是运行时绑定的
我们判断this会绑定到什么首先就要分析它的调用位置
function foo() {
bar()//此时的调用栈为:全局--》foo--》bar
function bar() {
baz()//此时的调用栈为:全局--》foo--》bar--》baz
function baz() {
}
}
}
foo()//此时的调用栈为:全局--》foo
在寻找到它的调用位置之后我们就需要判断这里的this适用于以下四条规则中的哪一条
默认绑定
当独立调用函数时适用此条,也可以看成当其他三条规则都不适用时适用这条规则
独立函数调用可以看成函数没有被绑定到某个对象上进行调用
例如下面这个例子
function foo() {
console.log(this)
}
foo()
结果

此时的this绑定了全局对象window上
值得注意的是,在严格模式下,这里的this会绑定到undefined上
隐式绑定
另一种比较常见的绑定方式为通过某个对象调用
function foo() {
console.log(this)
}
var obj = {
name: "obj",
foo: foo
}
obj.foo()
结果

此时的this绑定到了obj对象上了
隐式丢失
被隐式绑定的this有时也会应用默认绑定规则
例如下面这段代码
function foo() {
console.log(this)
}
var obj = {
name: "obj",
foo: foo
}
var bar = obj.foo
bar()

可以看到this绑定到了window上,这就是隐式丢失
显式绑定
在上面的代码中我们可以看到隐式绑定也会有可能出现隐式丢失的现象,为了确保我们的this能正确的绑定到我们想要的对象上可以使用显式绑定
显式绑定可以通过传递参数的形式来把this绑定到参数上
显示绑定有具体三种方式
call
call方法需要传入一个参数来作为this的绑定对象,如果函数需要参数则在后面用逗号隔开
function foo(name, age) {
console.log(this)
console.log(name + " " + age)
}
var obj = {
name: "obj",
}
foo.call(obj, "张三", 18)
结果

这里可以看到this绑定到了obj上了
注意:call方法是立即执行的
apply
apply方式与call方法相似,但传递参数的方式不同
function foo(name, age) {
console.log(this)
console.log(name + " " + age)
}
var obj = {
name: "obj",
}
foo.apply(obj, ["张三", 18])
结果

这里可以看到this绑定到了obj上了
注意:apply方法也是立即执行的
bind
无论是apply绑定或者是call绑定,都不能完全解决this的绑定丢失问题
当将函数作为参数传递给其他函数之后,很难知道其他函数会怎么调用这个函数
函数的this指向此时也不受你控制
为了解决这个问题,我们可以使用bind方法
function foo() {
console.log(this)
}
function bar(fn) {
fn.call(obj)
}
var obj = {
name: "obj",
}
bar(foo.bind(window))
结果

bind方法不会立即执行函数,而是会返回一个新函数
新函数的this将会指向你所指定的对象
以后this的指向也始终会是预期的
new绑定
当我们使用new关键字时,会执行以下几件事情
- 创建一个
空对象 - 将_空对象_的
this绑定到这个空对象 - 执行函数体里的代码
function foo() {
console.log(this)
this.a = 2
}
var obj = {
name: "obj",
}
var bar = new foo()
console.log(bar.a)
结果

可以看到此时的this已经绑定到了foo上
装箱
无论是call还是apply还是bind,当我们传入一个原始值(如数字,字符串)时会发生什么呢
function foo() {
console.log(this)
this.a = 2
}
var obj = {
name: "obj",
}
foo.call(123)
foo.apply("123")
结果

得到的结论就是如果你传入了一个原始值来当作this的绑定对象,这个原始值会被转换成它的对象形式
如new Number()、new String()等等
这通常被称为装箱
绑定优先级
当一个函数涉及了多条规则,规则与规则之间则会按照自己的优先级生效
-
毋庸置疑的是
默认绑定优先级最低,是其他规则都不适用情况下的兜底条款 -
显示绑定的优先级高于隐式绑定function foo() { console.log(this.name) this.a = 2 } var obj = { name: "obj", foo: foo } var obj2 = { name: "obj2", foo: foo } obj.foo.call(obj2)结果

-
new绑定比隐式绑定优先级高function foo() { this.a = 2 } var obj = { name: "obj", a: 4, foo: foo } var obj2 = new obj.foo() console.log(obj2.a)结果

-
new绑定无法与call/apply方法一起使用,但我们可以通过与bind方法比较来得到结果function foo() { console.log(this) } var obj = { name: "obj", } var obj2 = foo.bind(obj) new obj2结果

我们可以知道new绑定优先级高于显式绑定
this规则之外
在现实使用中,我们总有些语法超出了规则之外
忽略显式绑定
当传入的参数是null或者为undefined时,这个显式绑定会忽略,使用默认绑定
function foo() {
console.log(this)
}
foo.call(null)
foo.call(undefined)
结果

间接函数引用
创建一个函数的间接引用,这种情况适用默认规则
function foo() {
console.log(this)
}
var obj = {
foo: foo
}
var obj2 = {
name: "obj2"
};
(obj2.foo = obj.foo)()
结果

箭头函数
在ES6中提出了一种新函数,他的名字叫箭头函数
在箭头函数中,其实并没有this
所以并不适用上面提到的四条规则
箭头函数中的this是由其外部作用域来决定的
当箭头函数中遇到this时,箭头函数便会去它的外层作用域寻找
var obj = {
bar: function () {
var foo = () => {
console.log(this)
}
return foo
}
}
var baz = obj.bar()
baz()
结果












![学习babylon.js --- [3] 开启https](https://img-blog.csdnimg.cn/de5381c579a1456f981f34e9b42c8a60.png)







