JavaScript学习笔记三

作用域和闭包

一、this 的不同应用场景,如何取值

answer:

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

二、手写bind函数

调用bind函数会返回一个新的函数
answer:

// 模拟 bind,这个与写jQuery的插件一样(jQuery.prototype.dialog=function(info){})
Function.prototype.bind1 = function () {
	//因为我们不知道有多少个参数传进来,所以我们把传入的参数变成数组,而传入的参数是列表形式的
    // 将参数拆解为数组,列表变数组
    const args = Array.prototype.slice.call(arguments)

    // 获取 this(数组第一项)
    const t = args.shift()

    // this表示fn1.bind(...) 中的 fn1
    const self = this

    //bind是要返回一个函数的!!! 所以返回一个函数
    return function () {
        return self.apply(t, args)
    }
}
//参数情况
function fn1(a, b, c) {
    console.log('this', this)	//第一个参数
    console.log(a, b, c)		//第2-4参数
    return 'this is fn1'
}
//第一个参数是this,第二个是a,第三个是b,第四个是c
const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
const res = fn2()
console.log(res)

注释:
在这里插入图片描述

三、实际开发中的闭包应用场景,举例说明

answer
不通过set或者get没有办法赋值或者获取什么,例如data,若没有set无法给data赋值,没有get无法获取data的内容

// 闭包隐藏数据,只提供 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') )

四、JS创建10个<a>标签,点击的时候弹出对应的序号

answer

let a
for (let i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}

注释:
i:不可以和a一起定义,因为:
当i与a一起定义为全局变量时,/标签创建是十几秒就会创建完成,此时i已经成为10了,而我们还没有点击标签,所以当我们点击标签的时候弹出的都是10;
所以:i不可以是全局变量,只能定义成块级作用域,每次点击的时候,i只能从块级中找,超出块的范围是无效的

五、作用域和自由变量(knowledge point

1、作用域

在这里插入图片描述

①、全局作用域

就是不会受到什么约束,window对象,document对象都可以使用

②、函数作用域

在一个函数中定义,只能在函数中使用,超出函数就不可以使用

③、块级作用域(ES6新增)

在这里插入图片描述就是在if、for、while等这些语句后面的{ }里定义变量,该变量只能在这个块里面使用,超出范围就报错

2、自由变量

  1. 一个变量在当前作用域没有定义,但被使用了
  2. 此时要向上级作用域,一层一层依次寻找,直至找到为止(感觉很像英语的就近原则!!)
  3. 如果到全局作用域都没有找到,则会报错xx is not defined

六、闭包

自由变量的查找,是在函数定义的地方,向上级作用域查找

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

1. 函数作为参数被传递

函数在此处定义好后,被当成参数传到另一地方使用

函数作为返回值
function create() {
    const a = 100
    return function () {
        console.log(a)
    }
}

const fn = create()
const a = 200		//这个和上面的a=100是不一样的
fn() 				// 100

注释:
fn()中的a,是个变量,按照作用域的范围一层一层网上找

2. 函数作为返回值被返回

函数在此处定义好后,被返回到另一个地方执行

// 函数作为参数被传递
function print(fn) {
    const a = 200
    fn()
}
const a = 100
function fn() {
    console.log(a)
}
print(fn) 		// 100

注释:
print(fn):这个fn就是上面的fn()函数
fn()中的a是一个变量,要从作用域角度找,fn中没有,则到上一级,就是a=100中找到

七、this

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

1. 作为普通函数被调用

直接返回window

2. 使用call 、 apply 、 bind 被调用

传入什么就绑定什么

3. 作为对象方法被调用

返回对象本身

4. 在class 方法中调用

返回实例本身

5. 箭头函数

返回上级作用域的本身

//1. 作为普通函数被调用
function fn1(){
	console.log(this)
}
fn1()				//window

// 2. 使用call 、 apply 、 bind 被调用
fn1.call({x:100})	//{x:100}

const fn2 = fn1.bind({x:222})
fn2()			//{x:222}

// 3. 作为对象方法被调用
const zhangsan = {
	name : "zhangsanOk",
	sayHi(){
		//this 就是当前对象
		console.log(this)
	},
	wait(){
		setTimeout(function(){
			//this === window
			//这个setTimeout不是zhangsan.sayHi()这种执行的,而是setTimeout本身触发执行的
			console.log(this)
		})
	}
	// 4. 箭头函数
	waitAgain(){
		setTimeout(()=>{
			//this 就是当前对象
			console.log(this)
		})
	}
//5、在class 方法中调用
class People{
	constructor(name){
		this.name = name
		this.age = 20
	}
	sayHi(){
		console.log(this)
	}
}
const zhang = new People('张三')
zhang.sayHi()					//zhang对象
}

注释:
bind:会返回一个新的函数来执行,例如上面的,fn1.bind({x:222})会返回一个新的fn1函数

箭头函数:箭头函数只会调用上级作用域所指的this,本身的this不会调用,这就是wait()与waitAgain()的区别

call()和apply():都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。apply和call方法的第一个参数都是特定的作用域第二个参数不同,apply第二个参数可以是Array的实例,也可以是arguments对象。call方法需要逐个列出需要传递的参数。

联系xialuo那个例子:(this 的区别)
在这里插入图片描述为什么两个不一样的输出?
因为:xialuo.sayHi():对象是xialuo
xialuo.proto.sayHi():对象是xialuo.proto
在这里插入图片描述所以我们执行xialuo.sayHi():时,有点类似于再次绑定(如下)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值