《你不知道的JavaScript》阅读笔记(2)

152 阅读3分钟

《你不知道的JavaScript》阅读笔记(2)

一、关于this

结论一:this并不会指向函数本身

结论二:this只有在函数执行时才是确定的,它取决于函数的调用位置

1、绑定规则:

1⃣️、默认绑定

独立函数调用,直接在全局声明一个函数并且调用,则this指向全局,如果严格模式则this会指向undefined

2⃣️、隐式绑定

当函数具有上下文的时候,this会指向上下文,如下面事例就是指向的obj

function foo(){
	console.log(this.a)
}
const obj={
	a:1,
	foo:foo
}
obj.foo()

隐式丢失:如下代码,obj.foo其实本质上还是foo的引用给了bar,最后调用和独立调用没有什么区别,所有this遵守的是默认绑定

function foo(){
	console.log(this.a)
}
const obj={
	a:1,
	foo:foo
}
var a=2;
const bar=obj.foo
bar() //2

3⃣️、显式绑定

call,apply,bind,其中call、apply只有参数的形式不同,bind则是返回一个具有绑定对象上下文的函数,不会立即执行,bind被称为硬绑定

4⃣️、new 绑定

使用new来调用函数后,或者按面对对象的依赖来说就是通过构造函数new了一个对象,会发生三个步骤:

1、创建一个全新的对象

2、这个对象会被执行原型链接

3、这个新对象会绑定到函数调用的this

4、如果函数没有返回其他对象则会把这个新对象返回

第二步我们这边不做过多讲述以后会讲到,如下代码我们就会发现obj就是生成的新对象,这个新对象会绑定到构造函数调用的this,所以obj.a=1

function Foo(){
	this.a=1;
}
const obj=new Foo()

new可以修改已经被使用bind硬绑定的this,如下代码,使用new后新创建的对象会代替硬绑定的对象指向this

function foo(val){
	this.a=val
}
const obj={}
const bar=foo.bind(obj)
bar(2);
obj.a //2
const baz=new bar(3)
baz.a=3;

上述情况来进行柯里化

function foo(p1,p2){
	this.val=p1+p2
}
const baz=foo.bind(null,'p1');
const bar=new baz('p2') 
bar.val //p1p2

2、硬绑定在某些情况下传入的值会被忽略,比如你传入了null或者是undefined

function foo(){
	console.log(this.a)
}
var a=2;
foo.call(null) //2

3、间接引用,下面这种情况会遵循默认绑定

function foo(){
	console.log(this.a)
}
var a=3;
const p={
	a:4,
	foo:foo
}
const q={
	a:5,
	foo:foo
}
(p.foo=q.foo)()//3

4、软绑定:软绑定出现的意义是如果我们进行了硬绑定则我们无法修改this的指向(new除外),大大降低了函数的灵活性,软绑定就是让默认绑定的this不绑定window或者undefined,而是绑定我们指定的对象,如下代码

Function.prototype.softBind=function(obj){
	const fn=this
	if(typeof this !=='function'){
		throw new Error('this is not function')
	}
	const args=[].slice.call(arguments,1)
	var bound=function(){
			return fn.apply((!this||this===window)?obj:this,args.concat.apply(args,arguments))
	}
	bound.prototype=Object.create(fn.prototype)
	return bound
}
function foo(){
	console.log(this.a)
}
const obj={
	a:1
}
const bar=foo.softBind(obj)

setTimeout(bar,1000) //1
const obj2={
	a:3
}
bar.call(obj2)//3

5、箭头函数:保留上下文引用,如下

function foo(){
	return ()=>{
		console.log(this.a)
	  }
}
const obj1={
	a:1
}
const obj2={
	a:2
}
const bar=foo.call(obj1)
const baz=bar.call(obj2) //1

function zzz(){
	setTimeout(()=>{
	console.log(this.a)
},1000)
}
zzz.call(obj2) //2

上述代码箭头函数会保留foo()执行时的this指向,定时器里也会保留zzz()执行时的this指向,也就是说箭头函数会保留他的上下文,且箭头函数的this无法被显式修改的(new 也不行)