frontend-interview
frontend-interview copied to clipboard
Day18 - 介绍一下this指向4种形式
四种形式
bind
, apply
, call
, new
bind
指定函数执行时的 this
apply
指定函数执行时的 this
并调用函数
call
指定函数执行时的 this
并调用函数,跟 apply
的区别在于,从第二位起是函数的参数,而 apply
会把第二个数组参数的所有元素作为函数参数
new
在调用构造函数的时候将 this
指向创建的空对象
- 如果是一般函数,this指向全局对象window;
- 在严格模式下"use strict",为undefined.
- 对象的方法里调用,this指向调用该方法的对象.
- 构造函数里的this,指向创建出来的实例.
第一、如果一个函数中有this,但是它没有以对象方法的形式调用,而是以函数名的形式执行,那么this指向的就是全局对象; 第二、如果一个函数中有this,并且这个函数是以对象方法的形式调用,那么this指向的就是调用该方法的对象; 第三、如果一个函数中有this,并且包含该函数的对象也同时被另一个对象所包含,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,
如:
var obj = {
test;{
fun:function(){
console.log(this);
}
}
}
obj.test.fun();
第四、如果一个构造函数或以类方法中有this,那么它指向该构造函数或类创建出来的实例对象。
默认绑定 如果是一般函数,this指向全局对象window,在严格模式下"use strict",为undefined. 隐式绑定 对象的方法里调用,this指向调用该方法的对象. 显式绑定 对于call、apply、bind的这三种调用方式都是属于显式绑定,作用是通过显示传入一个对象,改变this的上下文为此对象。call和apply是直接改变上下文对象直接调用,而bind是返回一个已经显示绑定的上下文的函数 new绑定 构造函数里的this,指向创建出来的实例. 一般情况下:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
_Rainbow_Z: ⾸先,在默认情况下,this是指向全局对象的,⽐如在浏览器就是指向window。 其次,如果函数被调⽤的位置存在上下⽂对象时,那么函数是被隐式绑定的。 再次,显示改变this指向,常见的⽅法就是call、apply、bind,由于bind将obj绑定到f函数上后返回⼀个新函数,因此需要再在后⾯加上括号进⾏执⾏,这是bind与apply和call的 区别
_Rainbow_Z: 最后,也是优先级最⾼的绑定 new 绑定。 ⽤ new 调⽤⼀个构造函数,会创建⼀个新对象, 在创造这个新对象的过程中,新对象会⾃动绑定到Person对象的this上, 那么 this ⾃然就指向这个新对象。
_Rainbow_Z: 绑定优先级: new绑定 > 显式绑定 >隐式绑定 >默认绑定
-
一般的函数调用情况下,this指向全局。这是因为直接从内存中找到这个函数然后拿出来的时候,没有绑定所处的环境,所以采用默认的全局对象作为 this。
-
对象方法调用,obj.foo() ,这时候根据在对象属性里得到的函数的地址值来访问这个函数,这个函数拿出来的时候环境是处在这个对象内,所以 this 指向这个对象。
-
new 创建实例的时候,this 指向的是这个实例。
-
call,apply,bind 绑定 this,这时候 this 指向提供的对象。
a.如果是一般函数,this指向全局对象window;
b.在严格模式下"use strict",为undefined.
c.对象的方法里调用,this指向调用该方法的对象.
d.构造函数里的this,指向创建出来的实例.
- 默认情况this指向window,严格严格模式下指向undefined
- 对象调用时,只想当前对象
- 被call、apply、bind改变时,只想改变的对象
- 通过new创建新对象时默认指向新创建的对象
结论
- 如果是一般函数,this指向全局对象window;
- 在严格模式下"use strict",为undefined.
- 对象的方法里调用,this指向调用该方法的对象.
- 构造函数里的this,指向创建出来的实例
改变this指向的方法
改变this的指向并且执行调用函数 .call(), call(thisScope, arg1, arg2, arg3...) .apply(), apply(thisScope, [arg1, arg2, arg3...]);两个参数
而bind 改变this的指向,返回的是函数 .bind() bind(thisScope, arg1, arg2, arg3...)
this指向的四种情况:
- new,通过new构造函数里的this,指向新创建的实例
- call、apply、bind绑定this,this指向传递的对象;
- 默认情况下,全局上下文中this指向window,如果在严格模式时,this为undefined
- 方法执行时,通过.调用方法,则方法中的this指向该对象
一,判断this指向原则
函数中的this,指向函数运行时所在的对象(当前对象,而不是上层对象)。如果函数运行时没有依赖的当前对象,则this指向最上层对象(eg: window)。
二,this指向的几种情况
1. obj.fun()
中的this,指向当前运行的对象obj
fun 中的 this->obj ,自动指向.前的对象
var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
2. new Fun()
中的this,指向当前运行的对象(new出来的新实例对象)
Fun 中的 this->正在创建的新对象,new 改变了函数内部的 this 指向,导致 this 指向实例化的对象
function Person(name) {
this.name = name;
console.log(this); // Person {name: "song"}
};
var person = new Person('song');
console.log(person.name);// "song"
3. fun()
中的this,指向当前运行的对象window
this->最上层对象(eg: window),直接执行函数,this指向默认的最上层对象(eg: window)
function f() {
console.log(this);
}
f() // window
4. 函数中的函数的this,没有依赖的当前对象,默认指向window
this->最上层对象(eg: window),因为函数内函数,没有调用它的对象,所以只能指向默认的额window。
- 例1,函数中的赋值型函数
var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
}();
}
}
o.f1()
// Object
// Window (没有调用的它的对象了,所以只能指向默认的额window)
this指向的4种形式按优先级来说分别为
- new 关键字 this指向新创建的对象
- call,apply,bind绑定时,this指向绑定的对象
- 通过对象调用方法时,this指向调用方法的对象
- 没有调用对象时,指向全局
- 独立函数调用,例如getUserInfo(),此时this指向全局对象window
- 对象调用,例如stu.getStudentName(),此时this指向调用的对象stu
- call()、apply()和bind()改变上下文的方法,this指向取决于这些方法的第一个参数,当第一个参数为null时,this指向全局对象window
- 箭头函数没有this,箭头函数里面的this只取决于包裹箭头函数的第一个普通函数的this
- new构造函数调用,this永远指向构造函数返回的实例上,优先级最高。
当默认情况 this 指向 window 但严格模式下指向 undefined 当对象调用时指向当前对象 被call、apply、bind改变指向改变的对象 通过new创建新对象时新创建的对象 new -> call、apply、bind -> 对象调用 -> 默认情况
● web全局环境下的this指向window,nodejs环境为global对象 ● 非严格模式下,函数内部的this指向window,严格模式下,为undefined ● 对象的方法里调用,this指向调用该方法的对象 。被嵌套的函数独立调用时,this默认指向window ● 构造函数里的this,指向创建出来的实例 ● 此外,bind/call/apply 可以更改绑定this的指向
this 绑定有四条规则
默认绑定,隐式绑定,显示绑定,new绑定
this 是在函数被调用时才会绑定的,所以要确定函数中this绑定,我们首先需要找到函数的调用位置。 然后再根据以上四条规则,按照其优先级 new绑定>显示>隐式>默认 ,就能确定this 的绑定对象。
默认绑定
函数被直接调用,不符合其他三条绑定规则则会默认绑定,非严格模式下this指向全局对象,严格模式下指向undefined
function foo( ){
console.log( this.a )
}
var a =1 ;
foo( );//1
function foo( ){
"use strict"
console.log( this.a )
}
var a =1 ;
foo( );// TypeError: this is undefined
隐式绑定
调用位置有上下文对象,或者说调用函数被某个对象拥有或者包裹。引用到了对象的属性上,然后通过对象调用。 this会指向这个对象
function foo( ){
console.log( this.a )
}
var obj={
a:1,
foo:foo
} ;
obj.foo( );//1
obj的foo属性,指向了foo函数,通过obj.foo()调用,this指向了obj。
- 隐式丢失
但这里要注意,隐式丢失的情况,就是因为obj.foo其实也指向foo函数的引用,这个引用如果被赋值给另一个变量,再通过该变量调用,那就相当于跳过了obj,直接调用了,所以会造成隐式丢失。
function foo( ){
console.log( this.a )
}
var obj={
a:1,
foo:foo
} ;
var b=obj.foo;
b( ); // TypeError: this is undefined
以上,相当于全局直接调用foo函数,所以是默认绑定。 注意,函数作为参数传参给别的函数,也是一种隐式赋值,一样会发生隐式丢失的情况。
显示绑定
通过,apply(...),call(...) ,bind( )硬绑定,修改this指向
function foo( ){
console.log( this.a )
}
var obj={
a:1
} ;
foo.call(obj); //1
foo.apply(obj); //1
var bar=foo.bind(obj);
bar(3);//1
bind其实就是基于包裹了一层函数,内部再通过apply实现的硬绑定,解决上面说的this丢失问题,这章暂不细纠。
以上代码都将,foo中this指向了obj。
new
通过new的方式来调用函数,会创建一个新的实例对象,构造函数中的this也会指向这个新创建的对象。 new的方式改变this指向的优先级式最高的。
function foo( a){
this.a=a;
}
var b= new foo(2);
console.log(b.a);//2
总结
以上,我们知道了确认this绑定,需要知道调用位置,再按优先级从高到低,ew绑定>显示>隐式>默认,看匹配哪条规则,就能明确this指向。
- 方法调用模式,当一个函数作为一个对象的属性被调用,this指向该对象
var myObject = {
name: 'myobj',
myFunc: function() {
console.log(this.name) // myobj
}
}
myObject.myFunc()
- 函数调用模式,当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的。当这个函数被调用时,this绑定到全局对象
var name = 'window';
var myObject = {
name: 'myobj',
myFunc: function () {
console.log(this.name) // myobj 方法调用模式
var func = function() {
console.log(this.name) // window, 函数调用模式
}
func()
}
}
myObject.myFunc()
- 构造器调用模式,当一个函数使用new新建实例时,会将新创建的实例对象指向构造器函数的prototype,并且this指向该实例对象
var myObject = function(name) {
this.name = name
}
myObject.prototype.myFunc = function(){
console.log(this.name)
}
var obj = new myObject('objname');
obj.myFunc() // objname
- apply, call, bind调用模式,第一个参数会传递this指向的对象
var name = 'window'
var obj = {
name : 'obj'
}
var myFunc = function(){
console.log(this.name)
}
myFunc() // window
myFunc.bind(obj)() // obj
myFunc.apply(obj) // obj
myFunc.call(obj) // obj
全局上下文的this
严格/非严格模式全局上下文的this都指向window
函数上下文的this
场景 | this指向 |
---|---|
普通函数调用 | 严格模式默认指向undefined/非严格模式默认指向window |
对象中的函数调用模式 | 默认指向调用的对象 |
call/apply/bind 调用模式 | 默认指向第一个参数 |
构造函数调用模式(new) | 如果构造函数没有返回对象,就指向新对象,否则指向构造函数返回的对象 |
箭头函数调用模式 | this指向上层非箭头函数的this |
不同调用this的优先级
new 调用 > call/apply/bind > 对象上的函数调用 > 普通函数调用
1.如果是一般函数,this指向全局对象window; 2.在严格模式下"use strict",为undefined. 3.对象的方法里调用,this指向调用该方法的对象. 4.构造函数里的this,指向创建出来的实例.
https://juejin.cn/post/7054586334177919013/
this 对象是在运行时基于函数的执行环境绑定的 在全局函数中,this 指向 window,而当函数被作为某个对象的方法调用时,this 指向那个对象。 匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window。 箭头函数中没有this,this指向其所处的词法作用域 普通函数,在严格模式下为undefined
this指向,也即this绑定的4种形式如下:
- 默认绑定,指向window。在全局环境下的this指向window;普通函数定义后,执行时内部的this也指向window;回调函数内部,this也指向window;箭头函数例外,其内部this是定义它的环境下的this指向。
console.log(this); // window;
function foo(){
console.log(this);// window;
}
foo()
setTimeout(function(){
console.log(this); // window
},1000)
- 隐式绑定,指向调用函数的对象,如,对象内有函数属性,调用该函数,则this指向该对象。
let obj = {
foo:function(){
console.log(this); // obj
}
}
obj.foo()
- 显示绑定,通过call、apply或bind去修改this的指向,如下
function foo(){
console.log(this.a)
}
let obj = {
a:1
}
foo.call(obj);// 1
- new 构造函数绑定,通过new 构造函数创建一个新的实例,将构造函数内的this指向该实例,如下
function Dog(options){
this.name = options.name;
this.age = options.age;
}
dog1 = new Dog({name:'dog1',age:'1'})
console.log(dog1.name); // dog1
console.log(dog1.age); // 1
dog2 = new Dog({name:'dog2',age:'2'})
console.log(dog2.name); // dog2
console.log(dog2.age); // 2
结论
- 如果是一般函数,
this
指向全局对象window
- 在严格模式下(
use strict
),为undefined
- 对象的方法里调用,
this
指向调用该方法的对象 - 构造函数里的
this
,指向创建出来的实例
改变 this 指向的方法
call
call()
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。
func.call(thisScope, arg1, arg2, arg3...)
apply
apply()
方法调用一个具有给定 this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
func.apply(thisScope, [arg1, arg2, arg3...])
bind
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
func.bind(thisScope, arg1, arg2, arg3...)
- 如果是普通函数,this 指向全局对象,在浏览器是
window
,在 node 是global
- 如果是箭头函数,this 指向定义时外部环境的 this
- 如果是对象调用,则 this 指向该对象
- 如果是在构造函数或者Class中, this 指向构造出来的实例
- 如果是使用 bind、call、apply,this 指向函数的第一个值对应的对象
- 如果是在严格模式下,this 在函数外部指向 全局,在函数内部指向 undefined
this 这四种指向性问题,其实说的是一个函数被调用的四种方式:
- 一个函数可以作为函数被调用
- 可以作为方法被调用
- 可以作为构造函数被调用
- 也可以用call apply bind的方式去调用。
这四种调用方式会造成的是会有不同的this指向。如果你是用函数的方式去调用,那么this在严格模式下就是undefined,在普通模式下就是window。如果你是用方法的方式去调用,那么 this 指向的就是这个方法所属的那个对象。如果你是用构造函数去调用,那么this就是一个空对象。如果你是用call apply bind去调用,那么就是你指定this的值了。