JS中this指向问题

-this四种绑定方式 #

  • 1.默认绑定规则
  • 2.隐式绑定规则
  • 3.显示绑定规则bind、call、apply
  • 4.new 绑定

优先级:4 > 3 > 2 > 1

1、默认绑定规则

默认绑定规则this指向window

1.1 全局环境

<script type="text/javascript">
	console.log(this === window);  //true
  console.log({} === {}) //false
</script>	

1.2 函数独立调用

this指向window

1.2.1 普通函数

<script type="text/javascript">
  //函数独立调用
	function test(){
		console.log(this === window); //true
	}
	test();//等价于window.test()
</script>	

1.2.2 立即执行函数

所有立即执行函数this指向window(执行环境是浏览器环境)

(function(){
		console.log(this);//window
})()

(function(){
		console.log(this);//window
}())

2、隐式绑定规则

隐式绑定规则谁调用this指向谁

2.1 普通隐式绑定

  • 每一个函数执行,都会产生自身的this,
  • this编译时不产生,执行时产生
  • 他们的指向可能相同,但不是同一个this
<script type="text/javascript">
	var a =0;
	var obj = {
		a:2,
		foo:function(){
			console.log(this); //obj
			function test(){
				console.log(this); //window
			}
			test(); //函数独立调用
		}
	}
	obj.foo(); //obj调用foo()
</script>

2.2 闭包中this指向

产生闭包:当函数执行的时候,导致函数被定义,并抛出

<script type="text/javascript">
	var a =0;
	var obj = {
		a:2,
		foo:function(){
			//console.log(this); //obj
			function test(){
				console.log(this); //window
			}
			return test; 
		}
	}
	obj.foo()();  
	//obj.foo() => return test();
	//obj.foo()(); => test()//函数独立调用
</script>

2.3 隐式丢失

<script type="text/javascript">
	var a =0;
	function foo(){
		console.log(this); //window
	}
	var obj = {
		a:2,
		foo:foo
	}
	obj.foo(); //obj
	
  //隐式丢失或者理解为独立调用
	var bar = obj.foo;
	bar(); //window
	// var bar = foo;
	// bar();
</script>

2.4 函数赋值

s<script type="text/javascript">
	var a =0;
	function foo(){
		console.log(this); //window
	}
	function bar(fn){
		console.log(this); //window
		fn(obj);
		// fn.bind(obj)();
		// new fn();
	}
	//父函数是有能力决定子函数的this指向的
	var obj = {
		a:2,
		foo:foo
	}
//预编译的过程中,实参被赋值为形参:(值的拷贝过程,浅拷贝)
	bar(obj.foo);
</script>	

2.5 父函数是有能力决定子函数的this指向的

父函数api中定义的

var arr = [1,2,3]
//回调函数
arr.forEch(function(item,index,arr){
	console.log(this) //window
})

arr.forEch(function(item,index,arr){
	console.log(this) //obj
},obj)

3、显示绑定规则

  • bind、call、apply
<script type="text/javascript">
	var a = 0;
	function foo(a,b,c,d){
		// console.log(this);
		console.log(a,b,c,d);
	}
	var obj = {
		a:2,
		foo:foo
	}
	var bar = obj.foo;
	
	obj.foo(1,2,3,4);
	bar.call(obj,1,2,3,4);
	bar.apply(obj,[1,2,3,4]);
	bar.bind(obj)(1,2,3,4);
	
	bar.call(undefined,2,3,4); //window
	bar.apply(null,[1,2,3,4]); //window
</script>

4、new 绑定

<script type="text/javascript">
	function Person(){
		var this = {};
		this.a = 1;
		return this; //指向person
	}
	
	var person = new Person();
	// console.log(person);
	
</script>

5、4种方式优先级

  • 1.默认绑定规则
  • 2.隐式绑定规则
  • 3.显示绑定规则bind、call、apply
  • 4.new 绑定
  • 4 > 3 > 2 > 1
<script type="text/javascript">
	function foo(b){
		this.a = b;
	}
	var obj1 = {};
	var bar = foo.bind(obj1); //foo的this指向obj1
	bar(2); //obj1的this.a=2
	
	console.log(obj1.a) //2
	var baz = new bar(3);//baz是foo的浅拷贝 
//new 用来实例化构造函数
//返回了一个新实例对象baz,baz的this指向自己,这个实例和obj1没有关系
	console.log(obj1.a); //2
	console.log(baz.a); //3
</script>

6、箭头函数this指向

箭头函数本身是没有this的,其this指向由其外层作用域决定,它里面的this其实是拿的父级作用域的this

所有绑定规则全部不适用于箭头函数

var a = 0
function foo(){
	console.log(this) //obj
	var test = ()=>{
		console.log(this) //obj
	}
  test()
}
var obj1 = {
  a:1,
  foo:foo
}
var obj = {
  a:2,
  foo:foo
}
obj1.foo()
obj1.foo()()//默认绑定对箭头函数无效
var bar = foo().call(obj2) //window

箭头函数不允许作为构造函数使用

var foo = ()=>{
	console.log(this)
}
new foo()
//报错,箭头函数不允许作为构造函数使用

7、this指向的使用

code

 <script>
     var name = 'window'
     var obj1 = {
         name: '1',
         fn1: function () {
             console.log(this.name)
         },
         fn2: () => console.log(this.name),
         fn3: function () {
             return function () {
                 console.log(this.name)
             }
         },
         fn4: function () {
             return () => console.log(this.name)
         }
     }
     var obj2 = {
         name: "2"
     }
     obj1.fn1(); //1
     obj1.fn1.call(obj2) //2

     obj1.fn2();  //window
     obj1.fn2.call(obj2) //window

     obj1.fn3()()  //window
     obj1.fn3().call(obj2) //2
     obj1.fn3.call(obj2)() //window

     obj1.fn4()() //1
     obj1.fn4().call(obj2) //1
     obj1.fn4.call(obj2)() //2
</script>

code

<script>
    function getName() {
        //全局方法在编译时被提升到最上面,之后被4覆盖
        console.log(5)
    } 
    function Foo(){
        getName = function (){
            console.log(1)
        };
        return this
    }
    Foo.getName = function () {
        console.log(2)
    };
    Foo.prototype.getName = function () {
        console.log(3)
    };
    var getName = function() { //表达式
        console.log(4)
    }
    // function getName() { //函数声明
    //     //函数声明编译时被提升到最上面,之后被4覆盖
    //     console.log(5)
    // } 
    
    console.log(Foo())
    Foo.getName();  //2
    getName();  // 4 5=>4(先走5最后4覆盖了5)
    Foo().getName(); //全局的getName被重写成1 5=>4=>1
    getName();//1    5=>1

    new Foo.getName(); //2
    new Foo().getName() //3
    new new Foo().getName() //3
</script>
posted @ 2020-08-14 23:19  Daeeman  阅读(299)  评论(0编辑  收藏  举报