高级2 - this_原型链_继承

this相关问题

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

  • apply()call()函数都可以 指定this值和参数值的情况下调用某个函数。
  • call()apply()的作用一样,区别在于提供给原函数的参数的方式不一样
    • apply()函数只接受两个参数,提供给原函数的参数以数组或类数组对象的形式存在
    • call()接收无限个参数, 第二个参数及其后面的参数就是提供给原函数的参数。

问题2:以下代码输出什么

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

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

func()   //  弹出window对象

function func() { 
  alert(this)
}
  • 因为在函数func()被直接调用时,this绑定到全局对象。在浏览器中,window 就是该全局对象

问题4:下面代码输出什么

function fn0(){
    function fn(){
        console.log(this);
    }
    fn();
}

fn0();  //  输出window对象


document.addEventListener('click', function(e){
    console.log(this);   //  输出document对象
    setTimeout(function(){
        console.log(this);   //  输出window对象
    }, 200);
}, false);

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

var john = { 
  firstName: "John" 
}

function func() { 
  alert( this.firstName ) 
}
func.call(john)    //  弹出John
  • func()函数通过call()函数调用,此时this为John对象,john.firstName存在,输出"John"

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

var module= {
  bind: function(){
    $btn.on('click', function(){
      console.log(this) // 这里的this指的是$btn
      this.showMsg();  //  $btn没有showMsg的属性,如果调用,这里会报错
    })
  },
  
  showMsg: function(){
    console.log('饥人谷');
  }
}
  • 应该改成如下:
var module= {
  bind: function(){
    var self = this;  // 先在外部将this保存成变量,再在内部调用这个变量
    $btn.on('click', function(){
      console.log(this);
      self.showMsg(); 
    })
  },

  showMsg: function(){
    console.log('饥人谷');
  }
}

这样,再进行测试,发现成功输出饥人谷

高级2 - this_原型链_继承_第1张图片
修改之后测试.png

原型链相关问题

问题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();
  • People是一个构建函数,protoTypePeople的属性(原型),即可以通过People.protoType的方式来获取这个属性,其类型是一个对象。
  • pPeople构建的实例,它有一个属性__proto__,它的值引用了p的父类PeopleprotoType属性。
  • constructorprotoType的一个属性,其值指向函数本身,例如:People.protoType.constructor就是People本身。

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

高级2 - this_原型链_继承_第2张图片
question8.png
  • toString()实际上是Object的方法
    • 如上原型图所示:对对象p调用p.toString()时,JS先从其自身的方法中找toString()方法,没有找到;
    • 然后通过__proto__属性找其父元素PeopleprotoType属性中有没有toString()方法,依然没找到;
    • 然后再通过其父元素PeopleprotoType属性中的__proto__属性即Object.protoType继续寻找,在Object.protoType找到了toString()方法。
  • 每个对象都有一个隐藏的__proto__属性,这个属性就是对其父元素原型对象(protoType)的引用。
  • 由于原型对象本身也是对象,也有__proto__属性,它的__proto__属性又指向了其更高父元素原型对象。这样就形成了一条链,这就是原型链

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

// 答案
String.prototype.getMostOften = function(){
    var box = {},
        max = 0,
        maxKey = "";
    for (var i=0, word;i max) {
            max = box[key];
            maxKey = key;
        }
    }
    return maxKey
}



// 题目
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次

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

  • instanceof用来检查一个对象是不是另一个构造对象的实例。
  • 其内部逻辑是测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
  • 所以如果表达式obj instanceof Foo 返回true,则并不意味着该表达式会永远返回true,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false

继承相关问题

问题11:继承有什么作用?

  • 继承的主要作用有两个
    • 继承可以使子类共享父类的属性和方法
    • 继承可以覆盖和扩展父类的属性和方法

问题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);
  • 第一种方法将会把printName这个方法重新定义在每个构建的对象上,这样如果构建的对象比较多,也将会有许多个printName函数,将会对性能产生影响
  • 第二种方法会把printName这个方法定义到构建函数的protoType上,这样新构建的函数将会通过原型链获取到这个方法,节约了内存
  • 推荐使用第二种方法

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

  • Object.create方法可以创建一个拥有指定原型和若干个指定属性的对象。
  • 在继承中,Object.create可以用于继承属性。
  • Object.create是在ES5中规定的,其兼容性见下图:
高级2 - this_原型链_继承_第3张图片
Object.create-compatibilty.png

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

  • hasOwnProperty方法会返回一个布尔值,其用来判断某个对象是否含有特定的自身属性,该方法会忽略掉那些从原型链上继承到的属性。
  • 语法为obj.hasOwnProperty(prop),参数prop为要检测的属性

问题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的作用是改变构造函数People的作用域,这样就可以让PeopleMale的作用域中执行,这样People中的一些属性赋值语句也会在Male中执行。
  • 通过这种方式就实现了属性的继承。

问题16: 补全代码,实现继承

function Person(name, sex){
    this.name = name;
    this.sex = sex;
}

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

function Male(name, sex, age){
   Person.call(this, name, sex);
   this.age = age;
}

var _prototype = Object.create(Person.prototype);
_prototype.consturctor = Male;
Male.prototype = _prototype;

Male.prototype.getAge = function(){
    console.log(this.age);
};

var ruoyu = new Male('若愚', '男', 27);
ruoyu.getName();

你可能感兴趣的:(高级2 - this_原型链_继承)