目录
- 执行上下文
- 作用域链
- 变量对象
- 函数的length属性
- 函数的prototype属性
- 函数中的this指向
- 函数的call()方法
- 函数的apply()方法
- 函数的bind()方法
问题:
- 什么是JS的执行上下文?
- 执行上下文分为哪两种?
- 执行上下文是在什么时候创建的(全局、函数)
- 什么是变量对象
- 什么是函数的作用域链
- 闭包是什么?有什么用?
- 手写一个闭包
- 阅读推荐的2篇文章
- this是什么
- 如何判断this指向
- 如何修改函数调用时的this指向
- 预习bind()
执行上下文
执行上下文特指JS函数的运行环境。有两种执行上下文:
- 全局执行上下文:全局运行环境。即函数可以运行在全局环境内。全局执行上下文在脚本开始运行的时候创建。
- 函数执行上下文:函数运行环境。即函数可以运行在另一个函数内。函数执行上下文是在函数调用时创建的。
在每个函数内可访问的变量分为两种:
自身变量(定义在自身作用域内)
-
父级变量(定义在父级作用域内)
-
父级的父级变量
-
父级的父级的父级变量
。。。。。。。。。
全局变量
-
-
结论:
执行上下文是一个函数运行的环境。编辑器通过变量对象创建函数作用域。当我们在代码中读取某个变量a的时候:
- 编译器首先会在当前作用域下检查有没有声明a
- 如果找不到,编译器会向当前作用域的父级作用域查找
- 以此类推
- 最后找到全局,还是找不到,则会抛出未定义错误。
作用域链
作用域链就是为函数查找变量的规则。
作用域链就是为函数建立作用域的规则。
作用域链是通过执行上下文中的变量对象实现的。
<script>
//全局下可以访问:{a }
var a = 1
fn1()
function fn1(){
//fn1下可以访问:{b a}
var b = 2
fn2()
function fn2(){
/*
这里是函数执行上下文(作用域),创建作用域的过程分为两阶段:
1. 预解析()
2. 逐行解析
*/
//fn2下可以访问:{c b a }
var c = 3
console.log(a + b + c);
}
}
</script>
变量对象
定义:变量对象是任何一个执行上下文中内置的对象,每个变量对象中都存储当前执行环境可访问的变量和函数。
闭包
示例
<script>
function outer() {
var a = 0
function inner() {
a++
console.log(a)
}
return inner
}
// outer()
// fn()
var fn1 = outer()
var fn2 = outer()
var fn3 = outer()
// console.log(fn);
</script>
定义:闭包就是能访问到外部特殊变量的内部函数。
来自火狐开发者社区
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。
- 闭包是组合
- 必须有一个嵌套函数
- 必须有一个引用
用途: 闭包主要用来保护变量。
写闭包条件
函数嵌套
内部函数必须引用外部函数的特殊变量
必须将内部函数作为返回值返回。
闭包的声明周期
开始于外部函数调用时
结束于内部函数执行完毕
函数的length属性
Function.length
定义
返回形参的数量。不包含剩余形参。
length是一个只读属性。
示例
function fn(a,b,c,...rest){
console.log('hello')
}
console.log(fn.length);
- 如果没有形参,那么length返回0
- 不包含剩余形参
函数的prototype属性
除了箭头函数,所有的函数都有一个prototype属性。
定义
用于引用原型对象。
函数是一种特殊的对象
每个函数都有自己的原型对象
函数中的this
定义
this是一个关键字,指向一个对象。
-
指向哪个对象,取决于this的调用方式
方法调用:this指向对象
函数调用:this指向全局对象
独自使用:this指向全局对象
函数调用的严格模式下:this指向undefined
在事件调用中:指向调用事件的对象
在call() apply() bind()方法中: this指向任何值
方法调用, this 指向对象 |
---|
独自使用, this 指向 window. |
函数名调用, this 指向window. |
函数名调用,(严格模式), this 是 undefined . |
事件函数中 this 指向接收事件的元素 |
函数的方法 call() , apply() , and bind() 中的this指向任意对象。 |
示例:独自使用
console.log(this)//window
示例:函数调用
function fn(){
console.log(this)//window
}
window.fn()
'use strict'
function fn() {
console.log(this)//undefined
}
fn()
示例:事件调用
<button onclick="this.style.display='none'">Click to Remove Me!</button>
示例:方法调用
const person = {
firstName: "John",
lastName: "Doe",
id: 5566,
fullName : function() {
console.log(this)
}
};
console.log(person.fullName())//person</pre>
function.call(obj,arg1,arg2,...,argN)
定义
Call()方法用于间接调用函数
用法1:当没有参数时间接调用函数等价与直接调用
function fn(){
console.log(this);
}
fn()//直接调用
fn.call()//间接调用
用法2:当传入第一个参数时,就等于修改了this指向。第一个参数可以是任意对象。
let obj = {x:1}
function fn(){
console.log(this);
}
// fn()//直接调用
fn.call(obj)//间接调用
用法3:call方法的第2个参数用于设置实参
let obj = {x:1}
function fn(a,b){
console.log(a,b);
console.log(this);
}
// fn(1,2)//直接调用
fn.call(obj,1,2)//间接调用
fn.call(obj,...[1,2])//间接调用
function.apply(obj,[arg1,arg2,...,argN])
Call()方法用于间接调用函数,与call()方法不同之处是,第二个参数是数组。
函数的bind()方法
定义
在函数fn上调用bind()方法:会创建/返回一个新函数,称为绑定函数。当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。