前端面试题——JS合集

。。。之前已经整理了一版了,迷之没了,哭泣


Explain event delegation

利用冒泡的原理,把事件加到父级上,触发执行效果。
使用情景:
  •为DOM中的很多元素绑定相同事件;
  •为DOM中尚不存在的元素绑定事件;
例如:

<ul id="parent-list">
    <li id="post-1">Item 1</li>
    <li id="post-2">Item 2</li>
    <li id="post-3">Item 3</li>
    <li id="post-4">Item 4</li>
    <li id="post-5">Item 5</li>
    <li id="post-6">Item 6</li>
</ul>

给每个独立的li元素添加事件监听器十分繁琐,如果有新增或删除事件将会是一场噩梦
如果将事件添加在父元素ul上,当子元素的事件冒泡到父元素时,可以检查事件对象的target属性,捕获真正被点击的节点元素的引用。

在jQuery中,

$(function(){ 
    $('#ul1,#ul2').delegate('li','click',function(){ 
        if(!$(this).attr('s')) { 
        $(this).css('background','red'); 
        $(this).attr('s',true); 
        }else { 
            $(this).css('background','#fff'); 
            $(this).removeAttr('s'); 
        } 
    }) 
});

最新on方法替代了delegate

$(function(){ 
        $('#ul1,#ul2').on('click','li',function(){ 
            if(!$(this).attr('s')) { 
            $(this).css('background','red'); 
            $(this).attr('s',true); 
            }else { 
                    $(this).css('background','#fff'); 
                    $(this).removeAttr('s'); 
            } 
        }) 
});

Explain how ‘this’ works in JavaScript

this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用
this的指向并不看在哪里定义,而是看在哪里使用。

  • 纯粹的函数调用

属于全局性调用,this就代表全局对象Global

var x = 1; 
function test(){ 
  alert(this.x); 
} 
test(); // 1 
function test(){ 
 this.x = 1; 
 alert(this.x); 
} 
test(); // 1 
var x = 1; 
function test(){ 
  this.x = 0; 
} 
test(); 
alert(x); //0 
  • 作为对象方法的调用
function test(){ 
    alert(this.x); 
} 
var o = {}; 
o.x = 1; 
o.m = test; 
o.m(); // 1 

将test方法复制给了o.m
最终由o这个对象调用了该方法(所以方法中的this此时就是o)

  • 作为构造函数调用
function test(){ 
    this.x = 1; 
  } 
var o = new test(); 
alert(o.x); // 1 

通过这个函数生成一个新对象(object)。这时,this指这个新对象。

  • apply调用
var x = 0; 
function test(){ 
    alert(this.x); 
} 
var o={}; 
o.x = 1; 
o.m = test; 
o.m.apply(); //0 
o.m.apply(o); //1

apply参数为空时表示全局变量
用括号内的对象执行前面的方法。

举例~

var x = 10;
function func() {
  alert(this.x)
}
var obj = {
  x: 20,
  fn: function() {
    alert(this.x)
  }
}
var fn = obj.fn
func() // 10
fn() // 10

可以看到 var fn = obj.fn,此句话只是将obj的fn方法赋值给了fn,并没有执行。
最终执行fn时并没有对象绑定在上面,所以this还是全局调用。

  • ES6 箭头函数(arrow function) 和 this
    箭头函数的特征就是,定义在哪,this 就指向那。即箭头函数定义在一个对象里,那箭头函数里的 this 就指向该对象。
var book = {
  author: 'John Resig',
  init: function() {
    document.onclick = ev => {
      alert(this.author) ; // 这里的 this 不是 document 了
    }
  }
};
book.init()

对象 book 里有一个属性 author, 有一个 init 方法, 给 document 添加了一个点击事件,如果是传统的函数,我们知道 this 指向应该是 document,但箭头函数会指向当前对象 book。

Explain how prototypal inheritance works

  • 原型链
    每个函数(或者说构造器)都有一个原型属性prototype指向自身的原型
    而由这个函数创建的对象有一个_ proto _属性,指向这个原型
    每个函数都是Function函数创建的对象,所以每个函数也有一个_ proto _属性指向Function函数的原型
    真正形成原型链的是每个对象的_ proto _属性,而不是函数的prototype属性
 Function.prototype = {
        constructor : Function,
        __proto__ : parent prototype,
        some prototype properties: ...
    };

所有的实例是共享同一个原型对象,因此有别于实例方法或属性,原型对象仅有一份。
在js中,对象在调用一个方法时会首先在自身里寻找是否有该方法,若没有,则去原型链上去寻找,依次层层递进。

  • 原型继承
Child.prototype = new Parent() ;

使得Child原型继承了Parent的原型对象的所有成员,但是也使得Child的实例对象的构造器的原型指向了Parent原型,即

var ch = new Child();
console.log(Child.prototype.constructor === Parent);  //true
console.log(ch.constructor === Parent);       //true

所以需要加一步修正

Child.prototype.constructor = Child;

What do you think of AMD vs CommonJS?

JS模块化的概念。

  • CommonJS
    nodeJS遵循
    CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}
    require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。
    CommonJS是主要为了JS在后端的表现制定的,不适合前端
  • AMD
    RequireJS遵循
    异步模块定义
    只有一个接口:define(id?,dependencies?,factory)
    要在声明模块的时候制定所有的依赖(dep),所有的依赖模块都是先执行,推崇依赖前置。
  • CMD
    seaJS遵循
    与AMD蛮相近,但是CMD推崇依赖就近。CMD 的 API 严格区分,推崇职责单一。

Explain why the following doesn’t work as an IIFE: function foo(){ }();. What needs to be changed to properly make it an IIFE?

function foo(){ }();相当于
function foo(){ };
();
因为 function foo(…){} 这个部分只是一个函数声明,对于解释器来说,就好像你写了一个字符串 “function foo(…){}”
而JS解释器会把()中的语句当做一个表达式,为空的话则会报错。

使用括号将上述代码括起来就不会报错,形成了一个IIFE(立即执行函数)
(function foo() {…}) ();
(function foo(){ }());
小括号能把我们的表达式组合分块,并且每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。
当我们用一对小括号把匿名函数括起来的时候,实际上小括号对返回的,就是一个匿名函数的Function对象。因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。

也可以通过一元操作符+变成了函数表达式。还可以使用 - ~ !等其他一元运算符或者括号,目的是为了引导解析器,指明运算符附近是一个表达式。

+function () {   
};  

(function () {  
});  

void function() {  
};  

What’s the difference between a variable that is: null, undefined or undeclared? How would you go about checking for any of these states?

null

null是一个对象,但是为空。typeof null 返回的是 ‘object’ 。
表示“无值(no value)”
null 是 JavaScript 保留关键字。
null 参与数值运算时其值会自动转换为 0
表达式:123 + null    结果值:123
表达式:123 * null    结果值:0

undefined

undefined是全局对象(window)的一个特殊属性,其值是未定义的。但 typeof undefined 返回 ‘undefined’ 。
表示不存在的值(non-existence of a value)
例如:定义一个变量但未赋予其初始值
undefined参与任何数值计算时,其结果一定是NaN。

undeclared

变量在使用前未声明。
尝试访问一个undefined 的变量,浏览器不会报错,但会返回undefined。
尝试访问一个undeclared的变量,浏览器会报错,JS执行会中断。

What is a closure, and how/why would you use one?

有时候需要得到函数内的局部变量,需要在函数的内部,再定义一个函数。
子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

 function f1(){
    n=999;
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999

f2函数,就是闭包
最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

What’s a typical use case for anonymous functions?

匿名函数就是没有实际名字的函数。
 要调用一个函数,必须要有方法定位它,引用它。所以,我们会需要帮它找一个名字。例如:

view plaincopy to clipboardprint?
var abc=function(x,y){  
  return x+y;  
}  
alert(abc(2,3)); // "5"  

或者采用立即执行函数进行调用。jQuery库采用的就是这种方式

How do you organize your code? (module pattern, classical inheritance?)

模块模式,类式继承?

始终声明我们的依赖
为第三方代码库添加shim(垫片)
定义跟调用应该分离
依赖应该异步加载
模块不应依赖全局变量

What’s the difference between host objects and native objects?

本地对象 native objects

Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError
简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。
需要new

内置对象 built-in objects

同样是“独立于宿主环境”。根据定义我们似乎很难分清“内置对象”与“本地对象”的区别。而ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
不需要new

宿主对象 host object

BOM DOM & 自定义对象

Difference between: function Person(){}, var person = Person(), and var person = new Person()?

function Person(){}

函数声明,独立的函数变量,可视为构造器(类)

var person = Person()

把Person()函数的运行结果赋值给person

var person = new Person()

使用关键字new,创建一个构造函数(类)的实例

举例

function Test() {  
  this.name = 'Test';  
  return 'Test';  
}  

var fnT = Test();  
var newT = new Test();  

这里写图片描述

如果函数返回值为常规意义上的值类型(Number、String、Boolean)时,new函数将会返回一个该函数的实例对象,而如果函数返回一个引用类型(Object、Array、Function),则new函数与直接调用函数产生的结果等同。==》一个看到的猜测

What’s the difference between .call and .apply?

用途相同,都是在特定的作用域中调用函数。
接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。

Explain Function.prototype.bind.

在JavaScript中,经常用到函数绑定,当需要在另一个函数中保持this上下文时,使用Function.prototype.bind()会很方便,在调用.bind()时,它会简单的创建一个新的函数,然后把this传给这个函数。
IE8及以下的IE浏览器并不支持Function.prototype.bind()
实现方式大致如下所示:

Function.prototype.bind = function (scope) {
    var fn = this;
    return function () {
        return fn.apply(scope);
    };
}
var foo = {
    x: 3
};
var bar = function(){
    console.log(this.x);
};
bar(); // undefined
var boundFunc = bar.bind(foo);  //返回的是一个函数
boundFunc(); // 3

call、apply、bind:
都是用来改变函数的this对象的指向的;
第一个参数都是this要指向的对象;
都可以利用后续参数传参;
bind是返回对应函数,便于稍后调用,apply、call是立即调用

When would you use document.write()?

在载入页面后,浏览器输出流自动关闭。在此之后,任何一个对当前页面进行操作的document.write()方法将打开—个新的输出流,它将清除当前页面内容(包括源文档的任何变量或值)。
脚本向窗口(不管是本窗口或其他窗口)写完内容后,必须关闭输出流。在延时脚本的最后一个document.write()方法后面,必须确保含有document.close()方法,不这样做就不能显示图像和表单。并且,任何后面调用的document.write()方法只会把内容追加到页面后,而不会清除现有内容来写入新值。

What’s the difference between feature detection, feature inference, and using the UA string?

特征检测 feature detection

特征检测检查特征是否存在

if (window.XMLHttpRequest) {
    new XMLHttpRequest();
}

特征推断 feature inference

检测的方式和特征检测类似,不过使用另一个特征进行推断,假设A存在的情况下B也会存在。

if (document.getElementsByTagName) {
    element = document.getElementById(id);
}

UA字符串 UA String

用户代理字符串(User Agent)是浏览器用来标识自身信息的一串字符

if (navigator.userAgent.indexOf("MSIE 7") > -1){
    //do something
}

此做法比较陈旧,不推荐使用。

Explain Ajax in as much detail as possible.

Ajax 是 Asynchronous JavaScript and XML的缩写
XMLHttpRequest 对象是处理所有服务器通信的对象

Ajax 基本上是把JavaScript技术和XMLHttpRequest对象放在Web表单和服务器之间。
当用户填写表单时,数据发送给一些JavaScript代码而不是直接发送给服务器。JavaScript 代码捕获表单数据并向服务器发送请求。
JavaScript代码在幕后发送请求,XMLHttpRequest可以根据需要自行与服务器进行交互,用户可以完全不知道幕后发生的一切。请求是异步发送的,JavaScript代码(和用户)不用等待服务器的响应。因此用户可以继续输入数据、滚动屏幕和使用应用程序。

Ajax应用程序中基本的流程:

1、从 Web 表单中获取需要的数据。 
2、建立要连接的 URL3、打开到服务器的连接。 
4、设置服务器在完成后要运行的函数。 
5、发送请求。 

示例如下:

function callServer() {
  // Get the city and state from the web form
  var city = document.getElementById("city").value;
  var state = document.getElementById("state").value;
  // Only go on if there are values for both fields
  if ((city == null) || (city == "")) return;
  if ((state == null) || (state == "")) return;

  // Build the URL to connect to
  var url = "/scripts/getZipCode.php?city=" + escape(city) + "&state=" + escape(state);

  // Open a connection to the server
  xmlHttp.open("GET", url, true);

  // Setup a function for the server to run when it's done
  xmlHttp.onreadystatechange = updatePage;

  // Send the request
  xmlHttp.send(null);
}

需要注意的是,xmlHttp.onreadystatechange要在send前设置

处理响应:

function updatePage() {
  if (xmlHttp.readyState == 4) {
    var response = xmlHttp.responseText;
    document.getElementById("zipCode").value = response;
  }
}

什么也不要做,直到 xmlHttp.readyState 属性的值等于 4。 服务器将把响应填充到 xmlHttp.responseText 属性中。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值