前端基础问题整理-JavaScript相关(一)

前端基础问题整理-JavaScript相关(二)

请解释事件代理(event delegation)

事件代理也称为事件委托,利用了事件冒泡。例如:

1
2
3
4
5
<ul class="item-list">
   <li class="item">item1</li>
   <li class="item">item2</li>
   <li class="item">item3</li>
</ul>

当页面li增多时单独给每个li元素添加事件处理程序既繁琐又容易出错,利用事件冒泡,在ul去监听事件,li产生事件往上冒泡时去捕获,利用e.target来判断是否为我们的目标元素,是的话就可以做相应操作了。

请解释JavaScript中this是如何工作的。

作为独立函数的调用

1
2
3
4
5
6
function func() {
    console.log(this);
}
 
func();
//Window

全局作用域中声明一个函数,并调用它,此时函数中的this指向全局对象。

作为对象方法调用

1
2
3
4
5
6
7
8
9
10
11
function say() {
    console.log(this);
}
 
var obj = {
    name: "f2er",
    say: say
};
 
obj.say();
//Object {name: "f2er"}

当函数作为一个对象的方法调用时,函数中的this绑定到了这个对象。

使用call或apply来调用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function func() {
    console.log(this);
}
 
var obj = {
    name: "f2er"
};
 
func.call(obj);
//Object {name: "f2er"}
 
func.apply(obj);
//Object {name: "f2er"}

当使用call()或apply()函数进行函数调用时,传入参数对象的将被设置为函数体内this的值,这两个函数都是设置调用函数体内的this值的,且第一个参数都为this,区别是第二个参数apply()是一个参数arguments(类数组对象),而call(),传递给他的是一系列参数。

new来调用函数

1
2
3
4
5
6
7
function F2er(name) {
    this.name = name;
    console.log(this);
}
 
var f2er = new F2er('f2er');
// F2er {name: "f2er"}

当使用new来调用一个函数时,会创建一个新的对象,然后绑定到Dog()调用中的this。

请解释原型继承(prototypal inheritance)的原理。

先上一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Super() {
    this.superValue = "super";
}
 
Super.prototype.getSuperValue = function() {
    return this.superValue;
}
 
function Sub() {
    this.subValue = "sub";
}
 
var superInstance = new Super();
 
Sub.prototype = superInstance;
 
Sub.prototype.getSubValue = function() {
    return this.subValue;
}
 
var instance = new Sub();
console.log(instance.getSuperValue());
// super

每个函数Sub都有一个属性prototype,prototype指向一个原型对象,原型对象中也有一个指向函数的属性constructor,通过new一个函数Sub可以产生实例instance,调用这个instance的某个属性或方法时,instance会先查找自身是否有这个方法或者属性,没有的话就会去实例的构造函数Sub的原型prototype中查找,即Sub.prototype,如果给原型对象Sub.prototype赋予另一个类型的实例superInstance,则是在superInstance中查找的,这个superInstance中也有属性prototype指向某个原型对象,以此一级级往上最终到Object.prototype,这样就形成了原型继承。

利用此原理可以自己实现一个inherits函数:

1
2
3
4
5
function inherits(subType, superType) {
    var _prototype = Object.create(superType.prototype);
    _prototype.constructor = subType;
    subType.prototype = _prototype;
}

IIFE(立即调用的函数表达式)是什么?有什么作用?

(function fn(){..})(),函数被包含在一个括号内,变成为一个表达式,随后跟着一个(),就立即执行这个函数,
这种模式就是立即执行函数表达式(Immediately Invoked Function Expression),简称IIFE。

也有用(function fn(){..}())后面的括号在前面的括号内这种形式表示的,这两种形式在功能上都是一致的。

IIFE的一些作用:

创建作用域,内部保存一些大量临时变量的代码防止命名冲突。
一些库的外层用这种形式包起来防止作用域污染。
运行一些只执行一次的代码。

1
2
3
4
5
(function() {
    var module = require('module');
    module.setup();
    module.run();
})();

用闭包保存状态

以下点击页面标签的时候,实际并不是弹出每个具体的i的,而是elems.length,因为每个a监听器中引用的i都是同一个作用域的。

1
2
3
4
5
6
7
8
var elems = document.getElementsByTagName('a');
 
for (var i = 0; i & lt; elems.length; i++) {
    elems[i].addEventListener('click'function(e) {
        e.preventDefault();
        alert('I am link #' + i);
    }, 'false');
}

以下点击页面标签的时候,每一个i传入一个IIFE,IIFE形成单独一个作用域保存了当时的i值,所以点击a标签,可以弹出不同的i值。

1
2
3
4
5
6
7
8
9
10
var elems = document.getElementsByTagName('a');
 
for (var i = 0; i &lt; elems.length; i++) {
(function (lockedInIndex) {
elems[i].addEventListener('click'function (e) {
e.preventDefault();
alert('I am link #' + lockedInIndex);
}, 'false');
})(i);
}

什么是闭包(closure),有什么作用?

闭包是指有权访问另一个函数作用域中的变量的函数。
闭包的作用
避免全局变量的污染
实现内部变量真正的私有化
闭包的缺点
常驻内存,会增大内存使用量,易造成内存泄露

请指出 JavaScript 宿主对象和原生对象的区别?
宿主对象是指DOM和BOM。
原生对象是Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math等对象。

请指出以下代码的区别:function Person(){}、var person = Person()、var person = new Person()?
function Person(){}
声明一个函数Person()。

var person = Person()
将函数Person()的结果返回给变量person,如果没有返回值则person为undefined。

var person = new Person()
new一个Person的实例对象。

.call和.apply的区别是什么?

.call和.apply的共同点是都是用来改变函数体内this对象的值。

区别是第二个参数不一样。apply()的第二个参数是一个类数组对象arguments,参数都是以数组的形式传入,而call(),传递给他的是一系列参数。例如

1
2
3
4
5
Math.max.call(null, 1, 2, 3, 4);
//4
 
Math.max.apply(null, [1, 2, 3, 4]);
//4

请解释Function.prototype.bind
Function.prototype.bind方法会创建一个新函数,当这个新函数被调用时,它的this值是传递给bind()的第一个参数, 它的参数是bind()的其他参数和其原本的参数.
Function.prototype.bind的实现类似于:

1
2
3
4
5
6
Function.prototype.bind = function(scope) {
    var fn = this;
    return function() {
        return fn.apply(scope, arguments);
    };
}

Function.prototype.bind的作用

创建绑定函数

一些函数的参数常常也是函数,给当做参数的函数绑定this值确保参数函数执行时有正确的this指向。

转自: https://segmentfault.com/a/1190000005985882

虚拟主机
《JavaScript高级程序设计(第3版)》PDF
《JavaScript设计模式与开发实践 》PDF
《编写高质量JavaScript代码的68个有效方法》PDF
《JavaScript基础教程(第8版)》PDF
广告也精彩