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

一、作用域

在这里插入图片描述

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 }

猜你喜欢

转载自blog.csdn.net/GY_U_YG/article/details/125286585
今日推荐