一、为什么会有this的出现
“this关键词是JS中最复杂的机制之一,它是一个很特别的关键字,被自动定义在所有函数的作用域中”根据凯尔辛普森的书中描述,刚开始阅读时我对this的使用都感觉到有点一头雾水,虽然隐隐约约知道this的出现是为了使代码更简洁而且利于复用,同时this单指“这个“单词是非常意味鲜明的,但在各种情况下不同的this指向,反倒是让人觉得这个设计逻辑很反人类。
二、this
this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式,简单来说,只有在函数执行this才会有它的指向,如果函数不执行,则this没有任何意义。
三、this的绑定规则
1、默认绑定
默认绑定下,this默认指向window,什么时候会认为是默认绑定呢?即是函数的独立调用,this默认指向window,以及在全局作用域下this默认指向window。
function test(){
console.log(this === window);
}
test(); //函数独立调用 this指向window
var a = 0 l
function foo(){
console.log(this); //this指向window
}
var obj = {
a:2;
foo:foo;
}
var bar = obj.foo; //bar赋值为对象obj的foo方法
bar(); //独立调用foo函数
2、隐式绑定
this体现为谁调用就指向谁。
var a = 888;
var obj = {
a: 666;
foo: function(){
console.log(this); // obj
}
}
var obj1 ={
o:obj;
}
obj.foo(); //对象obj调用,则指向对象obj
obj1.o.foo(); //this指向obj,距离调用自己最近的对象
3、显式绑定
显式绑定是指通过用call,apply以及bind方法来改变this的行为,相比隐式绑定,this指向变化过程。
call()方法
call()方法的作用:可以调用一个函数,于此同时,改变这个函数内部的this指向,此外call()方法还可以实现继承。
语法:
fn.call(想要this指向的地方,函数实参1,函数实参2);//第一个如果不改变this指向,则传null
//call()实现this指向的改变
const obj1 = {
Name:'Essie',
Age:23,
};
function fn(){
console.log(this); //window
console,log(this.nickname); //undefined
}
fn.call(this); //this没有改变 函数调用fn(),指向window
function fn1(a,b){
console.log(this); //obj1
console.log(this.nickname); //Essie
console.log(a+b); //6
}
fn1.call(obj1,3,3); //this指向obj1对象
//call()实现继承
function Father(Name,Age){
this.name = Name;
this.age = Age;
}
function Son(Name,Age){
Father.call(this,Name,Age); //call()方法下Son继承了Father里的name和age属性
}
const son = new Son('Essie',23);
console.log(JSON.stringfy(son)); //{"Name":"Essie","Age":23}
apply()方法
apply需要传递数组,所以会有些不同。
语法:
fn.apply(想要this指向的地方,[函数实参1,函数实参2]);//第一个参数不改变this指向,传null
const obj1 = {
Name:'Essie',
Age:23,
};
function fn1(a){
console.log(this); //obj1
console.log(this.nickname); //Essie
console.log(a); //6
}
fn1.apply(obj1,['hello']);//this指向obj1,然后执行fn1()函数
bind()方法
bind()方法不会调用函数,但是可以改变函数内部的this指向,如果不需要立即调用,但又需要改变函数的内部指向, 则bind()是最为合适的。
语法:
函数 = fn.bind(想要this指向的地方,函数实参1,函数实参2);//第一个不改变,则传null
bind函数是有返回值的
4、new绑定
用new来调用函数u,发生构造函数调用是,执行操作步骤是,首先创建一个全新的对象;新的对象会被执行[Prototype]连接;新对象会绑定到函数调用的this;如果函数没有手动返回对象,则返回创建的新对象。
语法例子
function foo(a){
this.a = a;
}
var bar = new foo(2); //new了一个新对象并绑定到foo的this
console.log(bar.a); //2
四、this绑定优先级
显示绑定>隐式绑定>默认绑定
new绑定>隐式绑定>默认绑定
五、箭头函数的调用
六、原型链中的this
七、主要注意的地方
this指向只在函数执行时才有其实际意义,而且this指向永远不取决于写在哪,而是取决于谁调用。
1、以函数形式独立调用时(普通函数、立即执行函数、setTimeOut)调用,this指向的都是Window全局。
2、以方法形式调用的时候,this指向调用方法的对象
3、以构造函数调用的时候,this指向实例对象
4、以事件绑定函数的形式调用的时,this指向绑定事件的对象
5、使用call、apply调用,this指向指定的对象