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

this、new、apply、call、bind深入理解 #19

Open
laihuamin opened this issue Sep 1, 2017 · 0 comments
Open

this、new、apply、call、bind深入理解 #19

laihuamin opened this issue Sep 1, 2017 · 0 comments

Comments

@laihuamin
Copy link
Owner

this是什么?

this是上下文,分两种情况,在es6没出之前,this的指向一直是一个难点,this会指向谁,只会指向调用他的那个对象,但在es6的箭头函数中,有出现了不同的情况,接下来一个例子一个例子的看

第一个例子

console.log(this);
(function sayThis(){
    console.log(this);
})();
  • 输出的是两个window对象

因为这两个值都是window调用的,所以都会打印window对象,大家会奇怪第二个例子,为什么也是打印window。因为this指向最终调用他的对象,那么谁最终调用了他呢,window啊,问题解决了,我们来看第二个例子

第二个例子

class F{
    sayThis(){
        console.log(this);
    }
}
const f = new F;
f.sayThis();
  • 输出的是一个f对象

没有疑问,最终调用的对象是啥,f啊,进入下一个例子

第三个例子

function Person(x, y){
    this.x = x;
    this.y = y;
    this.moveTo = function (x,y) {
        this.x = x;
        this.y = y;
    }
}

const person = new Person(0, 0);
person.moveTo(1,1);
console.log(person);

这个例子中的person1中的x,y是什么值?不卖关子,是1和1。

  • 为啥呢,可能这里的this有点多我们一步一步来看
const person = new Person(0, 0);

这句语句之后,person被创建,而且有了两个属性x和y,值为1,还有个方法moveTo,等会再讲new操作符做了什么。

  • 那为什么后来值变成了1和1呢,关键在下一条语句
person.moveTo(1,1);

这句语句就要用到前面的知识点了,谁调用了this,答案是person对象,哪moveTo函数又是干嘛用的,改变this属性的x和y值,那么this就是person,所以最后改变的还是person的属性值,搞清楚这个例子,我们往下看,要是能搞懂下面这个例子,也理解的差不多了

第四个例子

o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a);
            console.log(this);
        }
    }
}
const j = o.b.fn;
j();
  • 输出的答案是undefined,还有window对象

为什么呢,其实中间过程我们都可以不用看,只看最终谁调用的他,不是b也不是o,是window,j函数是在全局环境中运行的,所以最终调用的还是window对象,看完这些我们来看看new操作符和this中。

第五个例子

function Person(x, y){
    this.x = x;
    this.y = y;
    this.moveTO = function (x,y) {
        this.x = x;
        this.y = y;
    }
}

const person1 = new Person(0, 0);
console.log(person1.moveTO(1,1));
const person2 = new person1.moveTO(1,1);
console.log(person2);
  • 这么两个输出的值是什么?一个是undefined,还有一个是对象,在严格模式下会报错,因为后面那个不是构造函数

为什么会产生这种现象,原因还是new引起的,我们先来熟悉一下new的过程:
1.创建一个以这个函数为原型的空对象
2.把这个函数的prototype赋值给_proto_
3.将这个对象当作this的传进函数,如果没有return,返回创建对象,如果有return出对象的话,就是直接返回return的内容
写成代码如下:

function NewFunc(func){
    var ret = {}; //先创建一个空对象
    if (func.prototype !== null) {
        ret.__proto__ = func.prototype;
    }// 进行new的第二步,把函数的prototype赋值给新建对象的_proto_
    var ret1 = func.apply(ret, Array.prototype.slice.call(arguments, 1));
    //把this的值指向作用ret对象,并返回给ret1这个对象
    if ((typeof ret1 === "object" || typeof ret1 === "function") && ret1 !== null){
        return ret1;
    }
    return ret;
}

第六个例子

    function Person1(name) {
        this.name = name;
    }
    function Person2(name) {
        this.name = name;
        return this.name;
    }
    function Person3(name) {
        this.name = name;
        return new Array();
    }
    function Person4(name) {
        this.name = name;
        return new String(name);
    }
    function Person5(name) {
        this.name = name;
        return function() {};
    }
    
    
    const person1 = new Person1('xl');
    const person2 = new Person2('xl');
    const person3 = new Person3('xl');
    const person4 = new Person4('xl');
    const person5 = new Person5('xl');
  • 输出结果如下,我们一个一个看
// {name: 'xl'}
// {name: 'xl'}
// []
// 'xl'
// function() {}

第一个为什么是{name: 'xl'},显而易见,new的过程就是没有this会返回一个对象,过程已经在上面了,可以过一遍

第二个为什么还是{name: 'xl'},也很好理解,因为有return的时候是把return的内容给对象

第三个参见第二条就很容易理解了

第四个,用new String是会创建一个字符串的,而不是一个字符串对象,对象和基本类型还是有本质的区别,可以看一下高程这本书,有空我也会总结一下

第五个,参见第二条

第七个例子

function Point(x, y){ 
   this.x = x; 
   this.y = y; 
   this.moveTo = function(x, y){ 
       this.x = x; 
       this.y = y; 
   } 
} 
 
const p1 = new Point(0, 0); 
const p2 = {x: 0, y: 0}; 
p1.moveTo.apply(p2, [10, 10]);
console.log(p2);
  • 这里输出的p2是什么值呢,{x:10,y:10}

为什么会产生这种情况?

  • 我们来看一下apply、call、bind的作用

apply、call、bind是用来改变this这个上下文指向的,就像例子中,本来this的作用对象是调用他的pi,但是在apply的作用下,转到了p2的身上,有了这一个妙用,我们就可以轻易掌控this,想给谁就给谁

第八个例子

function Point(x, y){ 
   this.x = x; 
   this.y = y; 
   this.moveTo = function(x, y){ 
       this.x = x; 
       this.y = y; 
   } 
} 
 
const p1 = new Point(0, 0); 
const p2 = {x: 0, y: 0}; 
p1.moveTo.call(p2, 10, 10);
console.log(p2);
  • 输出结果和上面的一致

那么call和apply的效果是一致的,写法有差异,apply传的是数组,call需要一个一个传。

  • 那么为什么需要两个呢,一个apply不行么?apply不能代替call么?

其实他们还是有本质性区别的,call比apply快,apply还要对数组进行深拷贝以及一个一个校验,然后才能用里面的参数,而call省却了这些步骤,取得了性能上的优势

  • 那bind又是干什么的呢?见下面一个例子

第九个例子

function Point(x, y){ 
   this.x = x; 
   this.y = y; 
   this.moveTo = function(x, y){ 
       this.x = x; 
       this.y = y; 
   } 
} 
 
const p1 = new Point(0, 0); 
const p2 = {x: 0, y: 0}; 
const f = p1.moveTo.bind(p2, 10, 10);
f();
console.log(p2);
  • 输出的结果和上面还是上面一致

区别就在于他可以不立即触发,用一个函数存起来,当想要改变的时候去触发这个条件,那样用处就很大,复用等一些功能也可以被创造

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