阅读 50

那些年你不知道的this

this-函数上下文

this的指向不仅由定义函数的方式和位置决定的,同时还严重受到函数调用方式的影响


作为函数直接被调用
  • 非严格模式:this指向全局上下文(window)
  • 严格模式:this指向undefined
function fn1() {};
fn1();

const fn2 = function () {};
fn2();
(function () {})()
复制代码
作为方法被调用
  • this指向调用对象(即宿主对象)
let my = {};
my.fn = function () {return this};
my.fn(); // my
复制代码
作为构造函数调用
  • this指向新创建的对象
function Fn() {
    this.my = "11"
    name = "1"
}

const fn = new Fn();
name; // "1"
fn.name; // undefined
fn.my; // "11"
复制代码

new操作符实现过程
  1. 在内存中创建一个新对象
  2. 这个对象内部的 [[ Prototype ]] 特性被赋值为构造函数的 prototype 属性
  3. 构造函数内部的 this 的指向被修改为这个新对象
  4. 执行构造函数内部的代码
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的对象

使用apply和call方法调用
  • 第一个参数不传或者传undefined,this默认指向调用对象
  • 反之,this指向第一个参数
const my = {};
function fn() {
    return this;
}
fn(); // window
fn.call(); // window
fn.call(1); // Number {1}
fn.call(my, 1, 2, 3); // my
fn.apply(); // window
fn.apply(1); // Number {1}
fn.apply(my, [1, 2, 3]); // my
复制代码

解决函数上下文问题

使用箭头函数绕过函数上下文
  • 箭头函数没有单独的this值,它的this与声明所在的上下文相同
const fn = {
    show: () => {
        return this
    }
}
let newFn = {};
newFn.fn = fn.show;
fn.show(); // window
newFn.fn(); // window
复制代码
使用bind方法
  • bind不会改变原始函数,而是创建一个全新的函数
  • 创建的新函数被绑定到指定对象上。不管如何调用该函数,this均被设置为对象本身。被绑定的函数与原函数行为相同
function fn() {
    return this;
}
const newFn = fn.bind({});
newFn(); // {}
newFn().call(window); // {}
fn(); // window
复制代码
参考

《JavaScript忍者秘籍2》

文章分类
前端
文章标签