对this的简单理解
this的绑定时间
var length=10; function f(){ var length=20; console.log(this.length); } f(); //10 我们以这个简单的代码块为例子,可以看到this在方法f里面,那么this在什么时候绑定呢?顺着代码来,可以看到,我们这里是一个声明的函数方法(函数定义的三种方法之一)。先声明,然后分配地址空间(初始化),再定义函数体,那么this是在定义函数体后就绑定了吗,看结果,显然不是,那么this只会是在被调用的时候才绑定的。
我们接着深度剖析一下,为什么是在调用时也就是运行时绑定的呢?
我们知道JS是一个脚本语言,很多东西都是简化的,JS在声明函数方面,把构造函数/方法/lambda/全局函数等隐式地混合在一起了。
我们这里要知道——当声明方法时需要找到对应的构造函数,让这个方法内部的 this 指向构造函数生成的实例;当声明构造函数的时候,this 则指向构造函数生成的这个实例;当声明 lambda 表达式的时候,不存在 this 指向,这时候 this 应按照闭包的规程逐次向上层作用域找,没找到则抛出异常。
在函数声明的时候,JS是不能通过静态分析去确定这到底是构造函数还是lambda等等,所以只能在动态调用方法时去绑定this。
额外提一点,在lambda方面,JS在ES6也是引入了箭头函数,有兴趣的可以了解一下。
this的绑定方式
一共有四种绑定方式(优先级从低到高),我们一一介绍。
1、默认绑定
我们知道了this是在调用时绑定的,那么绑定谁呢也就是说指向谁呢?具体的在下一部分讲。
很容易理解,默认绑定就是说this会有一个默认的绑定对象。
2、隐式绑定
这里也容易理解,this隐式地改变了原来的默认绑定。简单来说,就是偷偷地改变了绑定对象,不再是默认的。
3、显式绑定
既然是显式的,那么就不再是偷偷的了,而是明目张胆地用一些方法去改变this绑定的对象。那么是哪些方法呢,这里简单介绍一下:call,apply,bind。
var a={
name:"shan",
age:21,
sex:"male"
}
var b={
name:"sun",
getName:function (){
console.log("name:"+this.name+
" age:"+this.age);
}
}
b.getName.call(a); //name:shan age:21 可以看到call把函数里this的绑定对象从b转到了a,并且执行了该函数。call和apply的区别就是,call后面的参数是一个参数队列,apply后面则是合在一起的一个数组;至于bind,它和call的区别就是不会执行函数,而是返回一个新函数对象。
4、new绑定
new关键字是用来实例化的,this自然是指向实例化后的实例对象。
class gn{
name="shan";
constructor() {
console.log(this.name);
}
}
var b=new gn(); //shan
console.log(b.name); //shan 其实new关键字的实现原理也是涉及到了显式绑定方法,有兴趣的可以去了解一下。
this的指向
1、函数声明
function f(){ var length=100; console.log(this.length); } f(); //undefined
无对象调用时,this是一个默认绑定,指向的是默认的全局对象也就是window,还有下面这种情况:
var length=10;
function f(){
var length=100;
console.log(this.length);
}
f(); //10 这里涉及了一个数据声明的问题,有兴趣的可以去学习一下。
2、有对象调用
var a={
name:"shan",
getName:function(){
console.log(this.name);
}
}
a.getName(); //shan 有对象调用时,this隐式绑定了该对象。所以指向该对象,如上,返回的是shan。如下,可以对比一下:
var name="dan";
var a={
getName:function(){
console.log(this.name);
}
}
a.getName(); //undefined 可见,this绑定的不再是默认的window对象。
3、函数表达式
var name="shan";
var a=function(){
console.log(this.name)
}
a(); 这个也是无对象调用,所以是默认绑定,指向window。
4、实例化调用
这里参考上方的new绑定,this指向的就是实例化后的对象
var a=function(){
this.name="shan";
console.log(this.name);
}
var b=new a(); //shan
console.log(b.name); //shan
b.name="dan";
console.log(b.name); //dan 5、call、apply调用
这里参考上方的显式绑定,call、apply其实是一种上下文绑定
var a={
name:"shan",
age:21,
sex:"male"
}
var b={
name:"sun",
getName:function (){
console.log("name:"+this.name+
" age:"+this.age);
}
}
b.getNmae.apply(a); //name:shan age:21 6、箭头函数
var a={
name:"dan",
getName:function (){
setTimeout(()=>console.log(this.name),100)
}
}
a.getName(); 箭头函数本身是没有this关键字的,但是它会继承父环境,在这里体现出来的就是它继承了getName函数的this,指向了a对象。


京公网安备 11010502036488号