AboutFE
AboutFE copied to clipboard
18、This问题
this是JS的关键字、代表函数运行时候生成的一个内部对象、只能在函数内部用。
函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。
- 情况一:纯粹的函数调用 函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。
function test(){
this.x = 1;
alert(this.x);
}
test(); // 1
// 明this就是全局对象,对代码做一些改变:
var x = 1;
function test(){
this.x = 0;
}
test();
alert(x); //0
- 情况二:作为对象方法的调用 函数还可以作为某个对象的方法调用,这时this就指这个上级对象
function test(){
alert(this.x);
}
var o = {};
o.x = 1;
o.m = test;
o.m(); // 1
- 情况三 作为构造函数调用 所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。
function test(){
this.x = 1;
}
var o = new test();
alert(o.x); // 1
// 为了表明这时this不是全局对象,对代码做一些改变:
var x = 2;
function test(){
this.x = 1;
}
var o = new test();
alert(x); //2 表明全局变量x的值根本没变。
- apply调用 函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数
var x = 0;
function test(){
alert(this.x);
}
var o={};
o.x = 1;
o.m = test;
o.m.apply(); //0 apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。
// 如果把最后一行代码修改为 o.m.apply(o); //1 运行结果就变成了1,证明了这时this代表的是对象o
js中this的指向,如何改变,call和apply和bind的区别
在JavaScript中this可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境情况
1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(非严格模式,在严格版中的默认的this不再是window,而是undefined)
2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。#### 3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
// 作为对象方法调用
var test = {
a : 5,
b : 6,
sum : function () {
return this.a + this.b; // 此处this = test
}
}
alert(test.sum()); // 11// 作为函数调用
a = 4;
b = 3;
function sum(){
return this.a + this.b; // 此处this = window
}
alert(sum()); // 7
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
对于构造函数,this会指向new出来的实例
function Fn(){
this.user = "萌爷";
}
var a = new Fn();
console.log(a.user); //萌爷如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn()
{
this.user = '萌爷';
return 1;
}
var a = new fn;
console.log(a.user); //萌爷function fn()
{
this.user = '萌爷';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined如何改变
new操作符会改变函数this的指向问题 首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。
apply或call,bind
- cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b) bind与apply、call最大的区别就是:bind不会立即调用,其他两个会立即调用,如果多次调用bind,那么多出来的次数都是无效的都是用来改变函数的this对象的指向的,第一个参数都是this要指向的对象,都可以利用后续参数传参。
将上述一个例子改造一下
var a = {
user:"萌爷",
fn:function(){
console.log(this.user); //萌爷
}
}
var b = a.fn;
var c = b.bind(a);
c();
https://juejin.im/post/5c0c87b35188252e8966c78a
总结
如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。 找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。
- new 调用:绑定到新创建的对象,注意:显示return函数或对象,返回值不是新创建的对象,而是显式返回的函数或对象。
使用new操作符调用函数,会自动执行以下步骤。
- 创建了一个全新的对象。
- 这个对象会被执行[[Prototype]](也就是__proto__)链接。
- 生成的新对象会绑定到函数调用的this。
- 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
- 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。
- call 或者 apply( 或者 bind) 调用:严格模式下,绑定到指定的第一个参数。非严格模式下,null和undefined,指向全局对象(浏览器中是window),其余值指向被new Object()包装的对象。
call就是改变函数中的this指向为thisArg,并且执行这个函数,这也就使JS灵活很多。严格模式下,thisArg是原始值是值类型,也就是原始值。不会被包装成对象 bind和call和apply类似,第一个参数也是修改this指向,只不过返回值是新函数,新函数也能当做构造函数(new)调用
- 对象上的函数调用:绑定到那个对象。
- 普通函数调用: 在严格模式下绑定到 undefined,否则绑定到全局对象。
ES6 中的箭头函数:不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用域来决定this, 具体来说, 箭头函数会继承外层函数,调用的 this 绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window)。 这其实和 ES6 之前代码中的 self = this 机制一样。 DOM事件函数:一般指向绑定事件的DOM元素,但有些情况绑定到全局对象(比如IE6~IE8的attachEvent)。
一定要注意,有些调用可能在无意中使用普通函数绑定规则。 如果想“ 更安全” 地忽略 this 绑 定, 你可以使用一个对象, 比如ø = Object.create(null), 以保护全局对象。
面试官考察this指向就可以考察new、call、apply、bind,箭头函数等用法。从而扩展到作用域、闭包、原型链、继承、严格模式等。这就是面试官乐此不疲的原因。