javascript 作用域和 this 绑定

首先需要说明的是,在 javascript 中,作用域和 this 绑定是两件事。

作用域

javascript 中的作用域是词法作用域(语法作用域、静态作用域)。词法作用域是在编译阶段就产生的,一整套函数内标识符的访问规则。也就是说,函数书写时在哪个作用域,使用时就能访问那个作用域的变量(直接通过变量名访问,而不是通过 this.identifierName 的方式访问)。

需要注意的是,箭头函数不会改变上述作用域规则,箭头函数会影响 this 的绑定规则。

验证代码如下:

let aa = 10;

function showInfo() {
    console.log(aa);
}

const showInfo2 = () => {
  console.log(aa);
};

function wrapper() {
  let aa = 100;
  function innerShowInfo() {
    console.log(aa);
  }

  return innerShowInfo;
}

function wrapper2() {
  let aa = 100;
  const innerShowInfo = () => {
    console.log(aa);
  };

  return innerShowInfo;
}

{
  let aa = 1000;
  setTimeout(showInfo, 1000);  // 10
}

{
  let aa = 1000;
  setTimeout(showInfo2, 1000);  // 10
}

{
  let aa = 1000;
  setTimeout(wrapper(), 1000);  // 100
}

{
  let aa = 1000;
  setTimeout(wrapper2(), 1000);  // 100
}

let obj = { bb: "this is obj", aa: 1000 };
showInfo.apply(obj);  // 10 {bb: 'this is obj'}
showInfo2.apply(obj);  // 10 Window
wrapper().apply(obj);  // 100 {bb: 'this is obj', aa: 1000}
wrapper2().apply(obj);  // 100 Window

this 绑定

在 es6 中函数有两种:通过 function 定义的函数(这里称为普通函数)、箭头函数。除非特殊指明,否则默认情况下我们说的函数指普通函数。

this 是函数发生调用时自动生成的一个量。this 不能被赋值。它代表的是调用这个函数的对象。在箭头函数中,这种情况为不同。箭头函数中没有 this 这个量。箭头函数中的 this 是依照词法作用域规则引用的父作用域的规则(按照此规则迭代直到找到一个对象)

当直接通过函数名调用(call)一个函数时,this 默认为 window(或者是 undefined 或其他值。不同引擎实现不一样)。

let aa = 10;

function showInfo() {
    console.log(aa, this);
}

const showInfo2 = () => {
  console.log(aa, this);
};

function wrapper() {
  let aa = 100;
  function innerShowInfo() {
    console.log(aa, this);
  }

  return innerShowInfo;
}

function wrapper2() {
  let aa = 100;
  const innerShowInfo = () => {
    console.log(aa, this);
  };

  return innerShowInfo;
}

{
  let aa = 1000;
  setTimeout(showInfo, 1000);  // 10 window
}

{
  let aa = 1000;
  setTimeout(showInfo2, 1000); // 10 window
}

{
  let aa = 1000;
  setTimeout(wrapper(), 1000); // 100 window
}

{
  let aa = 1000;
  setTimeout(wrapper2(), 1000); // 100 window
}


let obj = { bb: "this is obj", aa: 1000 };
let obj2 = { bb: "this is obj2", aa: 1000, showInfo };
let obj3 = { bb: "this is obj3", aa: 1000, showInfo2 };
let obj4 = { bb: "this is obj4", aa: 1000, show: wrapper() };
let obj5 = { bb: "this is obj5", aa: 1000, show: wrapper2() };

showInfo.apply(obj);  // 10 {bb: 'this is obj'}
showInfo2.apply(obj);  // 10 Window
wrapper().apply(obj);  // 100 {bb: 'this is obj', aa: 1000}
wrapper2().apply(obj);  // 100 Window
obj2.showInfo();  // 10 {bb: 'this is obj2', showInfo: ƒ}
obj3.showInfo2();  // 10 Window
obj4.show();  // 100 {bb: 'this is obj4', aa: 1000, show: ƒ}
obj5.show();  // 100 Window

wrapper()();  // 100 Window
wrapper2()();  // 100 Window

let caller = {name: 'this is name'};
wrapper.call(caller)();  // 100 Window
wrapper2.call(caller)(); // 100 {name: 'this is name'}

修改 this 指向

js 中有两种方式可以改变函数的 this 指定,分别是 applycall。二者的区别在于给函数传参的方式不一样。apply 以数组的形式传参,call 以不定参数的方式传参。

需要注意的是:这两种方式都不会改变箭头函数的 this 指向。因为箭头函数是依照词法作用域查找 this

function test() {
  console.log(arguments, this);
}

var name = "window name";
const test2 = ()=> {
  console.log(this.name);
}

let caller = {
  name: "caller"
}

// Arguments(2) ['01', '02', callee: ƒ, Symbol(Symbol.iterator): ƒ] {name: 'this is name'}
test.apply(caller, ['01', '02']);
// Arguments(2) ['01', '02', callee: ƒ, Symbol(Symbol.iterator): ƒ] {name: 'this is name'}
test.call(caller, '01', '02');

// window name
test2.apply(caller);
// window name
test2();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值