每天3小时学前端之JS-第21天-面向对象

147 阅读3分钟

此系列体验视频教程

点击观看:哔哩哔哩

this的各使用场合

1、全局环境

全局环境的this,指的是window

function fn() {
  console.log(this === window);
}
fn() // true 本质原因是因为fn是由window对象调用的
window.fn() // true 
console.log(this === window); // true

2、构造函数

构造函数中的this,指的是实例对象

function Fn(p) {
  this.bar = p
  console.log(this);
}
var obj1 = new Fn('obj1')
var obj2 = new Fn('obj2')

3、对象的方法

如果对象的方法里面包含this,this指向方法运行时所在的对象。将方法赋值给另一个对象的方法,就会改变this的指向

var obj1 = {
  bar: 1,
  fn: function () { // 这里保存的只是函数的地址,从作用域层面去考虑,跟放在全局没有什么区别。
    console.log(this.bar);
  }
}
obj1.fn() // 1
var obj2 = {
  bar: 2
}
obj2.fn = obj1.fn // 将一个对象的方法作为地址赋值给另一个对象属性的话,那么调用此函数的对象一旦变化,this指向也就跟着变化了。
obj2.fn() // 2

var bar = 3
var fn = obj1.fn
fn() // 3

对象的方法中this的更复杂的情况

var bar = 1;
var obj = {
  bar: 2,
  fn: function () {
    console.log(this.bar);
  },
};
obj.fn(); // 2
(obj.fn = obj.fn)(); // 1
(obj.fn = function () {
    console.log(this.bar);
})(); // 1
(function () {
    console.log(this.bar);
})() // 1

// (true || obj.fn)(); // 报错
(false || obj.fn)(); // 1
(true && function () {
    console.log(this.bar);
})(); // 1

(1, obj.fn)(); // 1 
(1, function () {
    console.log(this.bar);
})(); // 1
// 前面小括号最终返回的是一个函数的地址。后面再跟着小括号相当于直接调用此函数,并没有经过obj进行调用

// this不在对象第一层的情况,这时的this只是指向当前一层的对象,而不会继续指向更上一层。
var bar = 1
var obj = {
  bar: 2,
  o: {
    bar: 3,
    fn: function () {
      console.log(this.bar);
    }
  }
}
obj.o.fn() // 3

var o = {
  bar: 3,
  fn: function () {
    console.log(this.bar);
  }
}
var obj = {
  bar: 2,
  o: o
};
(obj.o).fn() // 3
o.fn() // 3

var bar = 4
var fn = obj.o.fn // 赋值给全局变量,this依然指向全局
fn() // 4

// 所以一般为了保持this指向不变,都会连同调用函数的对象一起赋值给一个变量
var obj2 = obj.o
obj2.fn() // 3

this指向问题与解决

// 多层函数中的this的指向
var bar = 1
var obj1 = {
  bar: 2,
  fn1: function () {
    console.log(this);
    var that = this
    var fn2 = function () { // 此立即执行函数是自己执行的,相当于在全局执行
      console.log(that.bar);
    }()
  }
}
obj1.fn1() // 2

function temp() {
  console.log(this.bar);
}
var bar = 1
var obj1 = {
  bar: 2,
  fn1: function () {
    var fn2 = temp()
  }
}
obj1.fn1() // 1

// 回调函数中this指向的问题
var obj2 = {
  bar: 1,
  fn: function () {
    console.log(this.bar);
  }
}
obj2.fn()

var bar = 2
function fn(f) {
  f()
}
fn(obj2.fn) // 2

var obj3 = {
  bar: 3,
  fn: function (f) {
    f()
  }
}
obj3.fn(obj2.fn) // 2

如何固定this指向

var bar = 1
var obj = {
  bar: 2
}
function fn() {
  console.log(this.bar);
}
fn() // 1
fn.call(obj) // 2 call方法可以改变前面函数内部的this指向,使前面函数的this固定指向call函数的参数(对象)

// call方法的参数,应该是一个对象,如果参数为空、null、undefined,则默认传入全局对象window
fn.call()
fn.call(null)
fn.call(undefined)
fn.call(window)

// 回调函数中this指向的问题
var obj2 = {
  bar: 1,
  fn: function () {
    console.log(this.bar);
  }
}
obj2.fn() // 1

function fn2() {
  obj2.fn.call(obj2)
}

var bar = 2
function fn(f) {
  f()
}
fn(fn2) // 1

var obj3 = {
  bar: 3,
  fn: function (f) {
    f()
  }
}
obj3.fn(fn2) // 1

// 多层函数中的this的指向问题
var bar = 1
var obj1 = {
  bar: 2,
  fn1: function () {
    var fn2 = function () {
      console.log(this.bar);
    }.call(obj1)
  }
}
obj1.fn1() // 2

var obj = {
  x: 1,
  y: 2
}
function fn(x, y) {
  console.log(x, y);
  console.log(this.x + this.y + x + y);
}
fn.call(obj, 10, 16) // call还可以接收更多的参数,从第二个开始往后的参数都会传递到call前面的函数中,作为函数的参数。

// call转换类数组对象为数组
var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
// var arr = ['a', 'b', 'c', 'd']
// var result = arr.slice()
// console.log(result);
var result = [].slice.call(obj)
console.log(result);