JavaScript基础知识: 作用域和闭包

本文详细讲解了JavaScript的块级作用域、自由变量、闭包概念,包括函数作为参数和返回值的应用,以及this关键字在不同场景下的行为。还介绍了bind和call方法的用法,以及闭包在实际开发中的数据隐藏和API设计。最后,剖析了原型中的this指向问题和bind方法的工作原理。
摘要由CSDN通过智能技术生成

一、作用域

在这里插入图片描述

1.1 块级作用域

// ES6 块级作用域
if (true) {
	let x = 10
}
console.log(x) // 报错

1.2 自由变量

  • 一个变量在当前作用域没有定义,但被使用了;
  • 向上级作用域,一层一层依次寻找,直到找到为止;
  • 如果到全局作用域都没找到,报错 xx is not undefined;

二、闭包

作用域应用的特殊情况,有两种表现:

  1. 函数作为参数被传递
  2. 函数作为返回值被返回
// 函数作为返回值
function create() {
  const a = 100
  return function() {
    console.log('a: ', a)
  }
}

let fn = create()
const a = 200
fn()  // 100
// 函数作为参数
function print(fn) {
  let a = 200
  fn()
}
let a = 100
function fn() {
  console.log(a)
}
print(fn) // 100
// 闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找
//      不是在执行的地方!!!
// 其实也不仅仅是闭包,是所有的自由变量的查找。。。。。。

三、this

this有这么几种使用场景,不是多复杂,而是使用场景较多。

  1. 作为普通函数
  2. 使用 call apply bind
  3. 作为对象方法去调用
  4. 在class方法中调用
  5. 箭头函数

this 取什么值,是在函数执行的时候确定,而不是定义的时候。

function fn1() {
  console.log(this)
}

fn1() // window

fn1.call({x: 100}) // {x: 100}
const fn2 = fn1.bind({x: 200})
fn2() // {x: 200}

// bind和call有点不一样,bind返回的是一个函数
const zhangsan = {
  name: '张三',
  sayHi() {
    console.log(this) // this即当前对象
  },
  wait() {
    setTimeout(function() {
      // setTimeout触发的函数执行,作为普通函数执行,window
      console.log(this) // this 是 window
    }, 10)
  }
}
zhangsan.sayHi()
zhangsan.wait()

在这里插入图片描述
上图中的箭头函数:箭头函数的this,永远取的是它上级作用域的this。

在这里插入图片描述
在这里插入图片描述

三、bind

bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj

在这里插入图片描述
手动实现bind
在这里插入图片描述
可以看到bind属于原型链中的
在这里插入图片描述
在这里插入图片描述

四、call

使用call方法,可以编写能够在不同对象上使用的方法。
call方法可以用来调用所有者对象作为参数的方法。
通过call,能够使用属于另外一个对象的方法。
比如下面,调用person对象的fullName方法,用于person1对象。

const person = {
  fullName: function() {
    return this.firstName + ' ' + this.lastName
  }
}

const person1 = {
  firstName: 'Bill',
  lastName: 'Gates'
}

const person2 = {
  firstName: 'Steve',
  lastName: 'Jobs'
}

const res = person.fullName.call(person1)
console.log(res) // Bill Gates

在这里插入图片描述

五、实际开发中的闭包

数据隐藏,只提供API,数据内部自己管理

// 闭包隐藏数据,只提供API
function createCache() {
  const data = {} // 闭包中的数据,被隐藏,不被外界访问
  return {
    set: function(key, val) {
      data[key] = val
    },
    get: function(key) {
      return data[key]
    }
  }
}

const c = createCache()
c.set('a', 100)
console.log(c.get('a')) // 100

六、原型中的this

class People {
  constructor(name) {
    this.name = name
  }

  eat() {
    console.log(`${this.name} eat sth`)
  }
}

class Student extends People {
  constructor(name, number) {
    // super:把名字给父类People,父类会帮我们处理,调用父类构造函数,但是学号number是学生特有的,自己处理
    super(name)
    this.number = number
  }
  sayHi() {
    console.log(`姓名: ${this.name}  学号: ${this.number}`)
  }
}
const xialuo = new Student('夏洛', 10010)
console.log(xialuo) // Student { name: '夏洛', number: 10010 }
console.log('........')
console.log(xialuo.sayHi()) // 姓名: 夏洛  学号: 10010
console.log(xialuo.__proto__.sayHi) // 会正确打印sayHi函数体,没问题

// [下行运行结果] 姓名: undefined  学号: undefined【this指向的问题,上面的this是xialuo,此行的this是xialuo.__proto__】
console.log(xialuo.__proto__.sayHi())
console.log(xialuo.__proto__.name) // undefined
console.log(xialuo.__proto__.number) // undefined
console.log(xialuo.__proto__.sayHi.call(xialuo)) // Student { name: '夏洛', number: 10010 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值