this的指向也算是js比较容易迷糊的一个点,有时候很容易搞错了this指向的是谁。
有俩点比较关键的说法
1.this总是执行为当前的执行环境。
2.this的指向取决于函数的调用方式
全局的执行上下文中.
console.log(this == window); // true
var b = 20;
console.log(window.b); //20
this.add = (a,b) =>{
return a+b
}
window.add(5,5) //10
上面的代码我们可以看出。在全局中var == this. == window.;
函数上下文中。
取决于函数的调用方式。
在全局中直接调用
function foo(){
return this;
}
console.log(foo() == window) //true
this还是指向window
绑定到对象上调用call,apply。
let obj = {
name:'lly',
age:20,
}
function gud(){
return this.name+':'+this.age
}
console.log(gud.call(obj)) //lly:20
console.log(gud.apply(obj)) //lly:20
call和apply修改了this的指向,从指向window,变成对象obj
构造函数中使用
function myobj(name,age){
this.name = name;
this.age = age;
this.say = function(){
return `我叫${
this.name},今年${
this.age}`
}
}
let lly = new myobj('lly',22);
console.log(lly.say) //我叫lly,今年22
构造函数中指向的是当前new的对象。
new创建的过程
1.创建一个空对象。
2.把this指向这个空对象。
3.进行属性和方法的赋值
4.返回this。
对象方法中使用
let obj ={
name:'lly',
age:40,
says:function(){
return this.name+':'+this.age
}
}
console.log(obj.says()) // lly:40
在函数调用的时候会指向当前函数,那如果对象里的函数换成箭头函数以后呢。
var name = '全局';
var age=20;
let obj ={
name:'lly',
age:40,
says:() =>{
return this.name+':'+this.age
}
}
console.log(obj.says()) //全局:20
会神奇的发现this又指向了全局,这是因为箭头函数本身是没有this的。
Dom节点上使用
$('.btn').click(function(){
console.log(this);
})
document.getElementById('btn').onclick = function(){
console.log(this);
}
<button onclick="console.log(this);">点我</button>
this都指向DOM元素节点。
总结
判断this指向,this的指向,是在函数被调用的时候确定的,
可以按照一个顺序来看
判读是否是箭头函数。
判断是否有修改指向的行为,call apply bind
判断所在的执行上下文
-------------------------------- 手动分割 -------------------------------------
看完不知道的js之后,做一下记录把,记录成长的对比。
this的几种绑定规则
1.默认绑定
function wait(){
console.log(this.a);
}
var a = 2;
wait(); // 2
上面的代码中的this指向的就是全局变量a的,默认绑定的就把this绑定到全局对象上,所以指向全局对象。根据之前说的看调用的位置,这个调用的位置就是在全局上下文中调用的,所以通过这个就可以看出来。
有一点需要注意下,严格模式下与 wait()的调用位置无关:
2.隐式绑定
function add(){
console.log(this.a+this.b);
}
let objs = {
a:1,
b:2,
add:add
}
objs.add(); // 打印 3
在上面我们可以看到,我们把add这个方法通过引用引用到对象obj的一个属性中,我们在通过objs.add
去调用,会发现this指向了我们的objs上。这就是隐式绑定,
**隐式丢失:**在使用隐式绑定的时候可能会照成隐式绑定的丢失。
function add(){
console.log(this.a);
}
let objs = {
a:10,
add:add
}
let objd = objs.add;
objs.add(); // 10
objd(); // undefined
隐式绑定的到objs上的只是一个引用,当再次使用的时候还是一个引用而已。不会附带this的绑定,会变成默认绑定。所以是undefined;
3.显式绑定(硬绑定)
这个也是我们上面说过的俩个 call和apply这俩个改变this的指向,称之为显示绑定,因为我们看的到这个方法就知道是改变了this的指向了。
function add(){
console.log(this.x+this.y);
}
let objs = {
x:1,
y:2
}
add.apply(objs) //3
这个上面也有提到过,这就简单说一下。apply修改add的指向到objs上。可惜,显式绑定仍然无法解决我们之前提出的丢失绑定问题。
硬绑定 bind方法
function add(y){
console.log(this.x + y);
}
let objs = {
x:5
}
let bar = add.bind(objs);
bar(10); //15
bind(…) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。
4.new绑定
new的过程我想大家可能都知道
中间就有一半修改中this的步骤。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2
使用 new 来调用 foo(…) 时,我们会构造一个新对象并把它绑定到 foo(…) 调用中的 this
上。new 是最后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。
如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后
就可以顺序应用下面这四条规则来判断 this 的绑定对象。
- 由 new 调用?绑定到新创建的对象。
- 由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
- 由上下文对象调用?绑定到那个上下文对象。
- 默认:在严格模式下绑定到 undefined,否则绑定到全局对象