介绍对于普通函数,可以理解为this 永远指向 调用 包含 自己(this本身) 的 函数 对应的对象。对于箭头函数,箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。 this 的指向,一般来说:this 永远指向最后调用它的那个对象this被调用时的五种情况:
1.作为对象方法被调用指向的是当前调用设个普通函数的对象,如下,this指向objfunction
sayHi() {
console.log("Hello,", this.name);
}
let person2 = {
name: "小万",
sayHi: sayHi
};
let person1 = {
name: "张三",
sayHi: sayHi
};
person1.sayHi();//Hello, 张三
person2.sayHi();//Hello, 小万Tips:那如果有链式调用的情况呢?this会绑定到哪个对象上?function sayHi() {
console.log('Hello,', this.name)
}
var person2 = {
name: '小万',
sayHi: sayHi
}
var person1 = {
name: '张三',
friend: person2
}
//如果person2里面没有name属性也不会调用person1里面的name,而是输出undefined
person1.friend.sayHi() // Hello, 小万这里也印证了开头的那句话:this 永远指向最后调用它的那个对象2. 作为普通函数被调用时this指向全局对象window没有明显的调用者的时候,其实是Window在调用Window.fn() 等价于fn()严格模式下 this被规定不会指向全局 则是undefinedwindow.name = 'window'
function sayHi() {
console.log("Hello,", this.window,this);
}
sayHi()可以看到。打印出的结果:this就是Window对象
赋值后调用的情况var name = "1999";
var obj = {
name: "are you ok",
show : function() {
return function(){
console.log(name,this.name,this===window);
}
}
};
var foo1 = obj.show();
foo1(); //1999 1999 true这里调用foo1的是Window,这里的 obj.show() 返回的是一个匿名函数所以 最后执行的 foo1()== window.foo1(), 函数foo1里面的 this.name 指向 window.name,所以最终输出 China。3.作为构造函数被调用时原型对象里面的this指向实例对象关于构造函数中this作用,构造函数原来初始化对象, new在构造函数中的作用:在内存中创建一个新的对象让this指向这个对象在构造函数里面的这个代码,给这个新对象添加属性和方法返回这个新对象,所以构造函数一般都是不用return返回的构造函数里的this指向 new创建的实例化对象(没有return的情况下),如果构造函数内出现了return,并且是一个object对象,那么最终的运算结果返回这个对象,只要构造函数不返回数据或者返回基本数据类型 this仍然指向实例function Person() {
this.name = "张三";
return {
name: "李四"
};
}
//因为使用了return,这里new出来的是对象{name: "李四"},所以this指向这个对象person.name等价于this.name,也即李四
let person = new Person();
console.log(person.name);//李四4.箭头函数里面的this箭头函数的 this 不会被改变,所以当前函数是箭头函数,那么就不用再看其他规则了。箭头函数的 this 是在创建它时外层 this 的指向。他只会从自己的作用域链上一层继承this,箭头函数的 this 是在创建它时外层 this 的指向,他没有自己的this 。这里的重点有两个:这里的重点有两个:创建箭头函数时,就已经确定了它的 this 指向。箭头函数内的 this 指向外层的 this。注:箭头函数不能当做构造函数,所以不能与 new 一起执行this.age = 20;
var obj = {
age: 18,
fn: () => {
console.log(this.age);//20
}
}
obj.fn()在这里,箭头函数继承了obj的this,当箭头函数被定义时,它会继承外层作用域的 this 值。在这个例子中,箭头函数 fn 是在 obj 对象中定义的,所以它应该继承 obj 对象作为外层作用域,并且 this 指向 obj 对象。然而,由于箭头函数的特性,它不会改变 this 的指向,而是继承外层作用域的 this 值。在浏览器环境中,默认的全局对象是 window,因此当访问 this.age 时,它实际上是在访问 window.age。如果全局作用域中存在 age 属性,它的值将被打印出来。所以,虽然箭头函数的外层作用域应该是 obj 对象,但由于浏览器中默认的全局对象是 window,所以当执行代码时,它会显示 window.age 的值。这可能是导致混淆的原因。剪头函数的this不会被修改func = () => {
// 这里 this 指向取决于外层 this
console.log(this)
}
func.bind(1)() // Window,口诀 1 优先如何让箭头函数里this不等于Window,答案是给他加一层函数var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s,这里return是因为sayHello是普通函数,需要return
}
}
var sayHello = A.sayHello();
sayHello();// 输出A
var B = {
name: 'B';
}
sayHello.call(B); //还是A
sayHello.call(); //还是A这里使用sayHello函数包裹了一下箭头函数,箭头函数定义时候的环境改变了,从对象A变为了sayHello,所以this从Window变为了对象A5.call&& apply&&bind使用call,apply,bind并不会改变箭头函数中的this指向。当对箭头函数使用call或apply方法时,只会传入参数并调用函数,并不会改变箭头函数中this的指向。当对箭头函数使用bind方法时,只会返回一个预设参数的新函数,并不会改变这个新函数的this指向。window.name = "这是window_name";
let f1 = function () {
return this.name;
};
let f2 = () => this.name;
let obj = { name: "这是obj_name" };
console.log(f1.call(obj)); //这是obj_name
console.log(f2.call(obj)); // 这是window_name
console.log(f1.apply(obj)); // 这是obj_name
console.log(f2.apply(obj)); // 这是window_name
console.log(f1.bind(obj)()); // 这是obj_name
console.log(f2.bind(obj)()); // 这是window_name都是把函数立即执行改变函数中的this指向(第一个参数是谁this就是谁),如果不传参数,默认指向WindowA.sayHello.call();//不传参数指向全局window对象,输出window.name也就是windowapply同理 唯一的区别就是传参的格式不一样,apply把传递给函数的形参以数组的形式管理起来,最终的效果和call一样,也是把数组中的每一项作为实参,一个个的传递给函数真实项目中建议大家使用call,因为其性能好一些(三个及以上参数,call的性能明显比apply好一些)this存储的值 null.undefined.对象一个也不写,非严格模式下是window 严格模式下是undefinednull 严格模式下是null非严格模式下是window多次bind只认第一次bind的值function func() {
console.log(this)
}
func.bind(1).bind(2)() // 1function fn(x, y) {
console.log('加油');
console.log(this);//this指向window
console.log(x + y);
console.log('-=-=-=-=--=-=-=-=-=-=-=-=-=');
}
var o = {
name: 'andy'
}
fn.call()//call 呼叫 可以调用函数
fn.call(o, 1, 2)//第一个值是this指向, 后边实参
fn.apply(o, [10, 20])//apply传递数组
fn.call(10, 20)//this-->new Numbe(10) x-->20 y-->undefined 执行结果
增加点难度function Animal(){
this.name = 'animal';
}
function Cat(){
Animal.call(this);
}
var cat = new Cat();
console.log(cat.name);// 'animal'这里要善于理解this 永远指向 调用 包含 自己(this本身) 的 函数 对应的对象。这句话,首先从cat看起,cat是一个实例化的对象,构造函数的this指向他实例化的对象,而构造函数Cat的Animal.call(this);里面传入的this,就是当前的实例化的对象cat,又由于是call调用,给传入的this赋值,也就是给实例化对象cat赋值,所以cat.name就是'animal'其他示例立即执行函数指向Window所谓立即执行函数,就是定义后立刻调用的匿名函数(参见下面这道例题里 hello 方法的函数体里这种写法)。var name = 'BigBear'
var me = {
name: 'xiaohong',
// 声明位置
sayHello: function() {
console.log(`你好,我是${this.name}`)
},
hello: function() {
(function(cb) {
// 调用位置
cb()
})(this.sayHello)
}
}
me.hello() // 这里输出的this指向Window,而不是me,因为
即便不考虑立即执行的匿名函数这种所谓的“特殊情况”, 按照上面指向原则来分析,结果也是一样。 立即执行函数作为一个匿名函数,在被调用的时候,我们往往就是直接调用,而不会(也无法)通过属性访问器( 即 xx.xxx) 这样的形式来给它指定一个所在对象,所以它的 this 是非常确定的,就是默认的全局对象 window。setTimeout 和 setInterval 中传入的函数 setTimeout 和 setInterval 中函数的 this 指向机制其实是一样的var name = 'BigBear'
var me = {
name: 'xiaohong',
hello: function() {
setTimeout(function() {
console.log(`你好,我是${this.name}`)
})
}
}
me.hello() // 你好,我是BigBear延时效果(setTimeout)和定时效果(setInterval),都是在全局作用域下实现的。无论是 setTimeout 还是 setInterval 里传入的函数,都会首先被交付到全局对象手上。因此,函数中 this 的值,会被自动指向 window。引用关于this指向问题及改变this指向的方法this指向问题汇总面试官:说说执行上下文吧JS 中 this 指向问题ES6箭头函数的this指向详解
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。