1:直接圆括号执行 this指的是window对象 IIFE也属于圆括号直接执行 this 只想window
例1
var obj = {
as:100,
fun: function(){
alert(this.as)
}
}
var b = obj.fun
b()
//输出undefined
例2
var a = 300;
var obj = {
a : 100,
b:(function(){
alert(this.a)
})()
}
//弹出300
例3
var xiaohong = {
name : "小红",
age : 25,
hello : (function(){
return this.age > 18? "女士" : "女生"
})()
}
alert ("大家好,我叫" + xiaohong.name + ",我是一个" + xiaohong.hello)
结果为女生
IIFE 里的this指的是window 所以this.age 是undefined undefined > 18 是false 所以返回的是 女生
例4
var obj = {
a: 100,
fun: function() {
var a = 200;
alert(this.a)
}
}
var a = 300;
var f = obj.fun
f()
//结果300
解析:条用的时候是圆括号直接调用的 所以这里this指向了window 而全局变量都是window对象的属性 →最后弹出300(其它的a都是障眼法)
2 从对象中调用或者数组枚举执行的函数 上下文this指的是这个对象或者数组
例1
function fun1(a, b, c) {
arguments[0]()
}
function fun2(a, b, c, d, e) {
alert(this.length)
}
fun1(fun2, 9, 2, 4, 2, 34, 234)、
//7
解析:this指的是谁要看谁在调用。函数fun1调用的时候 函数的执行是 arguments[0]的执行 ,因为arguments是fun1的实参列表,所以第0项就是fun2函数,所以符合规则;fun2函数中的this指的就是fun1函数的arguments类数组对象,所以length就是7
例2
function fun1(a, b, c) {
arguments[0](1, 2, 3, 4, 5, 6)
}
function fun2(a, b, c, d, e) {
alert(this.length) // 7
alert(arguments.length) // 6
alert(arguments.callee.length) // 5
alert(this.callee.length) // 3
}
fun1(fun2, 9, 2, 4, 2, 34, 234)
解析:
与例1类似 fun2中的this指的是fun1函数,所以此时this.length指的就是fun1的arguments类数组对象(因为是类数组枚举执行的符合规则);
arguments本身是fun2函数自己的实参列表,所以长度是6(调用的时候传了1~6的参数);
我们知道arguments.callee是fun2函数自己,所以length就是形参列表为5;
this.callee.length指的就是fun1的形参列表为3
例3
var m = 2;
var obj = {
fun1: function() {
return this.fun2()
},
fun2: fun2,
m: 4
}
function fun2() {
return this.m;
}
alert(obj.fun1())
// 4
解析 打点执行 this指向 obj 而obj.m 就是4
例4
var num = 1; // 5 , 25 , 125
var obj = {
num: 2, // 10 , 50
fun: (function() {
var num = 3;
this.num += 4;
return function() {
this.num *= 5;
num *= 6; // 18 , 108 , 648 ,
alert(num)
}
})()
}
obj.fun() // 18
obj.fun() // 108
alert(num) // 5
alert(obj.num) // 50
var f1 = obj.fun
f1() // 648
alert(num) // 25
alert(obj.num) // 50
var f2 = obj.fun
f2() // 3888
alert(num) // 125
解析: obj.fun() →IIFE只执行一次 且this指向window 所以全局的num = 1+4 是5 接着obj.fun() this指向obj 此时 obj的num 先变成2*5 是10 。num*=6 此时num是3 所以 *6就是18 结果为18
obj.fun()→ IIFE不再执行 所以全局的num 是5。接着obj.fun() this指向obj 此时 obj的num 先变成10*5 是50 。num*=6 此时num是18 所以 *6就是108 结果为108
alert(num)→ 全局的num 就是5
alert(obj.num)→ obj的num 就是50
var f1 = obj.fun
f1()→ 圆括号直接执行 this指向window 所以 this.num *= 5指的是全局的num*5 结果25 num*=6 此时num是108 所以 *6就是648结果为648
alert(num) → 全局的num 就是25
alert(obj.num)obj的num→ 是50
var f2 = obj.fun
f2()→圆括号直接执行 this指向window 所以 this.num *= 5指的是全局的num*5 结果125 num*=6 此时num是648 所以 *6就是3888结果为3888
alert(num)→全局的num 就是125
例5
var length = 1;
var obj = {
length: 10,
b: [{
length: 20,
fun: function() {
alert(this.length)
}
}]
}
var arr = [obj, obj.b, obj.b[0], obj.b[0].fun]
arr[0].b[0].fun() // 20
arr[1][0].fun() // 20
arr[2].fun() // 20
arr[3]() // 4
解析 前边三个最后返回的都是 对象
{
length: 20,
fun: function() {
alert(this.length)
}
}在执行所以this指向这个对象 结果都是20
arr[3]() 这个是数组通过枚举法在执行 所以this指的是 这个数组 它的length就是4
3 定时器直接调用,上下文是window对象
例1
var obj = {
a: 300,
fun: function() {
console.log(this.a++)
}
}
var a = 100;
setInterval(obj.fun, 1000)
//100 100 100.。。。。。。。。。。。
var obj = {
a: 300,
fun: function() {
console.log(this.a++)
}
}
var a = 100;
setInterval(function() {
obj.fun()
}, 1000)
// 301 302 303.............
4 DOM事件中的this,指的是触发事件的这个DOM元素
5 call()和apply()可以设置函数的上下文
例1:
function fun1() {
fun2.apply(obj, arguments)
}
function fun2(a, b, c) {
console.log(obj)
console.log(a)
console.log(b)
console.log(c)
}
var obj = {
name: '小明',
sex: '男'
}
fun1("香蕉", '葡萄', '梨子')
解析:apply有一个功能,可以将第二个参数(类数组参数)进行解构,变成一个罗列的参数。比如传进arguments是一个类数组对象,但是在fun2函数接受的a,b,c形参中给进行了解构,也就是分别变成了香蕉、葡萄、梨子
例2 利用apply求数组最值
Math.max.apply(null, [789, 2342, 123, 2134, 2345, 22])
综合实战题目
第一题
var a = 1;
function fn() {
this.a++;
a += 10;
var a = 8;
}
fn()
alert(a)//2
解析:因为fn执行的时候内部的this指的是window也就是全局的a=1,所以this.a++ 等于2;函数内部的a += 10本质上是undefined+= 10 结果为NaN,因为后面有个var a = 8;因为变量声明提升的原因造成的。alert的是全局的a
第二题
var length = 5;
var arr = [fn1, fn2];
function fn1() {
return this.length;
}
function fn2() {
return this[0]
}
var a = arr[0]()
var b = arr[1]()()
console.log(a) // 2
console.log(b) // 5
解析:a =arr[0]()是数组的枚举法执行this指的是这个数组 所以数组的length就是2。 b = arr[1]()() arr[1]()是数组的枚举法执行this就是这个数组,这部分执行之后return出一个函数,这个函数圆括号执行this就是window 所以结果就是5
第三题
var number = 2; // 4,16
var obj = {
number: 3, // 12,24
fn1: (function() {
this.number *= 2;
number = number * 3; // NaN
var number = 2; // 10,50
return function() {
this.number *= 4;
number *= 5;
alert(number)
}
})(),
fn2: function() {
this.number *= 2;
}
}
var fn1 = obj.fn1;
alert(number) // 4
fn1() // 10
obj.fn1() // 50
obj.fn2()
alert(window.number) // 16
alert(obj.number) // 24
解析:obj 里面的fn1是IIFE 声明之后立即执行一次 此时this指的是window 所以window的number 就变成 number*=2即 4。
fn1()圆括号打点执行 this指的是window fn1此时是obj.fn1 return出来的函数 this.number *=4 这时候全局的number就是4*4 = 16 number*=5 指的就是上边声明的number2*5 就是10alert结果就是10
obj.fn1() 对象打点执行this就是这个对象 this.number *= 4;就是obj的number*4 即 3*4 =12。 number*=5 指的就是上边声明的number10*5 就是50alert结果就是50
obj.fn2() 对象打点执行this就是这个对象 this.number *= 2 就是obj的number*2 即 12*2=24
最后alert(window.number)即为16
alert(obj.number)即为24
第四题
var length = 5;
function getLength() {
return this.length
}
function foo() {
this.length = 1;
return (function() {
var length = 2;
return {
length: function(a, b, c) {
return this.arr.length;
},
arr: [1, 2, 3, 4],
info: function() {
return getLength.call(this.length)
}
}
})()
}
var result = foo().info()
console.log(result) // 3
解析:因为result是foo执行的之后的函数执行,foo执行返回的是一个对象,这个对象打点调用info,info函数中执行了getLength函数,并且将上下文一同绑定了,绑定的是对象的length属性,该属性值是一个函数,所以getLenth函数在执行时候的this就是这个对象的length函数,this.length也就是该函数的形参length结果为3