let 指定长度的数组_知乎

第一大点:ES6常用的新特性

1.简化后的字面量写法:

ES5:

var human = {

breathe: function(name) {

console.log(name + 'is breathing...');

}

};

human.breathe('jarson');

ES6:

var human = {

breathe(name) { //不需要function也能定义breathe函数。 console.log(name + ' is breathing...');

}

};

human.breathe('jarson'); //输出 ‘jarson is breathing...’

2.创建类的新方式:

ES5:

function Human(name) {

this.name = name;

this.breathe = function() {

console.log(this.name + ' is breathing');

}

}

var man = new Human('jarson');

man.breathe();//jarson is breathing

ES6:

class Human {

constructor(name) {

this.name = name;

}

breathe() {

console.log(this.name + " is breathing");

}

}

var man = new Human("jarson");

man.breathe();//jarson is breathing

ES6中的继承:

class Man extends Human {

constructor(name, sex) {

super(name);

this.sex = sex;

}

info(){

console.log(this.name + 'is ' + this.sex);

}

}

var xx = new Man('jarson', 'boy');

xx.breathe(); //jarson is breathingxx.info(); //arsonis boy

3.模块化:0)完整案例

module "point" {

export class Point {

constructor (x, y) {

public x = x;

public y = y;

}

}

}

// myapp.js//声明引用的模块module point from "/point.js";

//这里可以看出,尽管声明了引用的模块,还是可以通过指定需要的部分进行导入import Point from "point";

var origin = new Point(0, 0);

console.log(origin);

1)内联导出

export class Human{

constructor(name) {

this.name = name;

}

breathe() {

console.log(this.name + " is breathing");

}

}

export function run(){

console.log('i am runing');

}

function eat() {

console.log('i am eating');

}

上面的例子中的模块导出了两个对象:Human类和run函数, eat函数没有导出,则仍为此模块私有,不能被其他文件使用。

2)导出多个对象

class Human{

constructor(name) {

this.name = name;

}

breathe() {

console.log(this.name + " is breathing");

}

}

function run(){

console.log('i am runing');

}

function eat() {

console.log('i am eating');

}

export {Human, run};

这样的写法功能和上面一样,而且也很明显,在最后可以清晰的看到导出了哪些对象。

3)Default导出

导出时使用关键字default,可将对象标注为default对象导出。default关键字在每一个模块中只能使用一次。它既可以用于内联导出,也可以用于一组对象导出声明中。

查看导出default对象的语法:

... //创建类、函数等等export default { //把Human类和run函数标注为default对象导出。 Human,

run

};

4)无对象导入

如果模块包含一些逻辑要执行,且不会导出任何对象,此类对象也可以被导入到另一模块中,导入之后只执行逻辑。如:

import './module1.js';5)导入默认对象

使用Default导出方式导出对象,该对象在import声明中将直接被分配给某个引用,如下例中的“app”。

import app from './module1.js';

4.变量的定义:

ES6中有两个新特性:let和 const,为了理解let,我们需要记住var是创建函数生存期内的变量:

function printName() {

if(true) {

var name = "Rafael";

}

console.log(name); // Rafael}

不像Java或其他语言,任何变量在JS中是在一个函数内创建,它会升级到哦函数之外部,不管你在哪里定义变量,都和你在函数顶部定义一样,这个行为称为hoisting。

上面代码用下面方式容易理解些:

function printName() {

var name; // variable declaration is hoisted to the top if(true) {

name = "Rafael";

}

console.log(name); // Rafael}

那么let是如何工作呢,和hoisting有什么关系,我们导入let的代码如下:

function printName() {

if(true) {

let name = "Rafael";

}

console.log(name); // ReferenceError: name is not defined}

let是在一个代码块内,变量名只能在代码块中可见。

function printName() {

var name = "Hey";

if(true) {

let name = "Rafael";

console.log(name); // Rafael }

console.log(name); // Hey}总结:var是function-scoped,而let是 block-scoped.

const是创建常量使用,一旦创建就一直不会被概念,如下:

const SERVER_URL = "http://127.0.0.1/"5.箭头函数:

ES6中新增的箭头操作符 => 简化了函数的书写。操作符左边为输入的参数,而右边则是进行的操作以及返回的值,这样的写法可以为我们减少大量的代码,看下面的实例:

let arr = [6, 8, 10, 20, 15, 9];

arr.forEach((item, i) => console.log(item, i));

let newArr = arr.filter((item) => (item<10));

console.log(newArr); //[6, 8, 9];

上面的 (item, i) 就是参数,后面的 console.log(item, i) 就是回到函数要执行的操作逻辑。

上面代码转为ES5格式:

var arr = [6, 8, 10, 20, 15, 9];

arr.forEach(function(item, i) {

return console.log(item, i);

});

var newArr = arr.filter(function(item) {

return (item < 10);

});

console.log(newArr);6.字符串模版:

ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。看一下实例就会明白了:

//产生一个随机数let num = Math.random();

//将这个数字输出到consoleconsole.log(`your num is${num}`);7.解构:

若一个函数要返回多个值,常规的做法是返回一个对象,将每个值做为这个对象的属性返回。在ES6中,利用解构这一特性,可以直接返回一个数组,然后数组中的值会自动被解析到对应接收该值的变量中。我们来看例子:

function getVal() {

return [1, 2];

}

var [x,y] = getVal(); //函数返回值的解构console.log('x:'+x+', y:'+y); //输出:x:1, y:2

或者:

var [x,y]=getVal(),//函数返回值的解构 [name,,age]=['wayou','male','secrect'];//数组解构

function getVal() {

return [ 1, 2 ];

}

console.log('x:'+x+', y:'+y);//输出:x:1, y:2console.log('name:'+name+', age:'+age);//输出: name:wayou, age:secrect8.默认参数:

现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了,有点类似PHP中的用法。

function sayHello(name){

//传统的指定默认参数的方式 var name=name||'woman';

console.log('Hello '+name);

}

//运用ES6的默认参数function sayHello2(name='woman'){

console.log(`Hello${name}`);

}

sayHello();//输出:Hello womansayHello('man');//输出:Hello mansayHello2();//输出:Hello womansayHello2('man');//输出:Hello man9.不定参数:

不定参数是在函数中使用命名参数同时接收不定数量的未命名参数。这只是一种语法糖,在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如下面这个例子中,…x代表了所有传入add函数的参数。

//将所有参数相加的函数function add(...x){

return x.reduce((m,n)=>m+n);

}

//传递任意个数的参数console.log(add(1,2,3));//输出:6console.log(add(1,2,3,4,5));//输出:15

或者:

var people=['Wayou','John','Sherlock'];

//sayHello函数本来接收三个单独的参数人妖,人二和人三function sayHello(people1,people2,people3){

console.log(`Hello${people1},${people2},${people3}`);

}

//但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数sayHello(...people);//输出:Hello Wayou,John,Sherlock

//而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法sayHello.apply(null,people);//输出:Hello Wayou,John,Sherlock

10.多行字符串:

另一个好吃的语法糖就是多行字符串,以前我们的实现是像这样的:

varroadPoem= 'Then took the other, as just as fair,nt'

+ 'And having perhaps the better claimnt'

+ 'Because it was grassy and wanted wear,nt'

+ 'Though as for that the passing therent'

+ 'Had worn them really about the same,nt'

varfourAgreements= 'You have the right to be you.nYou can only be you when you do your best.'

但是在ES6中,只要充分利用反引号。

varroadPoem= `Thentook the other,asjust asfair,Andhaving perhaps the better claimBecause it was grassy andwanted wear,Though asforthat the passing thereHad worn them really about the same,`

varfourAgreements = `You have the right tobe you.You can only be you when you doyour best.`11.for of 值遍历:

我们都知道for in 循环用于遍历数组,类数组或对象,ES6中新引入的for of循环功能相似,不同的是每次循环它提供的不是序号而是值。

var someArray = [ "a", "b", "c" ];

for (v of someArray) {

console.log(v);//输出 a,b,c}

12.加强版集合方法:

1)Set:

Set 是 ES6 新增的有序列表集合,它不会包含重复项。之前我们通常用对象(Object)或者数组(Array)来实现没有重复项的集合。但对象会对 key 进行 toString() 操作,这会导致某些 key 会意外覆盖之前的数据;如果 key 本身是一个对象,toString() 也得不到想要的结果,如下:

var o = {};

var key1 = 2;

var key2 = { toString : function() { return 2 } };

var key3 = { x : 1 };

var key4 = { y : 2 };

o[key1] = 1;

o[key2] = 2;

o[key3] = 3;

o[key4] = 4;

// o : Object {2: 2, [object Object]: 4}

数组可以存放任何类型的数据,不过数据除重需要自己实现。

Set 支持 add(item) 方法,用来向 Set 添加任意类型的元素,如果已经添加过则自动忽略;has(item) 方法用来检测 Set 中是否存在指定元素;delete(item) 方法用来从 Set 中删除指定元素;clear() 用来清空 Set;获取 Set 集合长度用 size 属性。如下:

var set = new Set();

set.add(window);

set.has(window); // trueset.size; // 1set.add(window);

set.add(1);

set.size; // 2set.delete(window);

set.has(window); // falseset.clear();

set.size; // 0

Set 调用 add、has、delete 等方法时对 key 进行的比较,不做类型转换。可以认为使用「===」进行比较,当然也不全是「===」:Set 中,NaN 只能添加一次(虽然NaN === NaN 返回 false);

Set 中,「-0」和「0 或 +0」可以同时存在,因为符号不一样(虽然 -0 === 0 或 -0 === +0 返回 true);

2)Map:

Map 是 ES6 新增的有序键值对集合。键值对的 key 和 value 都可以是任何类型的元素。通过 set(key, value) 方法为 Map 设置新的键值对,如果设置的 key 已经存在则用新的 value 覆盖,Map 在比较 key 时也不做类型转换,跟 Set 类似;Map 的 get(key) 方法用来获取指定 key 的值;Map 的 has(key) 、 delete(key) 、clear() 这些方法和 size 属性,与 Set 类似,直接看代码:

var map = new Map();

var key1 = {toString : function() { return 2}};

var key2 = 2;

map.set(key1, 1);

map.set(key2, 2);

map.has(key1); // truemap.has('2'); // false,类型不同map.delete(2);

map.size; // 1map.get(key2); // undefined

3)如何迭代它们:

我们没办法像数组一样用 for 循环来迭代 Set,也没办法像对象一样用 for...in 来迭代 Map。但是可以用 ES6 提供的新方法 for...of 来遍历它们。

Set 和 Map 有几个方法会返回可迭代对象(Iterator Objects),分别是 entries()、keys() 和 values()。直接遍历 Set/Map,等同于遍历 entries();keys() 和 values() 则分别返回 key 和 value 的集合;对于 Set,key 和 value 是一样的。这些方法和 for...of 现阶段都只有 Firefox 支持,下面的例子需要在 Firefox 下运行:

var set = new Set();

set.add('this is a demo.');

set.add(window);

set.add(top);

for(let item of set) {

console.log(item);

}

4)WeakMap/Set

WeakMap 相对于普通的 Map,也是键值对集合,只不过 WeakMap 的 key 只能是非空对象(non-null object)。WeakMap 对它的 key 仅保持弱引用,也就是说它不阻止垃圾回收器回收它所引用的 key。WeakMap 最大的好处是可以避免内存泄漏。一个仅被 WeakMap 作为 key 而引用的对象,会被垃圾回收器回收掉。

WeakMap 拥有和 Map 类似的 set(key, value) 、get(key)、has(key)、delete(key) 和 clear() 方法,但没有 size 属性,也没有任何与迭代有关的方法。

// Weak Mapsvar wm = new WeakMap();

wm.set(s, { extra: 42 });

wm.size === undefined

// Weak Setsvar ws = new WeakSet();

ws.add({ data: 42 });//因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思

13.新的数据类型Symbols:

Symbol如何使用呢, Symbol不是一个构造函数哦, 如果用new Symbol的话, 会报错的:

var sym1 = Symbol();

var sym2 = Symbol("foo");

var sym3 = Symbol("foo");

console.log(sym1, sym2, sym3) //输出Symbol() Symbol(foo) Symbol(foo)

连自己都不等于自己:

//用同样的参数创建两次, 也是不相等的:Symbol("foo") === Symbol("foo"); //输出:false

作为属性名的Symbol;使用Symbol给对象添加唯一的属性, Symbol也能作为对象的函数名;

let obj = {};

let sAttr0 = Symbol("hehe");

let sAttr1 = Symbol("meme");

obj[sAttr1] = 1;

console.log(obj[sAttr1]);

obj[sAttr0] = () => {

return ++obj[sAttr0];;

};

我们可以用typeof判断某一个变量类型为Symbol类型:

typeof Symbol() === 'symbol' //输出:truetypeof Symbol('foo') === 'symbol' //输出: truetypeof Symbol.iterator === 'symbol' //输出 : true14.Proxies代理(监控一个对象):

代理创建的对象可以获得宿主对象的全部行为(属性和方法)。可以用于拦截,虚拟对象,日志/分析等。

// Proxying a normal object 代理一个普通对象var target = {};//被代理的类var handler = {//第二个参数表示拦截后的操作 get: function (receiver, name) {//这里是拦截获取属性的操作:p.world 相当于第二个参数name为world return `Hello,${name}!`;

}

};

var p = new Proxy(target, handler);

p.world === 'Hello, world!';

或者:

// Proxying a function object 代理一个函数对象var target = function () { return 'I am the target'; };

var handler = {

apply: function (receiver, ...args) {

return 'I am the proxy';

}

};

var p = new Proxy(target, handler);

p() === 'I am the proxy';

15.Promise(解决令人头疼的异步回调):

在多个接口异步请求数据,然后利用这些数据来进行一系列的操作。一般会这样去写:

$.ajax({

url: '......',

success: function (data) {

$.ajax({

// 要在第一个请求成功后才可以执行下一步 url: '......',

success: function (data) {

// ...... }

});

}

});

这样的写法的原理是,当执行一些异步操作时,我们需要知道操作是否已经完成,所有当执行完成的时候会返回一个回调函数,表示操作已经完成。

使用回调函数的形式理解起来并不困难,但是实际的应用当中会有以下的缺点:在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的 Callback Hell。

如果几个异步操作之间并没有前后顺序之分(例如不需要前一个请求的结果作为后一个请求的参数)时,同样需要等待上一个操作完成再实行下一个操作。

为了解决上述的问题,Promise 对象应运而生,在 EMCAScript 2015 当中已经成为标准。

一个 Promise 对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。而且由于 Promise.all 这样的方法存在,可以让同时执行多个操作变得简单。接下来就来简单介绍 Promise 对象。

首先来看一段使用了 Promise 对象的代码:

function helloWorld (ready) {

return new Promise(function (resolve, reject) {

if (ready) {

resolve("Hello World!");

} else {

reject("Good bye!");

}

});

}

helloWorld(true).then(function (message) {

alert(message);

}, function (error) {

alert(error);

});

helloWorld 的例子当中利用了 then(onFulfilld, onRejected) 方法来执行一个任务打印 "Hello World!",在多个任务的情况下 then方法同样可以用一个清晰的方式完成。

function printHello (ready) {

return new Promise(function (resolve, reject) {

if (ready) {

resolve("Hello");

} else {

reject("Good bye!");

}

});

}

function printWorld () {

alert("World");

}

function printExclamation () {

alert("!");

}

printHello(true)

.then(function(message){

alert(message);

})

.then(printWorld)

.then(printExclamation);

上述例子通过链式调用的方式,按顺序打印出了相应的内容。then 可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个 Promise 对象。另外,在 then onFulfilled 的函数当中的返回值,可以作为后续操作的参数,因此上面的例子也可以写成:

printHello(true).then(function (message) {

return message;

}).then(function (message) {

return message + ' World';

}).then(function (message) {

return message + '!';

}).then(function (message) {

alert(message);

});

16.Math,Number,String,Object 的新API:

对Math,Number,String还有Object等添加了许多新的API。下面代码同样来自es6features,对这些新API进行了简单展示。

Number.EPSILON

Number.isInteger(Infinity) // falseNumber.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086Math.hypot(3, 4) // 5Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2

"abcde".contains("cd") // true"abc".repeat(3) // "abcabcabc"

Array.from(document.querySelectorAll(‘*‘)) // Returns a real ArrayArray.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior[0, 0, 0].fill(7, 1) // [0,7,7][1,2,3].findIndex(x => x == 2) // 1["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]["a", "b", "c"].keys() // iterator 0, 1, 2["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })

第二大点:理论知识点

1. 常用那几种浏览器测试?有哪些内核(Layout Engine)?

(Q1)浏览器:IE,Chrome,FireFox,Safari,Opera。

(Q2)内核:Trident,Gecko,Presto,Webkit。

2. 内元素和块级元素的区别?行内块元素的兼容性使用?(IE8 以下)

(Q1)行内元素:会在水平方向排列,不能包含块级元素,设置width无效,height无效(可以设置line-height),margin上下无效,padding上下无效。

块级元素:各占据一行,垂直方向排列。从新行开始结束接着一个断行。

(Q2)兼容性:display:inline-block;*display:inline;*zoom:1;

3.清除浮动有哪些方式?比较好的方式是哪一种?

(Q1)

(1)父级div定义height。

(2)结尾处加空div标签clear:both。

(3)父级div定义伪类:after和zoom。

(4)父级div定义overflow:hidden。

(5)父级div定义overflow:auto。

(6)父级div也浮动,需要定义宽度。

(7)父级div定义display:table。

(8)结尾处加br标签clear:both。

(Q2)比较好的是第3种方式,好多网站都这么用。

4.box-sizing常用的属性有哪些?分别有什么作用?

(Q1)box-sizing: content-box|border-box|inherit;

(Q2)content-box:宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框(元素默认效果)。

border-box:元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。

5.Doctype作用?标准模式与兼容模式各有什么区别?

(Q1)告知浏览器的解析器用什么文档标准解析这个文档。DOCTYPE不存在或格式不正确会导致文档以兼容模式呈现。

(Q2)标准模式的排版和JS运作模式都是以该浏览器支持的最高标准运行。在兼容模式中,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点无法工作。

6.HTML5 为什么只需要写 ?

HTML5不基于 SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行)。

而HTML4.01基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。

7.页面导入样式时,使用link和@import有什么区别?

(1)link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;

(2)页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;

(3)import是CSS2.1 提出的,只在IE5以上才能被识别,而link是XHTML标签,无兼容问题;

8.介绍一下你对浏览器内核的理解?

主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。

渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。

JS引擎则:解析和执行javascript来实现网页的动态效果。

最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

9.html5有哪些新特性?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?

(Q1)

HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。

(1)绘画 canvas;

(2)用于媒介回放的 video 和 audio 元素;

(3)本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;

(4)sessionStorage 的数据在浏览器关闭后自动删除;

(5)语意化更好的内容元素,比如 article、footer、header、nav、section;

(6)表单控件,calendar、date、time、email、url、search;

(7)新的技术webworker, websocket, Geolocation;

(Q2)

IE8/IE7/IE6支持通过document.createElement方法产生的标签,

可以利用这一特性让这些浏览器支持HTML5新标签,

浏览器支持新标签后,还需要添加标签默认的样式。

当然也可以直接使用成熟的框架、比如html5shim;

10.简述一下你对HTML语义化的理解?

用正确的标签做正确的事情。

html语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;

即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;

搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;

使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

11.介绍js的基本数据类型

Undefined、Null、Boolean、Number、String

12.js有哪些内置对象?

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

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

13.this对象的理解

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

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

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

14.eval是做什么的?

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

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

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

15.DOM怎样添加、移除、移动、复制、创建和查找节点(DOM操作API)?

// 创建新节点createDocumentFragment() //创建一个DOM片段createElement() //创建一个具体的元素createTextNode() //创建一个文本节点// 添加、移除、替换、插入appendChild()

removeChild()

replaceChild()

insertBefore() //在已有的子节点前插入一个新的子节点// 查找getElementsByTagName() //通过标签名称getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)getElementById() //通过元素Id,唯一性

16.null和undefined的区别?

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

undefined:

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

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

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

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

null:

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

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

17.new操作符具体干了什么呢?

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

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

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

18.JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小。

格式:采用键值对,例如:{'age':'12', 'name':'back'}

19.call() 和 apply() 的区别和作用?

apply()函数有两个参数:第一个参数是上下文,第二个参数是参数组成的数组。如果上下文是null,则使用全局对象代替。

如:function.apply(this,[1,2,3]);

call()的第一个参数是上下文,后续是实例传入的参数序列。

如:function.call(this,1,2,3);

20.如何获取UA(BOM API)?

function whatBrowser() {

document.Browser.Name.value=navigator.appName;

document.Browser.Version.value=navigator.appVersion;

document.Browser.Code.value=navigator.appCodeName;

document.Browser.Agent.value=navigator.userAgent;

}

21.HTTP状态码知道哪些?

100 Continue 继续,一般在发送post请求时,已发送了http header之后服务端将返回此信息,表示确认,之后发送具体参数信息

200 OK 正常返回信息

201 Created 请求成功并且服务器创建了新的资源

202 Accepted 服务器已接受请求,但尚未处理

301 Moved Permanently 请求的网页已永久移动到新位置。

302 Found 临时性重定向。

303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。

304 Not Modified 自从上次请求后,请求的网页未修改过。

400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。

401 Unauthorized 请求未授权。

403 Forbidden 禁止访问。

404 Not Found 找不到如何与 URI 相匹配的资源。

500 Internal Server Error 最常见的服务器端错误。

503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。

22.你有哪些性能优化的方法?

(1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。

(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数

(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。

(4) 当需要设置的样式很多时设置className而不是直接操作style。

(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。

(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。

(7) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。

23.什么叫优雅降级和渐进增强?

优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于IE独特的盒模型布局问题,针对不同版本的IE的hack实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效.

渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

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

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

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

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

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

25.线程与进程的区别

一个程序至少有一个进程,一个进程至少有一个线程.

线程的划分尺度小于进程,使得多线程程序的并发性高。

另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

26.请描述一下 cookies,sessionStorage 和 localStorage 的区别?

cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。

cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。

sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。

存储大小:

cookie数据大小不能超过4k。

sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。

有期时间:

localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;

sessionStorage 数据在当前浏览器窗口关闭后自动删除。

cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

27.iframe有那些缺点?

iframe会阻塞主页面的Onload事件;

搜索引擎的检索程序无法解读这种页面,不利于SEO;

iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。

使用iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过javascript动态给iframe添加src属性值,这样可以绕开以上两个问题。

28.如何实现浏览器内多个标签页之间的通信?

WebSocket、SharedWorker

也可以调用localstorge、cookies等本地存储方式。

localstorge另一个浏览上下文里被添加、修改或删除时,它都会触发一个事件,我们通过监听事件,控制它的值来进行页面信息通信。

注意quirks:Safari 在无痕模式下设置localstorge值时会抛出 QuotaExceededError 的异常。

29.如何在页面上实现一个圆形的可点击区域?

(1)map+area或者svg

(2)border-radius

(3)纯js实现 需要求一个点在不在圆上简单算法、获取鼠标坐标等等

30.介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的?

(1)有两种, IE 盒子模型、W3C 盒子模型。

(2)盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border)。

(3)区 别: IE的content部分把 border 和 padding计算了进去。

31.CSS优先级算法如何计算?

优先级就近原则,同权重情况下样式定义最近者为准;

载入样式以最后载入的定位为准;

优先级为:

!important > id > class > tag

important比内联优先级高(style)

32.为什么要使用CSS sprites

CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background-position”的组合进行背景定位,这样可以减少很多图片请求的开销,因为请求耗时比较长;请求虽然可以并发,但是如果请求太多会给服务器增加很大的压力。

33.display:none和visibility:hidden的区别?

display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。

visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。

34.position的absolute与fixed区别

absolute浮动定位是相对于父级中设置position为relative或者absolute最近的父级元素

fixed浮动定位是相对于浏览器视窗的

35.IE 8以下版本的浏览器中的盒模型有什么不同?

IE8以下浏览器的盒模型中定义的元素的宽高不包括内边距和边框

36.ajax 有那些优缺点?如何解决跨域问题?

(Q1)

优点:

(1)通过异步模式,提升了用户体验.

(2)优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用.

(3)Ajax在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。

(4)Ajax可以实现动态不刷新(局部刷新)

缺点:

(1)安全问题 AJAX暴露了与服务器交互的细节。

(2)对搜索引擎的支持比较弱。

(3)不容易调试。

(Q2)jsonp、 iframe、window.name、window.postMessage、服务器上设置代理页面。

37.JavaScript原型,原型链 ? 有什么特点?

(1)原型对象也是普通的对象,是对象一个自带隐式的 __proto__ 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链。

(2)原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链。

38.GET和POST的区别,何时使用POST?

GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符

POST:一般用于修改服务器上的资源,对所发送的信息没有限制。

GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,

也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。

然而,在以下情况中,请使用 POST 请求:

无法使用缓存文件(更新服务器上的文件或数据库)

向服务器发送大量数据(POST 没有数据量限制)

发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

39.请解释一下 JavaScript 的同源策略

概念:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。

这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。

指一段脚本只能读取来自同一来源的窗口和文档的属性。

为什么要有同源限制?

我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

40.Flash、Ajax各自的优缺点,在使用中如何取舍?

Flash适合处理多媒体、矢量图形、访问机器;对CSS、处理文本上不足,不容易被搜索。

Ajax对CSS、文本支持很好,支持搜索;多媒体、矢量图形、机器访问不足。

共同点:与服务器的无刷新传递消息、用户离线和在线状态、操作DOM

41.什么是闭包?

闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点:

(1)作为一个函数变量的一个引用,当函数返回时,其处于激活状态。

(2) 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。

简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

42.javascript里面的继承怎么实现,如何避免原型链上面的对象共享

用构造函数和原型链的混合模式去实现继承,避免对象共享可以参考经典的extend()函数,很多前端框架都有封装的,就是用一个空函数当做中间变量

43.ajax过程

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.

(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.

(3)设置响应HTTP请求状态变化的函数.

(4)发送HTTP请求.

(5)获取异步调用返回的数据.

(6)使用JavaScript和DOM实现局部刷新.

44.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

(1)查找浏览器缓存

(2)DNS解析、查找该域名对应的IP地址、重定向(301)、发出第二个GET请求

(3)进行HTTP协议会话

(4)客户端发送报头(请求报头)

(5)服务器回馈报头(响应报头)

(6)html文档开始下载

(7)文档树建立,根据标记请求所需指定MIME类型的文件

(8)文件显示

第三大点:JS中常用的算法

1.JS数组去重

以下是展示三种方法:

Array.prototype.unique1 = function () {

var n = []; //一个新的临时数组 for (var i = 0; i < this.length; i++) //遍历当前数组 {

//如果当前数组的第i已经保存进了临时数组,那么跳过, //否则把当前项push到临时数组里面 if (n.indexOf(this[i]) == -1) n.push(this[i]);

}

return n;

}

Array.prototype.unique2 = function()

{

var n = {},r=[]; //n为hash表,r为临时数组 for(var i = 0; i < this.length; i++) //遍历当前数组 {

if (!n[this[i]]) //如果hash表中没有当前项 {

n[this[i]] = true; //存入hash表 r.push(this[i]); //把当前数组的当前项push到临时数组里面 }

}

return r;

}

Array.prototype.unique3 = function()

{

var n = [this[0]]; //结果数组 for(var i = 1; i < this.length; i++) //从第二项开始遍历 {

//如果当前数组的第i项在当前数组中第一次出现的位置不是i, //那么表示第i项是重复的,忽略掉。否则存入结果数组 if (this.indexOf(this[i]) == i) n.push(this[i]);

}

return n;

}

2.判断回文(Palindromic Words):回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫回环。比如 mamam redivider .

很多人拿到这样的题目非常容易想到用for 将字符串颠倒字母顺序然后匹配就行了。其实重要的考察的就是对于reverse的实现。其实我们可以利用现成的函数,将字符串转换成数组,这个思路很重要,我们可以拥有更多的自由度去进行字符串的一些操作。

// Array methodsconst isPalindromicA = w = >w === w.split('').reverse().join('');

// while loopconst isPalindromicB = (w) = >{

let len = w.length;

let mid = (len / 2) | 0;

while (mid) {

if (w[mid] !== w[len - mid - 1]) {

return false;

}

mid--;

}

};

// -------------------------------------------------// perf test// first let's generate a fake word with, say 20 wordsvar word = (function() {

var len = 20;

var arr = [];

while (len--) {

arr.push(97 + ((Math.random() * 26) | 0));

}

return String.fromCharCode.apply(String, arr);

})();

// timesvar t = 2e4;

var i = 0;

console.time('Array method');

while (i < t) {

isPalindromicA(word);

i++;

}

console.timeEnd('Array method');

i = 0;

console.time('Loop');

while (i < t) {

isPalindromicB(word);

i++;

}

console.timeEnd('Loop');

3.统计一个字符串出现最多的字母:

正则表达式的办法,临时想起来的,运行起来还是要慢,至少慢了一半。所以有时候还是要老老实实写代码,奇淫巧技少用。

// 黑科技const findMaxDuplicateCharRegex = (chars) = >{

// 先对字符进行排序 chars = chars.split('').sort().join('');

// 获取相同字符序列 let regex = /(.)(\1)+/g;

let temp = null;

let max = 0;

let char = '';

while (temp = regex.exec(chars)) {

if (temp[0].length > max) {

char = temp[1];

max = temp[0].length;

}

}

return char;

};

// see 前端面试中的常见的算法问题var findMaxDuplicateCharNormal = function(str) {

if (str.length == 1) {

return str;

}

let charObj = {};

for (let i = 0; i < str.length; i++) {

if (!charObj[str.charAt(i)]) {

charObj[str.charAt(i)] = 1;

} else {

charObj[str.charAt(i)] += 1;

}

}

let maxChar = '',

maxValue = 1;

for (var k in charObj) {

if (charObj[k] >= maxValue) {

maxChar = k;

maxValue = charObj[k];

}

}

return maxChar;

};

// -------------------------------------------------// perf test// first let's generate a random char with 30 charactersvar chars = (function() {

var len = 30;

var arr = [];

while (len--) {

arr.push(97 + ((Math.random() * 26) | 0));

}

return String.fromCharCode.apply(String, arr);

})();

// timesvar t = 2e4;

var i;

i = 0;

console.time('正常方法');

while (i < t) {

findMaxDuplicateCharNormal(chars);

i++;

}

console.timeEnd('正常方法');

i = 0;

console.time('正则方法');

while (i < t) {

findMaxDuplicateCharRegex(chars);

i++;

}

console.timeEnd('正则方法');

4.不借助临时变量,进行两个整数的交换:

三种方式均可。没有做性能测试。

let a = 1;

let b = 2;

// ES 6[a, b] = [b, a];

// 加减法a = a - b;

b = b + a;

a = b - a;

// 异或a = a ^ b;

b = a ^ b;

a = b ^ a;

5.斐波那契数列:

联想到了三种方式: 动态规划 ; 尾递归的形式 ;以及使用 generator(算不上一个解决方案,只是临时想到的)。

上述三种方式中,动态规划最快,计算 fib(1000) 20000 次耗时 170 ms;尾递归耗时 200 ms 左右,generator 耗时 2800 ms 左右。

// 动态规划const fibonacciDynamic = function(n) {

let array = [0, 1];

for (let i = 2; i < n + 1; i++) {

array[i] = array[i - 1] + array[i - 2];

}

return array[n];

};

// 尾递归const fibonacciTailCall = function(n, ac1 = 1, ac2 = 1) {

if (n <= 1) {

return ac2

}

return fibonacciTailCall(n - 1, ac2, ac1 + ac2);

};

// generatorconst fibonacciGenerator = (function() {

function * fib() {

let a = 0,

b = 1,

sum = 0;

while (true) {

sum = a + b;

b = a;

a = sum;

yield sum;

}

}

return function(n) {

var iterator = fib();

let result = 0;

while (n--) {

result = iterator.next();

}

return result.value;

};

} ());

// -------------------------------------------------// perf test// calculate fib(1000) 20000 timesvar t = 2e4;

var n = 1000;

var i;

i = 0;

console.time('动态规划');

while (i < t) {

fibonacciDynamic(n);

i++;

}

console.timeEnd('动态规划');

i = 0;

console.time('尾递归');

while (i < t) {

fibonacciTailCall(n);

i++;

}

console.timeEnd('尾递归');

i = 0;

console.time('generator');

while (i < t) {

fibonacciGenerator(n);

i++;

}

console.timeEnd('generator');6.正数组的最大差值:

出乎意料地,这次 Math 方法竟然完败。不用说,reduce 超级慢,比 Math 还慢近十倍。

// 使用 Mathconst getMaxGap = (array) = >Math.max.apply(Math, array) - Math.min.apply(Math, array);

// 使用 reduceconst getMaxDiff = (array) = >{

if (array.length < 1) return arrary[0];

array = array.reduce(([max, min], el) = >{

max = el > max ? el: max;

min = el < min ? el: min;

return [max, min];

},

array);

return array[0] - array[1];

};

// see 前端面试中的常见的算法问题function getMaxProfit(arr) {

var minPrice = arr[0];

var maxProfit = 0;

for (var i = 0; i < arr.length; i++) {

var currentPrice = arr[i];

minPrice = Math.min(minPrice, currentPrice);

var potentialProfit = currentPrice - minPrice;

maxProfit = Math.max(maxProfit, potentialProfit);

}

return maxProfit;

}

// -------------------------------------------------// perf test// 2000000 times: Math ~= 100ms; Reduce ~= 1100ms; Normal ~= 25mslet array = [10, 5, 11, 7, 8, 9];

var t = 2e6;

var n = 1000;

var i;

i = 0;

console.time('Math');

while (i < t) {

getMaxGap(array);

i++;

}

console.timeEnd('Math');

i = 0;

console.time('Reduce');

while (i < t) {

getMaxDiff(array);

i++;

}

console.timeEnd('Reduce');

i = 0;

console.time('Normal');

while (i < t) {

getMaxProfit(array);

i++;

}

console.timeEnd('Normal');

7.排序算法:

冒泡排序法:

function bubbleSort(arr) {

for(let i = 0,l=arr.length;i

for(let j = i+1;j

if(arr[i]>arr[j]) {

let tem = arr[i];

arr[i] = arr[j];

arr[j] = tem;

}

}

}

return arr;

}

快速排序法(效率极高):算法参考某个元素值,将小于它的值,放到左数组中,大于它的值的元素就放到右数组中,然后递归进行上一次左右数组的操作,返回合并的数组就是已经排好顺序的数组了。

function quickSort(arr) {

if(arr.length<=1) {

return arr;

}

let leftArr = [];

let rightArr = [];

let q = arr[0];

for(let i = 1,l=arr.length; i

if(arr[i]>q) {

rightArr.push(arr[i]);

}else{

leftArr.push(arr[i]);

}

}

return [].concat(quickSort(leftArr),[q],quickSort(rightArr));

}8.随机生成指定长度的字符串:

function randomString(n) {

let str = 'abcdefghijklmnopqrstuvwxyz9876543210';

let tmp = '',

i = 0,

l = str.length;

for (i = 0; i < n; i++) {

tmp += str.charAt(Math.floor(Math.random() * l));

}

return tmp;

}9.原生实现类似getElementsByClassName 的功能:

自己实现一个函数,查找某个DOM节点下面的包含某个class的所有DOM节点?不允许使用原生提供的 getElementsByClassName querySelectorAll 等原生提供DOM查找函数。

function queryClassName(node, name) {

var starts = '(^|[ \n\r\t\f])',

ends = '([ \n\r\t\f]|$)';

var array = [],

regex = new RegExp(starts + name + ends),

elements = node.getElementsByTagName("*"),

length = elements.length,

i = 0,

element;

while (i < length) {

element = elements[i];

if (regex.test(element.className)) {

array.push(element);

}

i += 1;

}

return array;

}10.使用JS 实现二叉查找树(Binary Search Tree):

一般叫全部写完的概率比较少,但是重点考察你对它的理解和一些基本特点的实现。 二叉查找树,也称二叉搜索树、有序二叉树(英语:ordered binary tree)是指一棵空树或者具有下列性质的二叉树:任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

任意节点的左、右子树也分别为二叉查找树;

没有键值相等的节点。二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等

class BinarySearchTree {

constructor() {

this.root = null;

}

insert(data) {

let n = new Node(data, null, null);

if (!this.root) {

return this.root = n;

}

let currentNode = this.root;

let parent = null;

while (1) {

parent = currentNode;

if (data < currentNode.data) {

currentNode = currentNode.left;

if (currentNode === null) {

parent.left = n;

break;

}

} else {

currentNode = currentNode.right;

if (currentNode === null) {

parent.right = n;

break;

}

}

}

}

remove(data) {

this.root = this.removeNode(this.root, data)

}

removeNode(node, data) {

if (node == null) {

return null;

}

if (data == node.data) {

// no children node if (node.left == null && node.right == null) {

return null;

}

if (node.left == null) {

return node.right;

}

if (node.right == null) {

return node.left;

}

let getSmallest = function(node) {

if (node.left === null && node.right == null) {

return node;

}

if (node.left != null) {

return node.left;

}

if (node.right !== null) {

return getSmallest(node.right);

}

}

let temNode = getSmallest(node.right);

node.data = temNode.data;

node.right = this.removeNode(temNode.right, temNode.data);

return node;

} else if (data < node.data) {

node.left = this.removeNode(node.left, data);

return node;

} else {

node.right = this.removeNode(node.right, data);

return node;

}

}

find(data) {

var current = this.root;

while (current != null) {

if (data == current.data) {

break;

}

if (data < current.data) {

current = current.left;

} else {

current = current.right

}

}

return current.data;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值