this是什么
- this是JavaScript的一个关键字。
- this是在函数运行时,在函数体内自动生成的一个对象。
- this只能在函数体内使用。
在JavaScript中,函数的几种调用方式
- 普通函数调用
- 作为方法调用
- 构造函数调用
- call/apply中
- Function.prototype.bind中
- 箭头函数中
this的几种指向
- 哪个对象调用这个函数/方法,this就指向谁
- 箭头函数的this指向定义的时候离他最近的对象
- 箭头函数不绑定this,不会自己创建this,只能从自己的作用域的上一层继承this
- 外层普通函数的this,会在函数调用时发生变化,进而影响箭头函数的this变化
示例一
var x = 111
var test = {
x : 222
}
var temp = {
x : 333,
do : function(){
alert(this.x)
}
}
temp.do() // 333
test.do = temp.do
test.do() // 222
var foo = test.do
foo() // 111
示例二
var name = 'window'
var person1 = {
name: 'person1',
show1: function(){
console.log(this.name)
}
}
var person2 = {
name: 'person2'
}
person1.show1(); // person,this指向person1对象
person1.show1.call(person2); // person2,this指向person2对象
示例三
var name = 'window'
var person1 = {
name: 'person1',
show2: () => console.log(this.name)
}
var person2 = {
name: 'person2'
}
person1.show2(); // window,箭头函数的this和最近的普通function相同,没有,指向window
person1.show2.call(person2);// window,无法和person2绑定,所以也是window
示例四
var name = 'window'
var person1 = {
name: 'person1',
show3: function(){
return function(){
console.log(this.name);
}
}
}
var person2 = {
name: 'person2'
}
person1.show3()(); // window
person1.show3().call(person2); // person2
person1.show3.call(person2)(); // window
// 此问题牵扯到闭包的问题
/*
person1.show3()(); // window
等价于:
var fun = person1.show3();
fun(); // window
里面的匿名函数被返回到person1外边,再调用这个函数时,this指向了window
*/
/*
person1.show3().call(person2);
等价于:
var fun = person1.show3();
fun.call(person2); // person2
将匿名函数的this和person2绑定了
*/
/*
person1.show3.call(person2)(); // window
等价于
var fun = person2.show3()
fun()
在第一阶段绑定了person2,这时候匿名函数还没执行,等再执行时,绑定到了window上
*/
示例五
var name = 'window'
var person1 = {
name: 'person1',
show4: function(){
return () => console.log(this.name)
}
}
var person2 = {
name: 'person2'
}
person1.show4()(); // person1
person1.show4().call(person2); // person1
person1.show4.call(person2)(); // person2
// 这里涉及了箭头函数this的指向:最近一层的普通函数绑定的this,且定义时this就被定义好了
/*
person1.show4()();
等价于:
var fun = person1.show4(); // 定义时,this指向了person1
fun();
*/
/*
person1.show4().call(person2);
等价于:
var fun = person1.show4(); // 定义时指向person1,而call不起作用
fun.call(person2);
*/
/*
person1.show4.call(person2)();
等价于
var fun = person2.show4() // 将箭头函数最近的一层普通函数的this指向了person2,再执行时,this就指向了person2
fun()
*/
示例六
var name = 'window'
function Person(name){
this.name = name
this.show5 = function(){
return () => console.log(this.name)
}
}
var personA = new Person("personA");
var personB = new Person("personB");
personA.show5()(); // personA
personA.show5().call(personB); // personA
personA.show5.call(personB)(); // personB
示例七
var name = 'window'
function Person(name) {
this.name = name;
this.show1 = function () {
console.log(this.name)
}
this.show2 = () => console.log(this.name)
this.show3 = function () {
return function () {
console.log(this.name)
}
}
this.show4 = function () {
return () => console.log(this.name)
}
}
var personA = new Person('personA')
var personB = new Person('personB')
personA.show1() // personA
personA.show1.call(personB) // personB
personA.show2() // personA
personA.show2.call(personB) // personA
personA.show3()() // window
personA.show3().call(personB) // personB
personA.show3.call(personB)() // window
personA.show4()() // personA
personA.show4().call(personB) // personA
personA.show4.call(personB)() // personB
示例八
var name = 'window'
function foo(){
var name = 'inner';
console.log(this.name)
}
foo(); // window
// foo在全局全局执行,this指向window
_________________________________________
var name = 'window'
function foo(){
'use strict'
var name = 'inner';
console.log(this)
}
foo(); // undefined
// 这里this.name会报错,因为this是undefined
// 在严格模式下
示例九
function foo(){
setTimeout(() => {
console.log("id:" + this.id)
setTimeout( () => {
console.log("id:" + this.id)
},100)
},100)
}
foo.call({id:'111'}) // 111 111
function foo(){
setTimeout(function(){
console.log(this.id)
setTimeout(function(){
console.log(this.id)
},100)
},100)
}
foo.call({id:'111'}) // undefined undefined
function foo1(){
setTimeout(() =>{
console.log("id:", this.id)
setTimeout(function (){
console.log("id:", this.id)
}, 100);
}, 100);
}
foo1.call({ id: 111 }); // 111 undefined
示例十
// 嵌套箭头函数
function foo(){
return () => {
return () => {
return () => {
console.log(this.id)
}
}
}
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // 1
var t2 = f().call({id: 3})(); // 1
var t3 = f()().call({id: 4}); // 1
示例十一
var number = 2;
var obj = {
number: 4,
fn1: (function () {
console.log("定义obj的时候,立即执行函数就执行了");
var number;
this.number *= 2;
number = number * 2;
number = 3;
return function () {
var num = this.number;
this.number *= 2;
console.log(num);
number *= 3;
console.log(number);
}
})(),
db2: function () {
this.number *= 2;
}
}
var fn1 = obj.fn1;
console.log(number); // 4
fn1(); // 4 9
obj.fn1(); // 4 27
console.log(window.number); // 8
console.log(obj.number); // 8
当定义obj的时候执行了匿名函数1,此时处于全局作用域内,因此上下文this是window。执行完语句(1)导致全局变量number的值变为4;执行语句(2)时临时变量number还没有被赋值,所以是NaN,但下一句会将其赋值为3;最后,匿名函数1返回了匿名函数2,因此obj.fn1=匿名函数2。(注意匿名函数2里面会用到临时变量number,老生常谈的闭包)
来到语句(3),这句会把fn1这个变量赋值为obj.fn1,也就是匿名函数2
由于全局变量number已经在语句(1)中变为了4,所以语句(4)弹出的对话框结果为4
语句(5)执行的是fn1(),它与执行obj.fn1()的区别是两者this不一样。前者为null,而后者this为obj。但是又由于JS规定,this为null时相当于全局对象window,所以这句代码执行时函数的this为window。在匿名函数2里会将全局变量number更新为8,同时将匿名函数1中被闭包的临时变量number更新为9
语句(6)的效果在上面已经分析过了,this是obj,所以obj.number更新为8,闭包的number更新为27
网友评论