美文网首页
this_原型链_继承

this_原型链_继承

作者: 高进哥哥 | 来源:发表于2017-04-19 13:24 被阅读0次

    1: apply、call 、bind有什么作用,什么区别

    call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
    apply、call 的区别
    对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下:

    var func = function(arg1, arg2) {
     
    };
    就可以通过如下方式来调用:
    func.call(this, arg1, arg2);
    func.apply(this, [arg1, arg2])
    

    其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
    JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用 call 。而不确定的时候用 apply,然后把参数 push 进数组传递进去
    apply 和 call ,再来说说bind。bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。
    而bind,MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
    apply、call、bind比较
    那么 apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个栗子:

    var obj = {
        x: 81,
    };
    var foo = {
        getX: function() {
            return this.x;
        }
    }
    console.log(foo.getX.bind(obj)());  //81
    console.log(foo.getX.call(obj));    //81
    console.log(foo.getX.apply(obj));   //81
    

    三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。
    区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。
    总结一下:
    apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
    apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
    apply 、 call 、bind 三者都可以利用后续参数传参;
    bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

    this 相关问题

    2: 以下代码输出什么?

    var john = { 
      firstName: "John" 
    }
    function func() { 
      alert(this.firstName + ": hi!")
    }
    john.sayHi = func
    john.sayHi()
    

    输出:John:hi!
    谁在调用函数,谁就是this,所以this是john,代码执行后弹出John:hi!

    3: 下面代码输出什么,为什么

    func() 
    function func() { 
      alert(this)
    }
    

    输出 window
    在函数被直接调用时this绑定到全局对象。在浏览器中,window 就是该全局对象

    4:下面代码输出什么

    document.addEventListener('click', function(e){
       console.log(this);
       setTimeout(function(){
           console.log(this);
       }, 200);
    }, false);
    

    输出 document,window
    绑定事件函数时,this表示触发此事件的DOM对象。
    setTimeout、setInterval这两个方法执行的函数this也是全局对象

    5:下面代码输出什么,why

    var john = { 
      firstName: "John" 
    }
    function func() { 
      alert( this.firstName )
    }
    func.call(john)
    

    输出 John ,call方法可以在函数调用的时候将第一个参数设置为this值,所以现在的this就是传入的参数对象john。

    6: 以下代码有什么问题,如何修改

    var module= {
      bind: function(){
        $btn.on('click', function(){
          console.log(this) //this指什么
          this.showMsg();
        })
      },
      
      showMsg: function(){
        console.log('饥人谷');
      }
    }
    

    这里的this指的是触发此事件的DOM对象,不是module。
    this.showMsg(); //由于this是$btn,所以在执行这句是会报错。

    var module= {
    var _this=this;
      bind: function(){
        $btn.on('click', function(){
          console.log(_this) //this指什么
          _this.showMsg();
        })
      },
      
      showMsg: function(){
        console.log('饥人谷');
      }
    }
    

    原型链相关问题

    7:有如下代码,解释Person、 prototype、proto、p、constructor之间的关联。

    ···
    function Person(name){
    this.name = name;
    }
    Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
    }
    var p = new Person("若愚")
    p.sayName();
    ···
    Person是构造函数,也是一个对象,这个对象里面存在一个prototype属性,而构造函数内部定义了实例的属性和方法,这些属性和方法是属于该类的所有实例的特征;
    p是通过构造函数Person构造出来的实例,也是拥有proto属性。所以
    p.__proto__ === Person.prototype;
    prototype是构造函数内部的原型对象,所以拥有contructor和proto属性,其中contructor属性指向构造函数Person,proto指向该对象的原型,即

    Person.prototype.__proto__ === Object.prototype;
    Person.prototype.constructor == Person
    

    8: 上例中,对对象 p可以这样调用 p.toString()。toString是哪里来的? 画出原型图?并解释什么是原型链。

    如图所示,p.toString()方法是继承构造函数Object的原型对象里定义的toString方法,首先p会找自己的toString方法,如果没有找到,会沿着proto属性继续到构造函数Person的prototype里找toString方法,如果还未找到,再继续往Person.prototype的proto即Object.prototype找toString方法,最后找到toString()方法。

    原型链:由于原型对象本身也是对象,而每个javascript对象都有一个原型对象,每个对象都有一个隐藏的proto属性,原型对象也有自己的原型,而它自己的原型对象又可以有自己的原型,这样就组成了一条链,这个就是原型链。在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined。原型链一般实现为一个链表,这样就可以按照一定的顺序来查找。

    9:对String做扩展,实现如下方式获取字符串中频率最高的字符

    var str = 'ahbbccdeddddfg';
    var ch = str.getMostOften();
    console.log(ch); //d , 因为d 出现了5次
    
       var str = 'ahbbccdeddddfg';
        function String(str){
          this.str=str;
        }
        String.prototype.getMostOften=function(){
          var obj={};
          for(var i=0;i<this.str.length;i++){
            if(obj[this.str[i]]){
              obj[this.str[i]]++;
            }else{
              obj[this.str[i]]=1;
            }
          }
          console.log(obj);
          var count=0,maxValue;
          for(var key in obj){
            if(obj[key]>count){
              maxValue=key;
              count=obj[key];
            }
          }
          console.log("出现频率最多的字符为"+maxValue+",共有"+count+"个");
        }
        str=new String(str);
        var ch = str.getMostOften();
        console.log(ch); 
    

    10: instanceOf有什么作用?内部逻辑是如何实现的?

    instanceOf:判断一个对象是否为另一个对象的实例
    instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
    语法
    object instanceof constructor
    参数
    object
    要检测的对象.
    constructor
    某个构造函数

    内部逻辑
    function instanceOf(obj,fn) {
      var oldProto = obj.__proto__;
      do {
      if (oldProto=== fn.prototype){
        return true;
      }else {
        oldProto = oldProto.__proto__
      }
      }while(oldProto)
      return false;
    }
    

    继承相关问题

    11:继承有什么作用?

    作用:

    1. 子类拥有父类的属性和方法,不需要重复写代码,修改时也只需修改一份代码
    2. 可以重写和扩展父类的属性和代码,又不影响父类本身

    12: 下面两种写法有什么区别?

    //方法1
    function People(name, sex){
        this.name = name;
        this.sex = sex;
        this.printName = function(){
            console.log(this.name);
        }
    }
    var p1 = new People('饥人谷', 2)
    
    //方法2
    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    
    Person.prototype.printName = function(){
        console.log(this.name);
    }
    var p1 = new Person('若愚', 27);
    

    第一种方式是将所有的属性和方法都写在构造函数中,那么创建的每一个实例都会存有相同的方法,会造成很大的内存浪费。而第二种是将方法定义在原型上,这样只有在原型对象上才会有这个公有方法,所有实例对象都可以共享。

    13: Object.create 有什么作用?兼容性如何?

    Object.create() 方法使用指定的原型对象和其属性创建了一个新的对象。
    语法
    Object.create(proto, [ propertiesObject ])

    14: hasOwnProperty有什么作用? 如何使用?

    obj,hasOwnProperty(pro) 判断某个对象是否含有指定的属性但是该方法会忽略掉那些从原型链上继承到的属性

    function People(){
      this.name='lwk'
    }
    People.prototype.sayName=function(){console.log(this.name)}
    var p = new People()
    p.hasOwnProperty('name')//true
    p.hasOwnProperty('sayName')//false
    

    15:如下代码中call的作用是什么?

    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }
    function Male(name, sex, age){
        Person.call(this, name, sex);    //这里的 call 有什么作用
        this.age = age;
    }
    

    call调用Person方法,指定Person方法中的this为Male,并传入参数sex,age

    16: 补全代码,实现继承

    function Person(name, sex){
        this.name=name;
        this.sex=sex;
    }
    
    Person.prototype.getName = function(){
        console.log("name:"+this.name);
    };    
    
    function Male(name, sex, age){
       Person.call(this,name,sex)
       this.age=age;
    }
    Male.prototype=Object.create(Person.prototype,name);
    Male.prototype.constructor=Male;
    console.dir(Object.create(Person.prototype));
    Male.prototype.getAge = function(){
        console.log("age:"+this.age);
    };
    Male.prototype.printName=function(){
       this.getName();
       this.getAge();
    }
    
    var ruoyu = new Male('高进', '男', 24);
    ruoyu.printName();
    

    相关文章

      网友评论

          本文标题:this_原型链_继承

          本文链接:https://www.haomeiwen.com/subject/oqcqzttx.html