js基础(六) this

7/20/2017 javaScript面试

# 知识点一 this

# 原理

  1. 我们在 js 中主要研究的都是函数中的 this
  2. js 中的 this 代表的是当前行为执行的主体,js 中的 context 代表的是当前行为执行的环境(区域)
  3. this 是谁和函数在哪定义的和在哪执行的都没有任何的关系
  4. 如何区分this

# 使用场景

# 场景一 普通函数的调用

核心:普通函数的调用,this指向的是window,例如

function fn() {
  console.log(this)
}

fn()     // this ---> window
1
2
3
4
5

# 场景二 对象方法的调用

核心:对象方法的调用,this指的是该对象,且是最近的对象

  • 函数执行,首先看函数名前面是否有 . ,有的话. 前面是谁this 就是谁;没有的话this 就是 window ,例如
function fn() {
  console.log(this)
}
var obj = {fn: fn}

fn()     // this ---> window
obj.fn() // this ---> obj

function sum() {
  fn()   // this ---> window
}
sum()

var o = {
    sum: function() {
    console.log(this) // this ---> o
    fn() // this ---> window
  }
}
o.sum()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • 给元素的某个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的 this 是当前的元素
function fn() {
  console.log(this)
}
document.getElementById('div1').onclick = fn // this ---> #div1
document.getElementById('div1').onclick = function() {
  console.log(this) // this ---> #div1
  fn() // this ---> window
}
1
2
3
4
5
6
7
8

# 场景三 构造函数的调用

核心:构造函数的调用,this指的是实例化的新对象

在构造函数当中,类中(函数体中)出现的 this.xxx 中的 this 是当前类的一个实例

构造函数的公/私有方法this 查找步骤:

  1. 看方法执行的时候, . 前面是谁,this 就是谁
  2. 把函数体中的 this 替换成分析的结果
  3. 按照原型链的查找模式找到对应的值即可
function Fn() {
  this.x = 100;
  this.y = 200;
  this.getX = function() {
    console.log(`${this.x}`)
  }
}
Fn.prototype.getX = function() {
  console.log(`${this.x}`)
}
Fn.prototype.getY = function() {
  console.log(`${this.y}`)
}
Fn.prototype.setX = function(n) {
    this.x = n
}
var f1 = new Fn;

// 1.getX执行时,.前面是f1
// 2.console.log(`${this.x}`) --> console.log(`${f1.x}`)
// 3.f1的私有属性有x,即值为100
f1.getX() 

// 1.getX执行时,.前面是f1.__proto__即Fn.prototype
// 2.console.log(`${f1.__proto__.x}`) --> console.log(`${Fn.prototype.x}`)
// 3.f1.__proto__指向,Fn构造函数的原型Fn.prototype,Fn.prototype对象上没有属性x,继续往上一级Object的原型对象上查找,Object的原型对象也没有x属性,即值为undefined
f1.__proto__.getX() 

// 1.setX执行时,.前面是Fn.prototype
// 2.this.x = n --> Fn.prototype.x = n
// 3.Fn.prototype对象上没有属性x,即直接在Fn.prototype对象上增加x属性,值为300
Fn.prototype.setX(300) 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 场景四 apply和call调用

核心:apply和call调用,this指向参数中的对象

var name = 'f';
function fn(){
    console.log(this.name);
}
var f1 = {
    name:'f1',
}
var f2 = {
    name:'f2',
}

fn.call(f1);// f1
fn.call(f2);// f2
fn() // f
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 场景五 匿名函数的调用

核心匿名函数调用,指向的是全局对象 window,自执行函数this 的永远是 window

//①先用()包起来,然后再后面跟 (参数) 
(function(data){
    console.log(this, data);
})("222");

//②先后面跟(参数),然后再()包起来
(function(data){
    console.log(this, data);
}("333"));

//③正常函数格式,前面加 !|~|+|-
!function(data){
    console.log(this, data);
}("444");
~function(data){
  console.log(this, data);
}('555')
+function(data){
  console.log(this, data);
}('666')
-function(data){
  console.log(this, data);
}('777')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 场景六 定时器中的调用

核心:定时器中的调用,this指向的是全局变量window

var name = 'f';
var fn = setInterval(function(){
    var name = 'f1';
    console.log(this.name); // f
    clearInterval(fn);
},500);
1
2
3
4
5
6

# 场景七 箭头函数中的调用

核心:箭头函数内部的 this 是词法作用域,由上下文确定

箭头函数的this跟外层function的this一致,外层function的this指向谁,箭头函数的this就指向谁,如果外层不是function则指****向window

var obj={
    id:123,
    testFun:function(){
        var a= ()=>console.log(this)
        a();
    }
}
//testFun的this指的是obj,则箭头函数的this指向obj。
obj.testFun()  
//testFun的this指向window,箭头函数的this指向window。
obj.testFun.apply(null) 
1
2
3
4
5
6
7
8
9
10
11

# 案例一

说明

预解释步骤:首先声明变量,然后自上而下执行代码

函数执行步骤:首先形参赋值,然后预解释

var num = 20
var obj = {
  num: 30,
  fn:(function(num){
    this.num *= 3
    num += 15
    var num = 45
    return function() {
      this.num *= 4
      num += 20
      console.log(num)
    }
  })(num) // 把全局变量num的值20赋值给自执行函数的形参,而不是obj下的30,如果想是obj下的30,我们需要写obj.num
} 
var fn = obj.fn
fn()
obj.fn()
console.log(window.num, obj.num)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

image.png