mission-35

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

在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。在说区别之前还是先总结一下三者的相似之处:

都是用来改变函数的this对象的指向的。
第一个参数都是this要指向的对象。
都可以利用后续参数传参。

区别在哪里的,先看一个例子


var xw={ name: "小王",
gender: "男", age: 24,
say: function(){
alert(this.name+" , "+this.gender+" ,今年"+this.age);
}}
var xh={
name: "小红",
gender: "女",
age: 18
}
xw.say();

本身没什么好说的,显示的肯定是小王 , 男 , 今年24。那么如何用xw的say方法来显示xh的数据呢。对于call可以这样:
xw.say.call(xh);

对于apply可以这样:
xw.say.apply(xh);

而对于bind来说需要这样:
xw.say.bind(xh)();

如果直接写xw.say.bind(xh)是不会有任何结果的,看到区别了吗?call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以。那么call和apply有什么区别呢?我们把例子稍微改写一下。


var xw={ name: "小王",
gender: "男", age: 24,
say: function(school,grade){
alert(this.name+" , "+this.gender+" ,今年"+this.age+" ,在"+school+"上"+grade);
}}
var xh={
name: "小红",
gender: "女", age: 18
}

可以看到say方法多了两个参数,我们通过call/apply的参数进行传参。对于call来说是这样的
xw.say.call(xh,"实验小学","六年级");

而对于apply来说是这样的
xw.say.apply(xh,["实验小学","六年级"]);

看到区别了吗,call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。那么bind怎么传参呢?它可以像call那样传参。
xw.say.bind(xh,"实验小学","六年级")();

但是由于bind返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。
xw.say.bind(xh)("实验小学","六年级");

Q2: 以下代码输出什么?


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

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


func()
function func() {
alert(this)
}//[object Window];这里this指的是全局window

Q4:下面代码输出什么


document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);//#document和window;这里setTimeout里的this指全局的window

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


var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)//John;这里this指的是john,所以alert(this)

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


var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指btn
this.showMsg();
}.bind(this))//可以让this.showMsg()中的this指module
},
showMsg: function(){
console.log('饥人谷');
}
}

原型链相关问题

Q7:有如下代码,解释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();

mission-35_第1张图片
关系图

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

mission-35_第2张图片
原型图

如图,使用一个构造函数创造一个实例对象,在此对象上调用相应的属性和方法时,首先查找它本身有没有,如果没有,则顺着proto这个指针去找它的构造函数的原型上有没有,如果没有,再顺着原型的proto向上去找,也就是说,只要存在proto这个指针,在没有找到对应的属性与方法时,查找不会停下,直到没有proto为止,这样的一种形式可行的结构基础就叫原型链。

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

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


String.prototype.getMostOften = function(){
var tmp = this.split("").sort(),
count = 1,
max = 1,
maxS = "";
for(var i=0;i if( tmp[i] == tmp[i+1]){
count++;
console.log(tmp[i]);
}
else{ //不相等了,才开始统计次数
if(count > max){
max = count;
maxS = tmp[i];
count = 0; //不要忘记count需要清0!
}
}
}
console.log("s",maxS);
return maxS;
}

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

instanceof的作用是:判断一个对象是否是某个构造函数的实例,通过检测某个构造函数的原型是否存在于要检测的对象的原型链上。例子如下:


function Person(){}
var p1 = new Person();
p1 instanceof Person; // true
p1 instanceof Object; // true
var obj = new Object();
obj instanceof Person; // false
obj instanceof Object; // true

例如我们需要判断A是否为B的一个实例:
instanceof会通过判断表达式A.proto === B.prototype 是否返回true来判断。
如果返回false,则再判断A.proto.proto === B.prototype是否为true,据此不断的进行迭代。即是:沿着A的 proto 一直寻找到原型链末端,直到等于B.prototype为止。中途或者直到末端,两者相等了,就说明A是B的实例。如果直到末端,仍不相等,说明A不是B的实例。
总结一下,就是判断:B.prototype是否在A.proto的原型链上。

继承相关问题

Q11:继承有什么作用?

通过原型链中的属性继承达到缩减代码长度,让代码更加简洁明了的作用。

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


//方法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);


第二种方法将函数添加到构造函数的原型中。这样在构造实例时可以节省内存,但更大的区别体现在结构上。

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

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


var obj = {b:1};
var subObj = Object.create(obj);
console.log(subObj);

//相当于我们创建了一个新的对象,新对象有一个属性proto = obj,然后 subObj = 新对象。
通过Object.create(obj)能够把继承应用到原型链上,并创建新的下一级原型链空间,比如fun.prototype = Object.create(Person.prototype);通过这种方式能将Person类中的prototype原型上的方法继承到fun.prototype.proto下面
目前支持该方法的浏览器有IE9+,Firefox4+, Safari5+,Opera12+ 和Chrome。IE 6 7 8 不支持

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

hasOwnPerperty是Object.prototype的一个方法,可以判断一个对象是否包含自定义属性而不是原型链上的属性,hasOwnProperty是JavaScript中唯一一个处理属性但是不查找原型链的函数


function Person(){
this.age = 25;
}
Person.prototype.name = 'xxx';
var me = new Person();
console.log(me.hasOwnProperty('age'));//true
console.log(me.hasOwnProperty('name'));//false
console.log(me.proto.hasOwnProperty('name'));//true

Q15:如下代码中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的函数的执行环境传入到Person上,这样,当我们new Male()的时候,会首先创建一个空对象,然后将空对象传入到Person中,添加name和sex属性,然后再添加age属性,最后再返回出来,这样我们就得到了一个有name、sex和age属性的对象。

Q16: 补全代码,实现继承


function Person(name, sex){
// todo ...
}
Person.prototype.getName = function(){
// todo ...
};
function Male(name, sex, age){
//todo ...
}
//todo ...
Male.prototype.getAge = function(){
//todo ...
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();


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;
}
//继承,修改constructor
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function(){
console.log(this.age);
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.getAge();

你可能感兴趣的:(mission-35)