web前端最新最全面试题总结(JavaScript)

DOM事件模型

DOM事件流

DOM的结构是一个树形,每当HTML元素产生事件时,该事件就会在树的根节点和元素节点之间传播,所有经过的节点都会收到该事件。

DOM事件模型分为两类:

  • 一类是IE所使用的冒泡型事件(Bubbling);
  • 另一类是DOM标准定义的冒泡型与捕获型(Capture)的事件。
  • 除IE外的其他浏览器都支持标准的DOM事件处理模型。

冒泡型事件处理模型(Bubbling)

冒泡型事件处理模型在事件发生时,首先在最精确的元素上触发,然后向上传播,直到根节点。反映到DOM树上就是事件从叶子节点传播到根节点。

捕获型事件处理模型(Captrue)

相反地,捕获型在事件发生时首先在最顶级的元素上触发,传播到最低级的元素上。在DOM树上的表现就是由根节点传播到叶子节点。

标准的DOM事件处理模型

标准的事件处理模型分为三个阶段:

  1. 父元素中所有的捕捉型事件(如果有)自上而下地执行
  2. 目标元素的冒泡型事件(如果有)
  3. 父元素中所有的冒泡型事件(如果有)自下而上地执行

Event事件的常见api方法

  • event.preventDefault(); // 阻止默认事件。
  • 阻止冒泡
    • w3c的方法:(火狐、谷歌、IE11) event.stopPropagation();
    • IE10以下则是: event.cancelBubble = true;

自定义事件

var myEvent = new Event('clickTest');
element.addEventListener('clickTest', function () {
    console.log('smyhvae');
});
//元素注册事件
element.dispatchEvent(myEvent); //注意,参数是写事件对象 myEvent,不是写 事件名 clickTest

事件委托(事件代理)

事件委托的概念

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。 事件委托就是方法的代理。 可以简单理解为自己执行的事件可以让别的元素代替执行。

**事件委托的原理: **

事件委托是利用事件的冒泡原理来实现的 ,就是事件从最深的节点(目标节点)开始,然后逐步向上传播事件

事件委托的优点:

  1. 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
  2. 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
    例子解析:

案例

使用原始方法:

下面的代码的意思很简单,相信很多人都是这么实现的,我们看看有多少次的dom操作,首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li;

## 子节点实现相同的功能:
<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>
## 实现功能是点击li,弹出123:
window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

用事件委托的方式

window.onload = function(){
    var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }
}

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发,不怕,我们有绝招:

Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题):

window.onload = function(){
    var oUl = document.getElementById("ul1");
    oUl.onclick = function(ev){
        var ev = ev || window.event;
        var target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() == 'li'){
            alert(123);
            alert(target.innerHTML);
        }
    }
}

创建对象的常见方式

方式一:字面量
var obj11 = {name: 'smyh'};
var obj12 = new Object(name: `smyh`); //内置对象(内置的构造函数)
# 上面的两种写法,效果是一样的。因为,第一种写法,obj11会指向Object。
第一种写法是:字面量的方式。
第二种写法是:内置的构造函数
方式二:通过构造函数
var M = function (name) {
	this.name = name;
}
var obj3 = new M('smyhvae');
方法三:Object.create
var p = {name:'smyhvae'};
var obj3 = Object.create(p);  //此方法创建的对象,是用原型链连接的
# 这种方式里,obj3是实例,p是obj3的原型(name是p原型里的属性),构造函数是Objecet 。
方式四:通过工厂模式
function createPerson(name,age,job){
    var o=new Object();
    o.name=name;
    o.age=age;
    o.job=job;
    o.sayName=function(){
        alert(this.name);
    };
    return 0;
}
var person1=createPerson("Nicholas",29,"Software Engineer");
var person2=createPerson("Greg",27,"Doctor");
## 与工厂模式相比,具有以下特点:
	没有显式创建对象;
	直接将属性和方法赋给了this对象;
	没有return语句;
	要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)
	可以使用instanceof操作符检测对象类型
## 构造函数的问题:
	构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。
  这些问题可通过原型模式解决。
方式五:原型模式
function Person(){
}

Person.prototype.name="Nicholas";
Person.prototype.age=29;
Person.prototype.job="...";
Person.prototype.sayName=function(){
    ...
};
    
var person1=new Person();
person1.sayName();//"Nicholas"

面向对象:类定义的几种方式

类的定义/类的声明

**方式一:**用构造函数模拟类(传统写法)

function Animal1() {
    this.name = 'smyhvae'; //通过this,表明这是一个构造函数
}

**方式二:**用 class 声明(ES6的写法)

class Animal2 {
    constructor() {  //可以在构造函数里写属性
        this.name = name;
    }
}
实例化

类的实例化很简单,直接 new 出来即可。

console.log(new Animal1(),new Animal2()); //实例化。如果括号里没有参数,则括号可以省略

面向对象:类的继承几种方式

方式一 借助构造函数
function Parent(){
    this.name = 'parent的属性'
}
function Child(){
    Parent.call(this);
    this.type = 'child的属性'
}
console.log(new Child)

【重要】上方代码中,最重要的那行代码:在子类的构造函数里写了Parent1.call(this);,意思是:让Parent的构造函数在child的构造函数中执行。发生的变化是:改变this的指向,parent的实例 --> 改为指向child的实例。导致 parent的实例的属性挂在到了child的实例上,这就实现了继承。

**缺点:**这种方式,虽然改变了 this 的指向,但是,Child1 无法继承 Parent1 的原型。也就是说,如果我给 Parent1 的原型增加一个方法,是无法被继承的。

方式二 通过原型链实现继承
 function Parent(){
     this.name = 'parent的属性'
 }
function Child(){
    this.type = 'child的属性'
}

Child.prototype = new Parent()

console.log(new Child)

【重要】上方代码中,最重要的那行:每个函数都有prototype属性,于是,构造函数也有这个属性,这个属性是一个对象。现在,我们把Parent的实例赋值给了Child的prototye,从而实现继承。此时,Child构造函数、Parent的实例、Child的实例构成一个三角关系。于是:

  • new Child.__proto__ === new Parent()的结果为true

分析:

这种继承方式,Child 可以继承 Parent 的原型,但有个缺点:

缺点是:如果修改 child1实例的name属性,child2实例中的name属性也会跟着改变

方式三:组合的方式:构造函数 + 原型链
function Parent3() {
    this.name = 'Parent 的属性';
    this.arr = [1, 2, 3];
}

function Child3() {
    Parent3.call(this); //【重要1】执行 parent方法
    this.type = 'Child 的属性';
}
Child3.prototype = new Parent3(); //【重要2】第二次执行parent方法

var child = new Child3();

这种方式,能解决之前两种方式的问题:既可以继承父类原型的内容,也不会造成原型里属性的修改。

这种方式的缺点是:让父亲Parent的构造方法执行了两次。

方式四:es6中class用extends实现继承
class Person {
    constructor(skin, language) {
        this.skin = skin;
        this.language = language;
    }

    say() {
        console.log('I am a Person, ' + 'skin: ' + this.skin + 'language: ' + this.language)
    }
}

class American extends Person {
    aboutMe() {
        console.log(this.skin + ' ' + this.language)
    }
}

var american = new American('yello', 'chinese')

console.log(american.skin)  // yello
american.say() // I am a Person, skin: yellolanguage: chinese
american.aboutMe() // yello chinese

js的运行机制

程序、进程、线程
  • 程序:由源代码生成的可执行应用。 (例如:QQ.app)

  • 进程:一个正在运行的程序可以看做一个进程,(例如:正在运行的QQ警示),进程拥有独立运行所需要的全部资源

  • 线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)

    一个进程是由一或多个线程组成,进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。

单线程、多线程

单线程

  • 每个正在运行的程序(即进程),至少包括一个线程,这个线程叫主线程
  • 主线程在程序启动时被创建,用于执行main函数
  • 只有一个主线程的程序,称作单线程程序
  • 主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行

多线程

  • 拥有多个线程的程序,称作多线程程序。
  • iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称为子线程
  • 可以根据需要开辟若干子线程
  • 子线程和主线程都是独立的运行单元,各自的执行互不影响,因此能够并发执行
单线程、多线程的区别

单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)

多线程程序:有多个线程,线程间独立运行,能有效地避免代码阻塞,并且提高程序的运行性能

案例:
**多线程与单线程的区别**
生活举例
你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
如果你一手接电话,一手打卡。就是多线程。
2件事的结果是一样的。。你接了电话且打了卡。
JS的异步和单线程

因为是单线程,所以必须异步。

异步的经典案例一:
# 现有如下代码:
    console.log(1);
    setTimeout(function () {
        console.log(2);
    }, 1000);
    console.log(3);
    console.log(4);
# 上面的代码中,我们很容易知道,打印的顺序是1342。因为你会想到,要等一秒之后再打印2。

# 可如果我把延时的时间从1000改成0:

    console.log(1);
    setTimeout(function () {
        console.log(2);
    }, 0);
    console.log(3);
    console.log(4);
# 上方代码中,打印的顺序仍然是1342。这是为什么呢?我们来分析一下。

# 总结:

# js 是单线程(同一时间只能做一件事),而且有一个任务队列:全部的同步任务执行完毕后,再来执行异步任务。第一行代码和最后一行代码是同步任务;但是,setTimeout是异步任务。

于是,执行的顺序是:

先执行同步任务console.log(1)

遇到异步任务setTimeout,要挂起

执行同步任务console.log(3)

全部的同步任务执行完毕后,再来执行异步任务console.log(2)。

很多人会把这个题目答错,这是因为他们不懂 js 的运行机制。

注意上面那句话:同步任务执行完毕后,再来执行异步任务。也就是说,如果同步任务没有执行完,异步任务是不会执行的。为了解释这句话,我们来看下面这个例子。
同步的经典案例一:
console.log('A');

alert('haha'); //1秒之后点击确认

console.log('B');

# alert函数是同步任务,我只有点击了确认,才会继续打印B
同步和异步的对比

我们在上面列举了异步和同步的例子。现在来描述一下区别:【重要】

因为setTimeout异步任务,所以程序并不会卡在那里,而是继续向下执行(即使settimeout设置了倒计时一万秒);但是alert函数是同步任务,程序会卡在那里,如果它没有执行,后面的也不会执行(卡在那里,自然也就造成了阻塞)。

前端使用异步的场景

什么时候需要等待,就什么时候用异步。

  • 定时任务:setTimeout(定时炸弹)、setInterval(循环执行)
  • 网络请求:ajax请求、动态<img>加载
  • 事件绑定(比如说,按钮绑定点击事件之后,用户爱点不点。我们不可能卡在按钮那里,什么都不做。所以,应该用异步)
  • ES6中的Promise

代码举例:

console.log('start');
var img = document.createElement('img');
img.onload = function () {
    console.log('loaded');
}
img.src = '/xxx.png';
console.log('end');

上图中,先打印start,然后执行img.src = '/xxx.png',然后打印end,最后打印loaded

任务队列

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

总结:只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。【重要】

Event Loop (事件循环)

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

事件循环是如何执行的,事件循环器会不停的检查事件队列,如果不为空,则取出队首压入执行栈执行。当一个任务执行完毕之后,事件循环器又会继续不停的检查事件队列,不过在这期间,浏览器会对页面进行渲染。

关于事件循环,我们需要记住以下几点:

  • 事件队列严格按照时间先后顺序将任务压入执行栈执行;
  • 当执行栈为空时,浏览器会一直不停的检查事件队列,如果不为空,则取出第一个任务;
  • 在每一个任务结束之后,浏览器会对页面进行渲染;

案例1:

for (var i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
# 很多人以为上面的题目,答案是0,1,2,3。其实,正确的答案是:3,3,3,3

案例2:

for (var i = 0; i < 3; i++) {
    setTimeout(function () {
    	console.log(i);
    }, 1000);
}
console.log(i);
# 循环执行过程中,几乎同时设置了 3 个定时器,这些定时器都会在 1 秒之后触发,而循环完的输出是立即执行的.
# 3 -> 3,3,3,即第 13 直接输出,1 秒之后,连续输出 33

前端错误的分类

  • 即时运行错误(代码错误)
  • 资源加载错误

Class和普通构造函数有何区别

我们经常会用ES6中的Class来代替JS中的构造函数做开发。

  • Class 在语法上更加贴合面向对象的写法
  • Class 实现继承更加易读、易理解
  • 更易于写 java 等后端语言的使用
  • 本质还是语法糖,使用 prototype

JavaScript中如何检测一个变量是一个String类型?

请写出函数实现

typeof(obj) === “string” 
typeof obj === “string” 
obj.constructor === String 

请用js去除字符串空格?

# 方法一:使用replace正则匹配的方法
去除所有空格: str = str.replace(/s*/g,"");
去除两头空格: str = str.replace(/^s*|s*$/g,"");
去除左空格: str = str.replace( /^s*/, “”);
去除右空格: str = str.replace(/(s*$)/g, “”);
str为要去除空格的字符串,实例如下:
var str = " 23 23;
var str2 = str.replace(/s*/g,”");
console.log(str2); // 2323
# 方法二:使用str.trim()方法
str.trim()局限性:无法去除中间的空格,实例如下:
var str = " xiao ming ";
var str2 = str.trim();
console.log(str2); //xiao ming
同理,str.trimLeft(),str.trimRight()分别用于去除字符串左右空格。
# 方法三:使用jquery,$.trim(str)方法
$.trim(str)局限性:无法去除中间的空格,实例如下:
var str = " xiao ming ";
var str2 = $.trim(str)
console.log(str2); // xiao ming

js 字符串操作函数

我这里只是列举了常用的字符串函数,具体使用方法,请参考网址。

 concat() – 将两个或多个字符的文本组合起来,返回一个新的字符串。

 indexOf() – 返回字符串中一个子串第一处出现的索引。如果没有匹配项,返回 -1 。

 charAt() – 返回指定位置的字符。

 lastIndexOf() – 返回字符串中一个子串最后一处出现的索引,如果没有匹配项,返回 -1 。

 match() – 检查一个字符串是否匹配一个正则表达式。

 substr() 函数 – 返回从string的startPos位置,长度为length的字符串

 substring() – 返回字符串的一个子串。传入参数是起始位置和结束位置。

 slice() – 提取字符串的一部分,并返回一个新字符串。

 replace() – 用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。

 search() – 执行一个正则表达式匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回 -1 。

 split() – 通过将字符串划分成子串,将一个字符串做成一个字符串数组。

 length – 返回字符串的长度,所谓字符串的长度是指其包含的字符的个数。

 toLowerCase() – 将整个字符串转成小写字母。

 toUpperCase() – 将整个字符串转成大写字母。

你如何获取浏览器URL中查询字符串中的参数?

function showWindowHref(){
    var sHref = window.location.href;
    var args = sHref.split('?');
    if(args[0] == sHref){
        return "";
    }
    var arr = args[1].split('&');
    var obj = {};
    for(var i = 0;i< arr.length;i++){
        var arg = arr[i].split('=');
        obj[arg[0]] = arg[1];
    }
    return obj;
}
var href = showWindowHref(); // obj
console.log(href['name']); // xiaoming

怎样添加、移除、移动、复制、创建和查找节点?

1)创建新节点

createDocumentFragment() //创建一个DOM片段

createElement() //创建一个具体的元素

createTextNode() //创建一个文本节点

2)添加、移除、替换、插入

appendChild() //添加

removeChild() //移除

replaceChild() //替换

insertBefore() //插入

3)查找

getElementsByTagName() //通过标签名称

getElementsByName() //通过元素的Name属性的值

getElementById() //通过元素Id,唯一性

JS中typeof与instanceof的区别

JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。

typeof

typeof 其实就是判断参数是什么类型的实例,就一个参数

typeof 一般只能返回如下几个结果:“number”、“string”、“boolean”、“object”、“function” 和 “undefined”。

在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。这就需要用到instanceof来检测某个对象是不是另一个对象的实例。

instanceof

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

参数:object(要检测的对象.)constructor(某个构造函数)

闭包

  1. 介绍一下闭包和闭包常用场景?

使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念

  1. 闭包有三个特性:
  • 函数嵌套函数
  • 函数内部可以引用外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收
  1. 闭包是指有权访问另一个函数作用域中的变量的函数. 创建闭包常见方式,就是在一个函数内部创建另一个函数.

    • 应用场景 设置私有变量和方法

    • 不适合场景:返回闭包的函数是个非常大的函数

    • 闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

  2. 为什么会出现闭包这种东西,解决了什么问题?

    受JavaScript链式作用域结构的影响,父级变量中无法访问到子级的变量值,为了解决这个问题,才使用闭包这个概念

sessionStorage 、localStorage 和 cookie 之间的区别

共同点:用于浏览器端存储的缓存数据

不同点:

(1)、存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费;

web storage,会将数据保存到本地,不会造成宽带浪费;

(2)、数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;

(3)、数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;

sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;

(4)、作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;

说几条写JavaScript的基本规范?

  1. 不要在同一行声明多个变量。
  2. 请使用 ===/!==来比较true/false或者数值
  3. 使用对象字面量替代new Array这种形式
  4. 不要使用全局函数。
  5. Switch语句必须带有default分支
  6. 函数不应该有时候有返回值,有时候没有返回值。
  7. For循环必须使用大括号
  8. If语句必须使用大括号
  9. for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。

JS中有哪些数据类型?

简单数据类型:Undefined、Null、Boolean、Number 和String。 复杂数据类型:Object

  • 五种基本类型: Undefined、Null、Boolean、Number和String。
  • 1中复杂的数据类型————Object,Object本质上是由一组无序的名值对组成的。
  • Object、Array和Function则属于引用类型

” 和 “=” 的区别?

前者会自动转换类型,而后者不会。 前者比较的是值,后者比较的是值和类型。

JS中的常用内置对象有哪些?并列举该对象的常用方法?

  # Arguments 函数参数集合

  arguments[ ] 函数参数的数组 

  Arguments 一个函数的参数和其他属性  

  Arguments.callee 当前正在运行的函数  

  Arguments.length 传递给函数的参数的个数  
  
  
  # Array 数组  
  
  length属性动态获取数组长度  
  
  join() 将一个数组转成字符串。返回一个字符串。  
  
  reverse() 将数组中各元素颠倒顺序  
  
  delete运算符 只能删除数组元素的值,而所占空间还在,总长度没变(arr.length)。  
  
  shift() 删除数组中第一个元素,返回删除的那个值,并将长度减 1。 
  
  pop() 删除数组中最后一个元素,返回删除的那个值,并将长度减1。  
  
  unshift() 往数组前面添加一个或多个数组元素,长度要改变。 
  
  push() 往数组结尾添加一个或多个数组元素,长度要改变。 
  
  concat( ) 连接数组  
  
  slice( ) 返回数组的一部分  
  
  sort( ) 对数组元素进行排序  
  
  splice( ) 插入、删除或替换数组的元素  
  
  toLocaleString( ) 把数组转换成局部字符串  
  
  toString( ) 将数组转换成一个字符串 
  
  # Boolean 布尔对象  
  
  Boolean.toString( ) 将布尔值转换成字符串  
  
  Boolean.valueOf( ) Boolean对象的布尔值  
  
 #  Error 异常对象  
  
  Error.message 可以读取的错误消息  
  
  Error.name 错误的类型  
  
  Error.toString( ) 把Error 对象转换成字符串 
  
  EvalError 在不正确使用 eval()时抛出  
  
  SyntaxError 抛出该错误用来通知语法错误  
  
  RangeError 在数字超出合法范围时抛出  
  
  ReferenceError 在读取不存在的变量时抛出  
  
  TypeError 当一个值的类型错误时,抛出该异常  
  
  URIError 由URl的编码和解码方法抛出  
  
  # Function 函数构造器  
  
  Function.apply( ) 将函数作为一个对象的方法调用  
  
  Function.arguments[] 传递给函数的参数  
  
  Function.call( ) 将函数作为对象的方法调用  
  
  Function.caller 调用当前函数的函数  
  
  Function.length 已声明的参数的个数  
  
  Function.prototype 对象类的原型  
  
  Function.toString( ) 把函数转换成字符串 
  
  # Math 数学对象 
  
  Math对象是一个静态对象  
  
  Math.PI 圆周率。  
  
  Math.abs() 绝对值。  
  
  Math.ceil() 向上取整(整数加 1,小数去掉)。  
  
  Math.floor() 向下取整(直接去掉小数)。  
  
  Math.round() 四舍五入。  
  
  Math.pow(x,y) 求 x的y次方。  
  
  Math.sqrt() 求平方根。 
  
 #  Number 数值对象 
  
  Number.MAX_VALUE 最大数值  
  
  Number.MIN_VALUE 最小数值  
  
  Number.NaN 特殊的非数字值  
  
  Number.NEGATIVE_INFINITY 负无穷大  
  
  Number.POSITIVE_INFINITY 正无穷大  
  
  Number.toExponential( ) 用指数计数法格式化数字 
  
  Number.toFixed( ) 采用定点计数法格式化数字  
  
  Number.toLocaleString( ) 把数字转换成本地格式的字符串  
  
  Number.toPrecision( ) 格式化数字的有效位 
  
  Number.toString( ) 将—个数字转换成字符串  
  
  Number.valueOf( ) 返回原始数值  
  
  # Object 基础对象 
  
  Object 含有所有 JavaScript 对象的特性的超类  
  
  Object.constructor 对象的构造函数  
  
  Object.hasOwnProperty( ) 检查属性是否被继承  
  
  Object.isPrototypeOf( ) 一个对象是否是另一个对象的原型  
  
  Object.propertyIsEnumerable( ) 是否可以通过 for/in循环看到属性  
  
  Object.toLocaleString( ) 返回对象的本地字符串表示  
  
  Object.toString( ) 定义一个对象的字符串表示  
  
  Object.valueOf( ) 指定对象的原始值  
  
  # RegExp 正则表达式对象 
  
  RegExp.exec( ) 通用的匹配模式  
  
  RegExp.global 正则表达式是否全局匹配  
  
  RegExp.ignoreCase 正则表达式是否区分大小写  
  
  RegExp.lastIndex 下次匹配的起始位置  
  
  RegExp.source 正则表达式的文本  
  
  RegExp.test( ) 检测一个字符串是否匹配某个模式  
  
  RegExp.toString( ) 把正则表达式转换成字符串 
  
  # String 字符串对象 
  
  Length 获取字符串的长度。 
  
  toLowerCase() 将字符串中的字母转成全小写。 
  
  toUpperCase() 将字符串中的字母转成全大写。 
  
  charAt(index) 返回指定下标位置的一个字符。如果没有找到,则返回空字符串。 
  
  substr() 在原始字符串,返回一个子字符串  
  
  substring() 在原始字符串,返回一个子字符串。  
  
  split() 将一个字符串转成数组。  
  
  charCodeAt( ) 返回字符串中的第 n个字符的代码 
  
  concat( ) 连接字符串  
  
  fromCharCode( ) 从字符编码创建—个字符串  
  
  indexOf( ) 返回一个子字符串在原始字符串中的索引值(查找顺序从左往右查找)。如果没 有找到,则返回-1。 
  
  lastIndexOf( ) 从后向前检索一个字符串  
  
  localeCompare( ) 用本地特定的顺序来比较两个字符串  
  
  match( ) 找到一个或多个正则表达式的匹配  
  
  replace( ) 替换一个与正则表达式匹配的子串  
  
  search( ) 检索与正则表达式相匹配的子串  
  
  slice( ) 抽取一个子串  
  
  toLocaleLowerCase( ) 把字符串转换小写  
  
  toLocaleUpperCase( ) 将字符串转换成大写  
  
  toLowerCase( ) 将字符串转换成小写  
  
  toString( ) 返回字符串  
  
  toUpperCase( ) 将字符串转换成大写  
  
  valueOf( ) 返回字符串

什么是短路表达式?

短路表达式只是一种简写形式,也就是用 && 和 || 来赋值或者执行函数的形式

例如: 
  
  var foo = foo1 || foo2; 
  
  意思是如果foo1是真的,那么就把foo1的值赋给foo,否则把foo2的值赋给foo。 
  
  foo && foo() 
  
  当foo存在的时候,我们就执行foo函数,如果这个时候foo不是一个函数,就会报错,所以这个只是一种简写形式而已。

控制台中使用哪些部分调试?

  1. console.log 用于输出普通信息
  2. console.info 用于输出提示性信息
  3. console.error用于输出错误信息
  4. console.warn用于输出警示信息
  5. console.debug用于输出调试信息

JavaScript 中的垃圾回收机制?

在Javascript 中,如果一个对象不再被引用,那么这个对象就会被GC 回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。 因为函数 a被b引用,b又被 a外的 c引用,这就是为什么 函数 a 执行后不会被回收的原 因。

哪些常见操作会造成内存泄漏?

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。

垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)。

如何获取UA

function whatBrowser() {
    //获取完整的浏览器名称
    document.Browser.Name.value=navigator.appName; 
    //获取浏览器的版本,一般不与实际的浏览器版本对应	
    document.Browser.Version.value=navigator.appVersion; 
    //获取浏览器的名称。通常都是Mozilla,即使在非Mozilla的浏览器中也是如此		
    document.Browser.Code.value=navigator.appCodeName; 
    //获取浏览器的用户代理字符串
    document.Browser.Agent.value=navigator.userAgent;
}

new操作符具体干了什么呢

(1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

(2)属性和方法被加入到 this 引用的对象中。

(3)新创建的对象由 this 所引用,并且最后隐式的返回 this 。

this对象的理解

答:this总是指向函数的直接调用者(而非间接调用者);

如果有new关键字,this指向new出来的那个对象;

在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window。

javaScript中的this是什么,有什么用,它的指向是什么?

  • 全局代码中的this 是指向全局对象
  • 作为对象的方法调用时指向调用这个函数的对象。
  • 作为构造函数指向新创建的对象
  • 使用apply和call设置this

null和undefined的区别?

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

undefined:

(1)变量被声明了,但没有赋值时,就等于undefined。

(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

(3)对象没有赋值的属性,该属性的值为undefined。

(4)函数没有返回值时,默认返回undefined。

null:

(1) 作为函数的参数,表示该函数的参数不是对象。

(2) 作为对象原型链的终点。

eval是做什么的?

​ 它的功能是把对应的字符串解析成JS代码并运行;

应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval(’(’+ str +’)’)。

介绍js的基本数据类型

答: Undefined、Null、Boolean、Number、String

js有哪些内置对象?

答:数据封装类对象:Object、Array、Boolean、Number 和 String

其他对象:Function、Arguments、Math、Date、RegExp、Error

请指出document load和document ready的区别?

共同点:这两种事件都代表的是页面文档加载时触发。

异同点:

ready 事件的触发,表示文档结构已经加载完成(不包含图片等非文字媒体文件)。

onload 事件的触发,表示页面包含图片等文件在内的所有元素都加载完成。

编写一个方法 去掉一个数组的重复元素

var arr = [2,3,4,4,5,2,3,6],
   arr2 = [];
for(var i = 0;i< arr.length;i++){
    if(arr2.indexOf(arr[i]) < 0){
        arr2.push(arr[i]);
    }
}
console.log(arr2);
结果为:[2, 3, 4, 5, 6]

如何理解闭包?

1、定义和用法:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。

2、表现形式:使函数外部能够调用函数内部定义的变量。

3、实例如下:

(1)、根据作用域链的规则,底层作用域没有声明的变量,会向上一级找,找到就返回,没找到就一直找,直到window的变量,没有就返回undefined。这里明显count 是函数内部的flag2 的那个count 。

var count=10;   //全局作用域 标记为flag1
function add(){
    var count=0;    //函数全局作用域 标记为flag2
    return function(){
        count+=1;   //函数的内部作用域
        alert(count);
    }
}
var s = add()
s();//输出1
s();//输出2

变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域分类:全局变量和局部变量。

特点:

1、函数内部可以读取函数外部的全局变量;在函数外部无法读取函数内的局部变量。

2、函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

5、使用闭包的注意点

1)滥用闭包,会造成内存泄漏:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)会改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

说说你对作用域链的理解

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

介绍一下你所了解的作用域链,作用域链的尽头是什么,为什么?

  1. 每一个函数都有一个作用域,比如我们创建了一个函数,函数里面又包含了一个函数,那么现在 就有三个作用域,这样就形成了一个作用域链。
  2. 作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域链往上找。

栈和队列的区别?

栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。

队列先进先出,栈先进后出。

栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除
12345

栈和堆的区别?

栈区(stack)—   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。

堆区(heap)   —   一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回收。

堆(数据结构):堆可以被看成是一棵树,如:堆排序;

请给出异步加载js方案,不少于两种方案。

  1. defer,只支持IE
  2. async
  3. 创建script,插入到DOM中,加载完毕后callBack

如何用原生js给一个按钮绑定两个onclick事件?

Var  btn=document.getElementById(‘btn’);

//事件监听 绑定多个事件
var btn4 = document.getElementById("btn4");
btn4.addEventListener("click",hello1);
btn4.addEventListener("click",hello2);

function hello1(){
 alert("hello 1");
}

function hello2(){
 alert("hello 2");
}

Javascript中的定时器有哪些?他们的区别及用法是什么?

  • setTimeout 只执行一次
  • setInterval 会一直重复执行

计算一个数组arr所有元素的和

var arr1=[1,2,3,4,5,6,7,8,9];
var sum1=0;
for (var i=0;i<arr1.length;i++) {
	if (typeof arr1[i]=="number") {
		sum1+=arr1[i];
	}
}
document.write(sum1);

document.write和innerHTML的区别:

  • document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。
  • innerHTML则是DOM页面元素的一个属性,代表该元素的html内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容,则需要修改document.documentElement.innerElement。
  • innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
  • innerHTML很多情况下都优于document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分。

js中如何获取某一个属性的值,如何设置一个属性的值

.getAttribute(``"属性名"``)``//获取

.setAttribute(``"属性名"``,``"值"``)``//设置

举例说明一下什么是事件委托?

事件委托就是利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果

    <ul id="ul1">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
    </ul>
    <script>
        window.onload = function () { 
                var oUl = document.getElementById('ul1');
                oUl.onclick = function (ev) {
                        var ev = ev || window.event;
                        var target = ev.target || ev.srcElement;
                        if(target.nodeName.toLowerCase() == 'li') {
                                alert(target.innerHTML)
                        }
                }
        }
    </script>

Object.is() 与原来的比较操作符“ ===”、“ ==”的区别?

Object.is()类似于===,但在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,但 Object.is(NaN, NaN) 会返回 true。

把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?

  • 如果说放在body的封闭之前,将会阻塞其他资源的加载
  • 如果放在body封闭之后,不会影响body内元素的加载

如何编写高性能的Javascript?

  • 不要用for-in访问数组,可以用for-in访问对象
  • 将耗费资源的DOM访问进行缓存(定义变量保存数组长度)
  • 不要再函数内使用多个if嵌套
  • 避免循环,防止内存泄漏
  • 避免返回未声明

js延迟加载的方式有哪些?

defer属性、async属性、动态创建、jquery的getScript()

Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

hasOwnProperty

js正常模式和严格模式有什么不同?

  • 正常模式中,变量没有声明就赋值会默认为全局变量,严格模式禁止。
  • 严格模式this禁止指向全局,使用构造函数不加new会报错。
  • 严格模式一般禁止删除变量,只有configurable设置为true才可删除。
  • 严格模式对象不能有重名属性,正常模式可以。
  • 严格模式不能有重名参数,正常模式可以。

Javascript内置对象、原生对象、宿主对象关系

原生对象:

​ 独立于宿主环境的ECMAScript实现提供的对象。与宿主无关,在javascript(远景浏览器)、nodejs(node平台)、jscript(ie浏览器)、typescript(微软平台)等等中均有这些对象。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。在运行过程中动态创建的对象,需要new

内置对象:

​ 由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现,即在引擎初始化阶段就被创建好的对象。这意味着开发者不必明确实例化内置对象,它已被实例化了

​ 同样是“独立于宿主环境”。根据定义我们似乎很难分清“内置对象”与“本地对象”的区别。而ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。如此就可以理解了。内置对象是本地对象的一种。

宿主对象:

​ 何为“宿主对象”?主要在这个“宿主”的概念上,ECMAScript中的“宿主”当然就是我们网页的运行环境,即“操作系统”和“浏览器”。

​ 所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象,包含两大类,一个是宿主提供,一个是自定义类对象,ECMAScript官方未定义的对象都属于宿主对象,所有非本地对象都是宿主对象。宿主提供对象原理—>由宿主框架通过某种机制注册到ECscript引擎中的对象,如宿主浏览器(以远景为参考)会向ECscript注入window对象,构建其实现javascript。所有的BOM和DOM都是宿主对象。说白了就是,ECMAScript官方未定义的对象都属于宿主对象,因为其未定义的对象大多数是自己通过ECMAScript程序创建的对象。

猜你喜欢

转载自blog.csdn.net/yw00yw/article/details/85079290