JavaScript – this的使用


通过阅读MDN和各类博客复习了一下javascript中this的使用方法,之后也会继续补充相关内容


什么是this

在传统的面向对象语言中this关键字指代了当前对象本身,或者是当前对象的一个实例,通过使用this可以对其中方法与属性进行调用

javascriptthis的指向是临时决定的,而不是在创建时决定的,大多数情况下函数的调用方式决定了this的指向

全局环境中的this

无论是否处于严格模式下,在全局环境中this都唯一指向全局对象window(浏览器下)

1
2
3
4
5
console.log(this === window); //true

var a = 3;
console.log(a); //3
console.log(this.a) //3

函数环境中的this

直接调用

  • 在非严格模式下直接调用函数,则函数中的this指向全局
  • 在严格模式下调用函数,则此函数中的this会被赋值为undefined
  • 非严格模式
    1
    2
    3
    4
    5
    function foo() {
    return this;
    }

    console.log(foo() === window); //true
  • 严格模式
    1
    2
    3
    4
    5
    6
    function foo() {
    "use strict"//声明严格模式
    return this;
    }

    console.log(foo() === undefined); //true

call(),apply()

在js中可以使用call()或者apply()函数来改变this的指向

1
2
3
4
5
6
7
8
9
10
11
var person = {
name: "sleepy-god",
age: 20
};

function say(job) {
console.log(this.name + ":" + this.age + "-" + job);
}

say.call(person, "student"); //sleepy-god:20-student
say-apply(person, ["student"]); //sleepy-god:20-student
  • Function.prototype中的call()apply()都可以改变this的指向,将this值绑定到调用中的特定对象
  • call()apply()作用相同,唯一的不同点就是apply()接收的参数必须时数组形式的

bind()

bind()的用法与call()apply()类似

this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的

function.bind(thisArg[, arg1[, arg2[, ...]]])

call()apply()不同的是call()apply()会自动执行函数,而bind()不会,bind()会返回一个函数引用

下面附上一段摘自MDN的源码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(!Function.prototype.bind){
(function() {
var slice = Array.prototype.slice;
Function.prototype.bind = function() {
var thatFunc = this,
thatArg = arguments[0];
var args = slice.call(arguments, 1);
if(typeof thatFunc !== 'function') {
throw new TypeError('Function.prototype.bind - ' +
'what is trying to be bound is not callable');
}
return function() {
var funArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs)
}
}
})()
}

过程解析:

  • Array.prototype.slice赋值给变量slice
  • bind()传入的第一个参数arguments[0]记录下来,这是要绑定的this,然后将后续参数保存到args变量中
  • bind()方法返回的是一个函数,funArgs就是将bind()传入的剩余参数和后续返回的函数执行时加入的参数进行拼接
  • 然后将this指向之前的第一个参数arguments[0]

关于面试中常见的手写call()和apply()方法题目

浏览了不少博客和文章,发现手写call(),apply(),和bind()是比较常见的面试题目,因此我也总结了一下call()apply()的方法

手动实现call()方法

1
2
3
4
5
6
7
8
9
10
11
Function.prototype.myCall = function(context) {
if(typeof context === 'undefined' || context === null) {
context = window
}

context.fn = this;
let args = [...arguments].slice(1);
let result = context.fn(...args);
delete context.fn
return result
}

手动实现apply()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Function.prototype.myApply = function(context) {
if(typeof context === 'undefined' || context === null) {
context = window
}

context.fn = this;
let args = arguments[1];
let result;
if(args) {
result = context.fn(...args)
} else {
result = context.fn()
}
delete context.fn;
return result
}

参考MDN相关词条:Function.prototype.bind