关于this,原型链,继承
2017-04-19 本文已影响0人
JunVincetHuo
通过题目来熟悉this,原型链,继承
开胃菜----this
1. apply、call、bind有什么作用,有什么区别?
- 他们共同的作用是改变this的指向
- 不同在于,apply传递的是数组,call传递的是参数,也就是说,call是单个传递,apply是数组传递
- bind不同在于,它是创建一个新函数,而当它被调用的时候,它的第一个参数正是运行的this。
2. 以下代码输出什么?
var john = {
firstName : "John";
}
function func(){
alert(this.firstName + ":hi!")
}
john.sayHi = func;
john.sayHi(); //'John : hi!'
首先john这个对象有firstName的属性,后来john.sayHi 让 john这个对象新创建了sayHi方法,而当对象john调用sayHi()时,this的指向就是john。
3.下面代码输出什么,为什么?
func()
function func(){
alert(this) //window,倘若是严格模式是undefined
}
因为函数中没有this,就继续往上找,因为不是严格模式,因此输出window对象
4.下面代码输出什么
document.addEventListener('click', function(e){
console.log(this); //指向绑定事件的对象document
setTimeout(function(){
console.log(this); //指向全局,输出window对象
}, 200);
}, false);
因为setTimeout是window对象的方法,因此此时的this也理所当然的指向window。详细原因是setTimeout里面执行的匿名函数会隐式改变其this的指向,指向window
5.下面代码输出什么,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john) //通过call方法把this值指向john这个对象,所以输出'John'
call具有改变this指向的作用。
6. 以下代码有什么问题,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指什么
this.showMsg(); //报错
})
},
showMsg: function(){
console.log('Huo');
}
}
this.showMsg()
this指向遭到改变,当$btn进行监听时,里面的this指向就变成了$btn;
主食----原型链
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();
p.__proto__ === Person.prototype
Person.prototype.constructor === Person
p.__proto__.constructor === Person
Object.prototype.__proto__ === null
- Person是构造函数,也是一个对象,这个对象里面存在一个prototype属性,而构造函数内部定义了实例的属性和方法,这些属性和方法是属于该类的所有实例的特征;
- p是通过构造函数Person构造出来的实例,也是拥有proto属性。所以p.proto === Person.prototype;
- prototype是构造函数内部的原型对象,所以拥有contructor和proto属性,其中contructor属性指向构造函数Person,proto指向该对象的原型
8.上例中,对对象 p可以这样调用 p.toString()。toString是哪里来的? 画出原型图?并解释什么是原型链。
-
toString是
p.__proto__(Person.prototype).__proto__(Object.prototype)
所拥有的方法,先从p
找,没有就p.__proto__
找,再没有就p._proto__.__proto__
找,直到找到为止。 - 因此,原型链就像上面一样,每个对象都有一个
__proto__
,而每个__proto__
都指向他所创造的prototype
,直到Object.prototype
,而Object.__proto__ == null
,null
没有原型,因此终结。这条链就是原型链, - 也可以简写成
__proto__.__proto__.__proto__——>null (Object)

9.对String做扩展,实现如下方式获取字符串中频率最高的字符
String.prototype.getMostOften = function(){
var obj = {};
for (var i = 0; i < str.length; i++) {
var k = str[i]; //str[i]指的是第几个字母
if (!obj[k]) {
obj[k] = 1; //第一次出现
} else {
obj[k]++; //同样的字母+1
}
}
//遍历对象,找到次数最多的;
var max = 0,val;
for (var key in obj) {
if (obj[key] > max) { //obj[key] == obj.key
max = obj[key]; //进行比较,找到出现最多次数的,并赋值
val = key;
} else {
obj[k]++;
}
}
return val + '出现了' + max + '次';
}
var str = 'aabbbbc';
var ch = str.getMostOften();
console.log(ch)
10. instanceOf有什么作用?内部逻辑是如何实现的?
-
instanceof
运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。 -
instanceof
正是通过探测obj.__proto__.__proto__... === Constructor.prototype
来验证obj
是否是Constructor
的实例
甜品 ----继承
11. 继承有什么作用?
继承就是通过构造函数和原型链,让子类拥有父类的的属性和方法,无需重写一次代码,实现代码重用,同时子类可以添加和修改新的属性和方法,不影响父类。
12. 下面两种写法有什么区别?
//方法1
function People(name, sex){
this.name = name;
this.sex = sex;
this.printName = function(){
console.log(this.name);
}
}
var p1 = new People('Guangzhou', 2)
//方法2
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('Huo', 27);
- 方法一中是通过构造函数People中添加属性和方法,每生成一个实例就会占用里面所拥有的方法和属性的内存
- 方法二中在构造函数People的原型上添加方法,并且共用printName这个方法,达到节省内存的目的。
13. Object.create 有什么作用?兼容性如何?
- 它是es5里面的一种可以继承原型的方法,第一个参数是要继承的原型,如果不是一个子函数,可以传一个null,第二个参数是对象的属性描述符,这个参数是可选的。支持IE9以上及各w3c浏览器。
- 不过单纯地使用Object.create时,原型里的constructor依然是指向要继承的原型,导致判断错误,我们可以写以下函数来改变constructor。
function inherit(superType, subType){
var _prototype = Object.create(superType.prototype);
_prototype.constructor = subType;
subType.prototype = _prototype;
}
14. hasOwnProperty有什么作用? 如何使用?
hasOwnProperty()
方法会返回一个布尔值,指示对象是否具有指定的属性作为自身(不继承)属性。hasOwnProperty()
不会查找原型链,只查找对象本身的自身属性
function Person(name){
this.name = name;
}
var a = new Person(name);
a.hasOwnProperty('name') // true;
a.hasOwnProperty('constructor') //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;
}
在Male的构造函数中,借助了call方法,将父级的构造函数执行了一次并复制了一份。因此构造函数Male继承了Person的属性,其中的this指向是从Person中new出来的实例对象,call保证了this的指向正确。
16. 补全代码,实现继承
function Person(name, sex) {
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function () {
console.log('my name is:'+ this.name);
console.log('my sex is:' + this.sex);
};
function Male(name, sex, age) {
Person.call(this,name,sex);
this.age = age;
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function () {
console.log('my age is:' + this.age)
};
var huo= new Male('霍, '男', 21);
huo.printName();
huo.getAge();