Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES5-This详讲 #27

Open
huangchucai opened this issue Aug 8, 2017 · 0 comments
Open

ES5-This详讲 #27

huangchucai opened this issue Aug 8, 2017 · 0 comments

Comments

@huangchucai
Copy link
Owner

人生就像一列开往坟墓的列车,路途上会有很多站,很难有人至始至终陪你走完全程,当陪你的人要下车时,即便不舍,也要心存感激,然后挥手告别。---sunnyhuang

在es5很多新手可能对于this感觉到很迷惑,看见有些大神对this灵活运用,心里很是羡慕,不要紧,这篇文章让你彻底明白什么是this

函数的四种调用

  1. func(p1,p2) 直接调用
  2. obj.child.method(p1,p2) 对象的方法调用
  3. func.call(null,p1,p2) 通过call调用
  4. func.apply(null,[p1,p2]) 通过apply调用

我们一般都使用的是第一种和第二种调用,但是正规的函数调用是第三种和第四种。
func.call(context,p1,p2) this就是这个context的值,后面的是传入的参数,在不严格模式下,context等于null或undefined的时候会自动指向为window对象,同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

面试题运用

你可能遇到过这样的题目

var obj={
    sum: function(){
       console.log(this)
    }
}
var bar=obj.sum;
obj.sum()  //输出的是obj
bar()   //输出的确实window

我们不通过第一种或者第二种调用函数,通过第三种来调用函数上述代码的变换

obj.sum()  --->obj.sum.call(obj)   //obj就是context
bar()  ---->bar.call(undefined)   可以简写bar.call()   //window就是context   

数组的运用

猜猜如果数组中的元素调用函数,this指向谁呢?
function fn(){console.log(this)}
function fn1(){console.log(this+"fn2")}
var arr=[fn,fn1]
arr[0]() >---你可以意淫成arr.0.call(arr)

小试牛刀

var a = {
    name:"zhang",
    sayName:function(){
        console.log("this.name="+this.name);
    }
};
var name = "ling";
function sayName(){
    var sss = a.sayName;
    sss(); //this.name = ?   >--sss.call(undefined)  window.name
    a.sayName(); //this.name = ?   >--a.sayname.call(a)  a.name
    (a.sayName)(); //this.name = ? >--只是对于a进行了一层包装,a.sayname.call(a)   a.name
    (b = a.sayName)();//this.name = ?  >--先进行b的复制,然后再执行 b()  b.call()  window.name
}
sayName();
// ling
// zhang
// zhang
// ling

变形

var name = "ling";
function sayName(){
    var a = {
        name:"zhang",
        sayName:getName
    };

    function getName(){
        console.log(this.name);
    }

    getName(); //this.name = ?  >--getName.call()   window.name
    a.sayName(); //this.name = ?  >--a.sayName.call(a)  a.name
    getName.call(a);//this.name = ?  它直接转换了,所以是a.name
}
sayName();
//ling
// zhang
//zhang

继续变形,我看你能翻出天

var name = "ling";
var obj = {
    name:"zhang",
    sayName:function(){
        console.log("this.name="+this.name);
    },
    callback:function(){
        var that = this;  //2. 所以这里的this值是obj  that=this
        return function(){
            var sayName = that.sayName; //3. 这里就相当于是obj.sayName
            that.sayName(); //this.name = ?  //4. obj.sayName.call(obj)   obj.name
            sayName();//this.name = ?   //  sayName.call()    window.name
        }
    }
}
obj.callback()()  //1. 首先里面有一个this被复制给that 先转换这个obj.callback.call(obj)()
// zhang
//ling

让我们更加加深转换代码

  1. fun()
  2. obj.child.call(obj)
  3. arr.push(1)
  4. arr.push.call(arr,3)
  5. obj1.obj2.sum()

仰天抬头看看世界,思考1分钟人生,然后看题

1. fun.call()
2. obj.child()
3. arr.push.call(arr,1)  //记住1是参数
4. arr.push(3)
5. obj1.obj2.sum.call(obj2)

挑战升级

理解Array的原型调用
如果你是一个看mdn的小baby,就会在数组上面经常看到Array函数的原型上面调用函数实现某种效果

1. 在es5的时候实现一个数组push另一个数组
var arr1=[1,2,3],arr2=[4,5,6]
Array.prototype.push.apply(arr1,arr2) //arr1=[1,2,3,4,5,6]

刚开始,由于自己没有开发过api,我也不是怎么理解这个的原理,下面我来分解一下

  1. 如果我想给arr1后面添加一个数据arr1.push(1)
  2. 用我们刚刚的进行转换 arr1.push.call(arr,1)>--变成apply arr1.push.apply(arr1,[1])
  3. 我们把[1]变成arr2 arr1.push.apply(arr1,arr2)
  4. 由于数组的提供的api,不可能每一个都是arr1,所以统一调用Array.prototype。我们把arr1换成Array.prototype

试试理解 Math.max.apply(null,[1,2,3])


ES6的扩展语句

arr1.push(...arr2)
Math.max(...arr1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant