js上下文总结

01 context

任何方法,谁调用了它,则就是它的context。

这个和this的描述是一致的:

this最终指向的是调用它的对象

上下文就是this的指向。


02 不稳定的context

context在js的表现经常出现一些看似"不稳定"的情况,下面列出了一些"不稳定"。

(1) new和非new

下面是一道常见的面试题,问①和②分别输出什么结果?

function say() {
  console.log(this);
};

new say(); // ①
say(); // ②

虽然简单,却是对context最全的理解。
①输出 say 的实例
输出window吗?
显然我们凭借这段代码是无法做出对②的判断,因为我们根本不知道say()的运行环境是什么。


(2) 方法赋值

下面试题,将方法赋值给一个变量。

var name = "嗷嗷嗷";
var cat = {
  name: "喵",
  say: function() {
    console.log(this.name);
  }
}
var say = cat.say;
cat.say(); // ①
say(); // ②

结果:
①输出 喵
②输出 嗷嗷嗷

这里可以理解:因为say其实只是引用了一个函数,函数的运行依赖context,不同的context必然有不同结果。


(3) Event Loop

Event Loop又叫事件循环,由于js没有多线程,处理多个任务的时候,就需要采用异步队列(如定时器、I/O、Promse),或者利用浏览器的多线程启动多个任务(如ajax)。

那么异步任务,它的context就是浏览器当前打开的窗口了,即window。

下面是一个常见的面试问题:

function say() {
  setTimeout(function() {
    console.log(this);
  }, 0);
};
new say(); //①
say(); //②

①和②都输出window。


(4) 自执行函数

看下面一个问题:

function say() {
  (function() {
    console.log(this);
  })();
};
new say(); //①
say(); //②

①和②都输出window,这里也说明了自执行函数是被window调用。


03 闭包拯救世界

面对不稳定的context,闭包可以被动解决这些问题。
因为我们所期望的context,和闭包所表现的scope惊人相似。

于是我们纷纷这样做:

function say() {
  var _this = this;
  setTimeout(function() {
    console.log(_this);
  }, 0);
};
new say(); //①
say(); //②
function say() {
  (function(_this) {
    console.log(_this);
  })(this);
};
new say(); //①
say(); //②

上面做法用_this代替this,使得正常访问外层this。


04 bind来优化

对于用闭包来改变context的问题,不是很优雅。
用bind会更简洁。

实现是下面代码:

function say() {
  setTimeout(function() {
    console.log(this);
  }.bind(this), 0);
};
new say(); //①
say(); //②

通过bind直接改变当前函数的context,这样子做法是符合我们的阅读习惯的。


05 call和apply

call和apply又叫对象冒充,是在方法执行的时候,传入一个对象,顶替原有的context。

下面代码通过call,主动改变的执行函数的context。这在封装里面很重要。

<div onclick="clickdiv.call(this)">click me</div>
<script type="text/javascript">
function clickdiv() {
  console.log(this);
}
</script>

点击div,打印div元素。


06 箭头函数

可能意识到context这个问题,于是es6推出箭头函数。箭头函数采用词法作用域,这使得它和闭包的解决极为相似。

注意:arguments本身在箭头函数下,会指向外层函数的arguments (同this一样)。

function say() {
  setTimeout(() => {
    console.log(this);
  }, 0);
};
new say(); //①
say(); //②

这里①和②都正常输出了。


07 Arguments

Arguments也是context绕不过去的坎,Arguments是函数的内部对象,js在执行函数的时候,会根据Arguments初始化函数内部的变量。

arguments.callee可以访问到当前函数。
arguments.callee.caller可以访问调用当前函数的函数。

arguments上面特性严格模式下是不允许被使用的。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三和小钢炮

谢谢客官~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值