js三座大山
一:函数式编程
js三座大山之函数1
js三座大山之函数-静态词法作用域
js三座大山之函数-运行时this的四种指向
二:面向对象编程
js三座大山之对象,继承,类,原型链
三:异步编程:
js三座大山之异步一单线程,event loope,宏任务&微任务
js三座大山之异步二异步方案
js三座大山之异步三promise本质
js三座大山之异步四-Promise的同步调用消除异步的传染性
js三座大山之异步五基于异步的js性能优化
js三座大山之异步六实现微任务的N种方式
js三座大山之异步七实现宏任务的N种方式
静态词法作用域作用域与运行时this
完整的描述应该为:变量的静态词法作用域与函数的运行时动态this。
有很多同学会将变量的作用域和函数的运行时this指向搞混淆其实这可以说是两个东西。作用域是修饰变量的。 例如function fn
fn即为指向函数的变量,作用域是指能够访问到这个fn的范围,这与代码的编写位置和声明方式有关,而this是指谁调用的fn例如obj.fn()
,this就是函数的调用者。
运行时this:
在JavaScript中,函数的this关键字是在函数被调用时确定的,而不是在函数被定义时确定的。这就是所谓的“运行时绑定”。this的值取决于函数的调用方式。
函数的调用方式有多种方式 但是this指向本质只有四种情况 指向全局
,指向上层
, 显示设置this
,指向实例对象
,
1. 指向全局
function greet() {
console.log(this); // 指向全局window 浏览器调用了green
}
greet()
2. 箭头函数指向上层:
没有自己的this
,arguments
,super
或 new.target
.
这些值由距离最近的外层作用域的非箭头函数决定
。
注意: 只有函数才能生成新的作用域
const obj = {
name: 'hahha',
run(){
const say = (name) => {
console.log(this); // this指向obj 因为run是一个函数 有自己的作用域
};
say();
}
}
obj.run()
再通过下面的例子深刻的理解下 只有函数才能生成新的作用域
。
const obj = {
name: 'hahha',
run:()=>{
console.log('run this', this)
// this指向全局window
// 因为run的上层是obj但是obj是一个对象没有自己的作用域
// 只有函数才能生成新的作用域 所以在向外层找 到全局环境。
},
}
obj.run()
3.显示设置this
当函数使用call
、apply
或bind
方法调用时,
this
被显式设置为传递给这些方法的第一个参数。
function myFunction() {
console.log(this);
}
myFunction.call({custom: 'object'}); // 输出:{custom: "object"}
4. 指向实例对象
- 对象方法:
var obj = {
greet: function() {
console.log(this);
}
};
obj.greet() // 指向obj
- 构造函数:
function Person(name) {
this.name = name;
console.log(this) // 指向新创建的对象 具体可以了解下new操作符的实现原理
}
var john = new Person('John');
小例子
哪个对象实际调用函数 this就指向哪个对象。注意不要被引用传递干扰了视线。
let obj = {
name: 'obj',
p1:{
name: 'p1',
p2:{
name: 'p2',
action(){
console.log(this.name)
}
}
}
}
obj.p1.p2.action() // 指向p2
const fn = obj.p1.p2.action;
fn() // 指向window
第一种方式,本质上是obj引用p1,p1引用p2 p2调用了action方法 所以this是指向p2的,因为p2是实际调用者。
第二种方式,类似于全局直接调用方法 所以this指向全局。