this指向 普通函数与箭头函数 call/apply/bind arguments

this指向

 ① this并不指向函数,而是指向调用它的主体对象。
 ③ this指向的对象,我们称之为函数的上下文context,也叫函数的调用者
  1. 普通函数调用:通过函数名()直接调用:this指向全局对象window(注意let定义的变量不是window属性,只有window.xxx定义的才是。即let a =’aaa’; this.a是undefined)
  2. 构造函数调用:函数作为构造函数,用new关键字调用时:this指向新new出的对象
  3. 对象函数调用:通过对象.函数名()调用的:this指向这个对象
  4. 箭头函数调用:箭头函数里面没有 this ,所以永远是上层作用域this(上下文)
  5. apply和call调用:call/apply方法第一个参数是函数体内 this 的指向
  6. 函数作为数组的一个元素,通过数组下标调用的:this指向这个数组
  7. 函数作为window内置函数的回调函数调用:this指向window(如setInterval setTimeout 等)

严格模式下, this为undefined 

console.log("通过函数名()直接调用:this指向window");
let x = 2;
function test() {
    console.log(this);
    console.log(this.x);
    console.log(x);
}
test();//Object [global]

console.log("通过对象.函数名()调用的:this指向这个对象");
let obj = {
    x : 3,
    objTestest: test,
};
obj.objTestest(); //{ x: 3, objTestest: [Function: test] }

console.log("函数作为构造函数,用new关键字调用时:this指向新new出的对象");
let newobj = new test(); //test {}

console.log("函数作为数组的一个元素,通过数组下标调用的:this指向这个数组");
let arr = [1,2,test,4]; //test表示的是函数对象,即整个这个function,而test()表示调用函数,有return就对应一个返回值
arr[2](); //[ 1, 2, [Function: test], 4 ]

console.log("函数作为window内置函数的回调函数调用:this指向window(如setInterval setTimeout等)");
setTimeout(test,0); //Timeout {}

console.log("普通函数与箭头函数");
let obj={
    a:222,
    fn:function(){
        setTimeout(function(){console.log(this.a)})
    }
};
obj.fn();//undefined
//this 指向是 window setTimeout,window 下面没有a ,所以这里输出 undefined。
let obj={
    a:222,
    fn:function(){
        setTimeout(()=>{console.log(this.a)});
    }
};
obj.fn();//222
//这次输出 222 是因为,传给 setTimeout 的是箭头函数,然后箭头函数里面没有 this ,所以要向上层作用域查找,在这个例子上, setTimeout 的上层作用域是 fn。而 fn 里面的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj 。所以输出 222

console.log("call/apply");
let obj1={
    a:222
};
let obj2={
    a:111,
    fn:function(){
        alert(this.a);
    }
}
// obj2.fn.call(obj1); /call 和 apply 两个主要用途就是
// 1.改变this的指向   (把 this 从 obj2 指向到 obj1 )
// 2.方法借用   (obj1 没有 fn ,只是借用 obj2 方法)
输出结果:
通过函数名()直接调用:this指向window
Object [global] { ... }
undefined   (这个不会输出上面定义的let对象,因为他不是window,换成window.x = 2就输出2了)
2
通过对象.函数名()调用的:this指向这个对象
{ x: 3, objTestest: [Function: test] }
3
2
函数作为构造函数,用new关键字调用时:this指向新new出的对象
test {}
undefined
2
函数作为数组的一个元素,通过数组下标调用的:this指向这个数组
[ 1, 2, [Function: test], 4 ]
undefined
2
函数作为window内置函数的回调函数调用:this指向window( setInterval setTimeout 等)
Timeout { ... }
undefined
2

注意全局环境下定义的变量不是全局属性哦。如果没有定义window.namef,会输出undefined

参考:https://blog.csdn.net/weixin_37722222/article/details/81625826 这个讲的很好

普通函数与箭头函数

 区别:

1.写法

    // es5
    var fn = function(a, b) {
        return a + b;
    }
    // es6 箭头函数写法,当函数直接被return时,可以省略函数体的括号
    const fn = (a, b) => a + b;
    
    // es5
    var foo = function() {
        var a = 20;
        var b = 30;
        return a + b;
    }
    // es6
    const foo = () => {
       const a = 20;
       const b = 30;
       return a + b;
    }

当函数参数只有一个时,括号可以省略。函数体(中括号)中有且只有一行return语句时,中括号及return 关键字可以省略。

2.this指向

箭头函数中没有this。如果你在箭头函数中使用了this,那么该this一定就是外层的this。

function A() {
    let a = 3;
    this.a = 4;
    console.log(this); //A { a: 4 }
    setTimeout(function() {
        console.log(a) //3
    },100);
    setTimeout(function() {
        console.log(this.a);//undefined  this指向是Timeout{}方法
    },200);
    setTimeout(() => {
        console.log(a) //3
    },300);
    setTimeout(() => {
        console.log(this.a)  //4 在箭头函数里面,没有 this ,箭头函数里面的 this 是继承外面的环境。
    },400)
}
new A();

3.构造函数

function是可以定义构造函数的,而箭头函数是不行的。

//使用function方法定义构造函数
function Person(name, age){
    this.name = name;
    this.age = age;
}
var lenhart =  new Person(lenhart, 25);
console.log(lenhart); //{name: 'lenhart', age: 25}


//尝试使用箭头函数
var Person = (name, age) =>{
    this.name = name;
    this.age = age;
};
var lenhart = new Person('lenhart', 25); //Uncaught TypeError: Person is not a constructor

4.变量提升

由于js的内存机制,function提升的级别最高,而用箭头函数定义函数的时候,需要var/ let/const关键词,变量提升只会提升变量名的声明,而不会提升变量的赋值初始化,故箭头函数一定要定义于调用之前!

aaa();
bbb();   //报错ReferenceError: bbb is not defined
function aaa() {
    console.log(1);
}
let bbb = ()=>console.log(2);

call/apply/bind

相同:

三者都是用来改变函数的this对象的指向的;
三者第一个参数都是this要指向的对象,也就是想指定的上下文;
三者都可以利用后续参数传参;

不同:

apply和call传入的参数列表形式不同。appl接收arguments,call接收一串参数列表

bind 主要就是将函数绑定到某个对象,bind()会创建一个函数,返回对应函数便于稍后调用;而apply、call则是立即调用。

var obj = {
    x: 81,
};
var foo = {
    getX: function() {
        return this.x;
    }
};

var getX = foo .getX;

getX (); // 9  因为"this"指向全局对象
console.log(foo.getX.bind(obj)());  //81(方法名后多了括号)
console.log(foo.getX.call(obj));    //81
console.log(foo.getX.apply(obj));   //81

 arguments

 arguments与数组

相同点:

  • 都可用下标访问每个元素
  • 都有length属性

不同点:

  • 数组对象的类型是Array,类数组对象的类型是Object;
  • 类数组对象不能直接调用数组API;
  • 数组遍历可以用for in和for循环,类数组只能用for循环遍历;

arguments 用法

  1. 实现重载(overload):当函数的参数个数不明确时,函数体根据参数的不同进行相应处理arguments.length
  2. 实现递归:在函数内部反复的调用函数本身arguments.callee(在严格模式下不允许arguments.callee)
function factorial(num) {
    if(num<=1) {
        return 1;
    }else {
        return num * arguments.callee(num-1);
    }
}

arguments 转数组

Array.prototype.slice.call(arguments);

或者  [ ].slice.call(arguments);

Array.from() 是个非常推荐的方法,其可以将所有类数组对象转换成数组。

arguments  参考: https://blog.csdn.net/xiaotao_css/article/details/72794650

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值