this的指向
为什么需要this?
没有this的话,上图的obj改名了,里面的所有都要跟着改,非常不方便。
而用this,指向的就是这个对象自己,不管你外面怎么改名字。
this指向什么?
浏览器:window
nodejs:{}
nodejs环境,是把单个文件当做模块执行,然后调用函数.apply({}) 的方式,把整个文件绑定给空对象
这里的this,会根据规则动态绑定,并非像函数执行上下文(FEC)、作用域链那样编译的时候就确定,如下例子:
绑定规则
1、默认绑定
独立的函数调用,我们可以理解成函数没有被绑定到某个对象上进行调用(在全局的环境下调用)。
浏览器的this:window
nodejs的this:{ } 空对象
2、隐式绑定
是通过某个对象进行调用的,
3、显式绑定
通过call 、 apply 、bind 方法手动绑定某个对象
call 、 apply,第一个参数就是你指定的this,区别在于后面传参的方式而已
bind 是创建一个新的函数并重新指定this,然后赋值给其他标识符,调用这个标识符就默认是这个绑定的this。
后面传参数和call一样的,通过逗号
4、new 绑定
JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字
使用new关键字来调用函数是,每次会执行如下的操作:
function Person(){}
new Person()
1、创建一个全新的对象 { };
function Person(){
var obj = {}
}
2、这个新对象会绑定到函数调用的this上
function Person(){
var obj = {}
this = obj // 这里只是演示这个意思,不能这样写
}
3、如果函数没有返回其他对象,表达式会返回这个新对象
function Person(){
var obj = {}
this = obj // 这里只是演示这个意思,不能这样写
return this
}
var p = new Person()
// p = obj 相当于
规则优先级
1、new > 隐式 > 默认({ })
2、显式 > 隐式 > 默认(’abc’)
(’aaa’)
3、new 和 显式绑定({ })
内置函数的绑定
forEach等某些函数,默认是window,可以额外传入this参数,后面的执行都会绑定这个this参数
规则之外
1、忽略显示绑定
传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则
2、间接函数引用
创建一个函数的 间接引用,这种情况使用默认绑定规则。如下的最后一行代码(可能一辈子都用不上,主要是面试)
3、严格模式
// 在严格模式下, 自执行函数(默认绑定)会指向undefined
// 之前编写的代码中, 自执行函数我们是没有使用过this直接去引用window
function foo() {
console.log(this)
}
var obj = {
name: "why",
foo: foo
}
foo() // undefined
obj.foo() // obj
var bar = obj.foo
bar() // undefined
// setTimeout的this
// fn.apply(this = window)
setTimeout(function() {
console.log(this) // window
}, 1000);
===================
箭头函数 ( ) => { }
基本
箭头函数未被提升。它们必须在使用前进行定义。 (但是NodeJS环境里是有的,每个文件是一个模块,这样显示的就是这个模块的arguments)
优化(简写)
应用场景
面试题
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(隐式绑定)
// person1.foo1.call(person2); // person2(显示绑定优先级大于隐式绑定)
// person1.foo2(); // window(不绑定作用域,上层作用域是全局)
// person1.foo2.call(person2); // window
// person1.foo3()(); // window(独立函数调用)
// person1.foo3.call(person2)(); // window(独立函数调用)
// person1.foo3().call(person2); // person2(最终调用返回函数式, 使用的是显示绑定)
// person1.foo4()(); // person1(箭头函数不绑定this, 上层作用域this是person1)
// person1.foo4.call(person2)(); // person2(上层作用域被显示的绑定了一个person2)
// person1.foo4().call(person2); // person1(上层找到person1)