this 相关问题
1: apply、call 、bind有什么作用,什么区别
call apply,调用一个函数,传入函数执行上下文及参数
var value = 100
var obj = {
value: 200
}
function fn(a, b){
console.log(this.value + a + b)
}
fn(3, 4) //107, 因为 fn 中的 this 指全局对象 window
fn.call(obj, 3, 4) //207 指定fn中的执行上下文 obj,接着传入fn的参数 3, 4
fn.apply(obj, [3, 4]) //207 apply和call基本一样,只是使用方法不一样,apply第二个参数为数组,用来传入fn中
bind,返回一个新函数,并且使函数内部的this为传入的第一个参数
var obj1 = {
name: 'Neo',
fn: function(){
console.log(this) //{name: "Neo", fn: ƒ}
}
}
var obj2 = {a: 2}
var fn2 = obj1.fn.bind(obj2) //指定fn中 this 为 obj2
fn2() // 输出obj2:{a: 2} 如果给fn2赋值的时候没有使用bind,则此时输出obj1:{name: "Neo", fn: ƒ},因为赋值时,是obj1对象在调用其方法 fn
2: 以下代码输出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()
输出 John: hi!
首先把func赋值给了john对象的方法sayHi,然后john调用sayHi
对象调用方法时,方法中的this绑定到该对象
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 DOM对象 和 window对象
DOM对象绑定事件时,传入的函数中的this绑定到该DOM对象
setTImeout 和 setInterval 这两个方法执行的函数中的this绑定到全局对象window
5:下面代码输出什么,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)
输出 John
func调用call方法来执行时,call中传入john对象,意在绑定func中的this为john对象
6: 以下代码有什么问题,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指 $btn
this.showMsg();
})
},
showMsg: function(){
console.log('前端');
}
}
在事件监听函数中 this.showMsg(), this指代 $btn 这个jQuery对象,并不代表module对象,因此 this.showMsg() 相当于 $btn.showMsg()
想要在事件监听函数中 调用module 的方法,可以人为把this绑定到module对象,使用 bind() 即可:
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //现在this指module对象
this.showMsg();
}.bind(this))
},
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();
p是Person类创建的实例对象,p具有_ proto_属性,指向Person的prototype属性,prototype对象有constructor属性,指向了Person,prototype也有_ proto_属性,因为prototype也是个对象,是由Object类生成的实例。
同时Person也有_ proto_属性,指向了Function的prototype,Function 可以理解为函数之父,包括Person类 和 Object类都是Function创建的,同时Function创建了自己。
8: 上例中,对对象 p可以这样调用 p.toString()。toString是哪里来的? 画出原型图?并解释什么是原型链
如图所示,p自身没有toString,就到Person类的prototype去找,也没有,prototype是个对象,由Object类创建,但是仍然没有toString,所以继续到prototype的_ proto _ 也就是Object的prototype中去找,最终找到了toString方法。
以上读取toString属性的搜索过程,是沿着由_ proto _ 组成的链子一直走的,这个链子,就叫做『原形链』
9:对String做扩展,实现如下方式获取字符串中频率最高的字符
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次
方法如下:
<script>
String.prototype.getMostOften = function(){
//声明空对象,和只有一个值的数组(数组是对象,便于后面存储其他属性)
var obj = {}, temp = [0]
//遍历调用其的this字符串,如果obj有当前属性,则 +1,没有则创建当前属性,并赋初值为 1
for(var i = 0; i < this.length; i++){
if(obj[this[i]]){
obj[this[i]]++
}else{
obj[this[i]] = 1
}
}
//得到对象后,格式如: {a: 2, b:3, c:1}
//接着遍历对象,当前属性值如果大于temp数组存的值,则去覆盖temp数组,同时给temp数组(对象)添加key属性,用于存储字符名
for(var key in obj){
if(obj[key] > temp[0]){
temp[0] = obj[key]
temp.key = key
}
}
//如此便能迭代出次数最高的字符
return '出现最多次的是:' + temp.key + ',次数是:' + temp[0]
}
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次
</script>
10: instanceOf有什么作用?内部逻辑是如何实现的?
instanceof操作符,我们常用来判断一个对象是不是某个类型的实例。
实际上,instanceof 运算符正是用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
如果一个对象通过沿着 _ proto _ 组成的原形链一层层查找其constructor属性,如果找到了则,该对象是某类型的实例。
之前的例子中,p就是Person的实例,也是Object的实例,因为可以通过原形链最终找到constructor指向了Person或者Object。
继承相关问题
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('晓风', 23);
直观的区别是:
- 方法1中, 把printName方法直接定义在了构造函数里;
- 而方法2中,把printName方法写入到Person类的原型上。
间接的影响是:
- 方法1每次构造新的对象,都会给对象绑定printName方法,存在浪费;
- 方法2 中的p1对象继承了Person类原型上的printName方法,以后再构造新对象,也是引用自类的原型上的方法,节省了内存(虽然本例中感觉微乎其微),也便于后续维护,因为直接修改原型即可。
13: Object.create 有什么作用?兼容性如何?
Object.create方法,可以创建一个拥有指定原型和属性的新对象
比如:
Student.prototype = Object.create(Person.prototype)
创建一个新对象,指定这个新对象的 _ _ proto_ _ 为Person.prototype,然后把这个对象赋值给prototype,为什么不能直接赋值?因为存在引用关系,修改了子类原型,其父类原型也会改变,所以需要clone一份,再去赋值。
Object.create是ES5中的方法,如果要兼容性更好一些,可以通过如下方法,手动创建空对象(只拥有_ _ proto_ _ ),并且这个空对象的构造函数的原型已经指向了Person.prototype,然后把这个对象赋值给Student.prototype
fn.prototype = Person.prototype
function fn(){}
Student.prototype = new fn()
14: hasOwnProperty有什么作用? 如何使用?
hasOwnPerperty是Object.prototype的一个方法,用来判断一个对象是否包含自定义属性而不是原型链上的属性
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('晓风', 23)
p1.hasOwnProperty('name') //true
p1.hasOwnProperty('printName') //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执行上下文中的this 为当前Male创建的新对象。
在Male构造函数中执行Person构造函数,并且指定了this。
这样通过Male构造出的对象,便能继承拥有Person中的属性,也就是name 和sex。
出了使用call,还可以使用bind方法,也是指定this:
Person.bind(this)(name, sex)
16: 补全代码,实现继承
function Person(name, sex){
// todo ...
}
Person.prototype.getName = function(){
// todo ...
};
function Male(name, sex, age){
//todo ...
}
//todo ...
Male.prototype.getAge = function(){
//todo ...
};
var xiaofeng = new Male('晓风', '男', 23);
xiaofeng.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
}
Male.prototype = Object.create(Person.prototype) //继承方法
Male.prototype.constructor = Male //修正constructor
Male.prototype.printName = function(){
console.log(this.name)
}
Male.prototype.getAge = function(){
console.log(this.age)
};
var xiaofeng = new Male('晓风', '男', 23);
xiaofeng.printName();