一、使用 typeof bar === "object" 判断 bar 是否是一个对象有神马潜在的弊端?如何避免这种弊端?
使用 typeof 的弊端是显而易见的(这种弊端同使用 instanceof):
let obj = {};
let arr = [];javascript
console.log(typeof obj === 'object'); //true
console.log(typeof arr === 'object'); //true
console.log(typeof null === 'object'); //true
从输出结果能够知道,typeof bar==='object'不能准确的判断bar就是一个object.能够经过 Object.prototype.toString.call(bar) === "[object Object]"来避免这种弊端:
console.log(Object.prototype.toString.call(obj)); //[object Object]
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(null)); //[object Null]
Object.prototype.toString相关信息:http://www.jb51.net/article/79941.htm复制代码
二、(function(){
var a = b = 3;
})();
console.log(b)//3;
console.log(a)//a is not defined;
等同于:
(function(){
b=3;
var a=b;
})();
三、 知识点:www.jb51.net/article/771…
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log(this.foo);
console.log(self.foo);
(function() {
console.log(this.foo);
console.log(self.foo);
}());
}
};
myObject.func();//bar bar undefined bar;
注意:被谁调用,不是处于谁的做用域,即便在做用域css
一、func是由myObject调用的,this指向 myObject。html
二、self指向myObject,至关于 myObject的this的副本。前端
三、这个当即执行匿名函数表达式(IIFE)是由window调用的,this指向 window 。java
四、IIFE的做用域处于myObject.func的做用域中,本做用域找不到self变量,沿着做用域链向上查找self变量,找到了指向 myObject对象的 self。
例二:
function outer(){
this.i = 10;
console.log(this.i);
this.text1=(function(){
console.log(this.i);
}());
this.text2=function(){
console.log(this.i);
};
};
outer();//10 10
console.log('**')
var ex=new outer();
ex.i='test';
ex.text2();//test
ex.text1();//Uncaught TypeError: ex.text1 is not a function(…)node
this是据以执行的对象,就是谁调用的,例二是在window中调用,this天然指向window,nginx
四、for(var i = 0; i < 5; i++) {
console.log('test');
setTimeout(function() {
console.log(i);
}, 0);
}
//每个setTimeout在执行时,会返回一个惟一ID,
输出内容是:5 5 5 5 5
setTimeout是异步,js的事件运行机制是先执行同步的,再执行异步,此时的i=5,使用var定义的变量i的做用域是函数,那么console i的值为for 循环的i值。
咱们就必须借助闭包的特性,每次循环时,将i值保存在一个闭包中,当setTimeout中定义的操做执行时,则访问对应闭包保存的i值便可。
for(var i = 0; i < 5; i++) {
console.log('test');
(function(){
setTimeout(function() {
console.log(i);
}, 0);
})(i);
}
//www.jianshu.com/p/cd3fee40e…web
六、下面两个函数的返回值是同样的吗?为何?apache
function foo1()
{
return {
bar: "hello"
};
}编程
function foo2()
{
return
{
bar: "hello"
};
}
foo1输出:object {bar:'hello'};
foo2: undefined;
在编程语言中,基本都是使用分号(;)将语句分隔开,这能够增长代码的可读性和整洁性。而在JS中,如若语句各占独立一行,一般能够省略语句间的分号(;),JS 解析器会根据可否正常编译来决定是否自动填充分号:
var test = 1 +
2
console.log(test); //3
等同于:var test=1+2;
console.log(test)//3
在上述状况下,为了正确解析代码,就不会自动填充分号了,可是对于 return 、break、continue 等语句,若是后面紧跟换行,解析器必定会自动在后面填充分号(;);
七、console.log(1+ +"2"); 等同于:console.log(1+(+'2'));
+'2' 的 + 是一元操做符,对 '2' 进行Number()操做,转为数字的2,因此等于3;
除了加法运算符有可能把运算子转为字符串,其余运算符都会把两侧的运算子自动转成数值。
自动转换类型:javascript.ruanyifeng.com/grammar/con…
八、
console.log(0.1 + 0.2);//0.30000000000000004
console.log(0.1 + 0.2 == 0.3);//false
计算机将全部数据以二进制的形式存储的,
把0.1和0.2转换成二进制:
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)
可是计算机只能用有限的位数来存一个数,因此最终,计算机存的数是一个近似于 0.1 的小数。
因此当咱们计算 0.1 + 0.2 时,实际上算的是两个近似值相加,获得的值固然也是近似等于 0.3。
好比1/2,1/8,1/1024,这种2的倍数的能够精确的转换。
九、实现函数 isInteger(x) 来判断 x 是不是整数
能够将 x 转换成10进制,判断和自己是否是相等便可:
function isInteger(x) {
return parseInt(x, 10) === x;
}
ES6 对数值进行了扩展,提供了静态方法 isInteger() 来判断参数是不是整数:
十、(function() {
console.log(1);
setTimeout(function(){console.log(2)}, 1000);
setTimeout(function(){console.log(3)}, 0);
console.log(4);
})();
输出内容是:1,4,3,2
JavaScript是单线程,单线程就意味着,全部任务须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就不得不一直等着。js中全部任务能够分红两种,一种是同步任务(synchronous),另外一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。
异步执行的运行机制以下。(同步执行也是如此,由于它能够被视为没有异步任务的异步执行。)
(1)全部同步任务都在主线程上执行,造成一个执行栈(execution context stack)。
(2)主线程以外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,因而结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
执行栈中的代码(同步任务),老是在读取"任务队列"(异步任务)以前执行。
js 事件运行机制:www.ruanyifeng.com/blog/2014/1…
十一、写一个少于80 字符的函数,判断一个字符串是否是回文字符串
function isPalindrome(str) {
return (str == str.split('').reverse().join(''));
}
//split() 方法用于把一个字符串分割成字符串数组。
//reverse() 方法用于颠倒数组中元素的顺序。
//join() 方法用于把数组中的全部元素放入一个字符串。元素是经过指定的分隔符进行分隔的。
十二、
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
(function(i){
btn.addEventListener('click', function(){ console.log(i); });
})(i);复制代码
document.body.appendChild(btn);
}
1三、下面的代码会输出什么?为何?
console.log(1 + "2" + "2");//122
console.log(1 + +"2" + "2");//32
console.log(1 + -"1" + "2");//02
console.log(+"1" + "1" + "2");//112
console.log( "A" - "B" + "2");//NaN2
console.log( "A" - "B" + 2);//NaN
1四、下面的代码会输出什么?为何?
var arr1 = "john".split(''); //j o h n
var arr2 = arr1.reverse(); //n h o j
var arr3 = "jones".split(''); //j o n e s
var arr4 = arr2.push(arr3);
console.log(arr1);//["n", "h", "o", "j", Array[5]]
console.log(arr2);//["n", "h", "o", "j", Array[5]]
console.log(arr4);//5
这个彻底作错了。
第一个错误:直接把arr3的数组信息逐个加在了arr2后,[n,h,o,j,j,o,n,e,s];
第二个错误,认为arr1的值是[j,o,h,n];
第三个错误,arr4应该等于arr2 push 后的值;
第一个错误就不说了,弱智错误,
第二个错误,
JS中没有指针,只有传值(value)与传址(reference引用)的区别,数组对数组是引用类型,数组对变量是值类型
var a = [1,2,3,4] //a不只是数组,仍是个对象,实际上a就是对[1,2,3,4]的引用
var b=a
var c=a
//以上两条赋值语句创建了b与c 对a即[1,2,3,4]的引用,不管改变a 仍是b抑或c 都是对[1,2,3,4]的操做,这就是传址(堆中操做)
var d=a[1] //则是把a[1]的值"1"传递给d,对d的改变则不会影响a[1],即所谓的传值(栈中操做)
第三个错误,
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
pop() 方法用于删除并返回数组的最后一个元素。
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
参考:www.cnblogs.com/bydclouds/p…
1五、var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456; 复制代码
console.log(a[b]); //456
a的属性名须要字符串,可是b和c是对象。所以,key值转化字符串,调用了toString()方法,因此,实际的效果:
a["[object Object]"] = 123;
a["[object Object]"] = 456;
16 原型,原型链,做用域,做用域链
原型:函数都有一个原型属性prototype,注:这个prototype的属性值是一个对象,默认的有一个constructor的属性,指向这个函数自己。对象有一个隐藏属性proto,该实例对象的proto属性指向原型对象prototype.
原型链:查找一个对象属性时,先查找基本属性,若没有,则沿着proto这条链向上找,这就是原型链。
做用域(scope):已声明变量或者函数的生命周期和做用范围。
做用域链:当查找一个变量时,先从当前做用域寻找,若找不到,就会去定义当前做用域的函数做用域范围内寻找,若找不到会一直查找到全局做用域,全局做用域都没有找到,就真的没有啦。
上下文执行环境:
1七、什么是闭包?举例说明
有两种应用状况:
一是:函数做为返回值,
function fn(){
var max=10;
return function(x){
if(x>max){
console.log(x);
}
}
}
var f1=fn();
f1(15);
二是:函数做为参数被传递:
var max=10;
fn=function(x){
if(x>max){
console.log(x);
}
};
(function(f){
var max=100;
f(15);
})(fn);
fn函数做为一个参数被传递到另外一个函数,复制给f参数。执行f(15)时,max 变量的取值是10,而不是100.
1八、类
1九、Null 和Undefined的区别
Undefined是表明声明未赋值的变量,变量的默认值是undefined;
Null是不存在的对象。
typeOf undefined=Undefined typeOf null=Object;
20、apply,call的区别???
apply,call的做用都是:继承另一个对象的属性.
2一、优化下面代码:
var str="我喜欢我可爱的女友,";
str=str+"她叫喵喵,";
str=str+"她时而可爱,时而认真,";
str=str+"她那天真的笑声可让人忘掉一切烦恼。";
console.log(str);
优化后的:
var arr=[];
arr.push(‘我喜欢我可爱的女友,’);
arr.push(‘她叫喵喵,’);
arr.push(‘她时而可爱,时而认真,’);
arr.push(‘她那天真的笑声可让人忘掉一切烦恼。’);
console.log(arr.join(‘’));
2二、get和post 请求的区别。
一、get请求的数据会附在URL后,post 请求是放在HTTP header中一块儿传送到URL请求,用户是看不到的;
二、Get请求大小有限制,Post 的数据量比较大,默认没有限制。
三、get 请求和post 表达的语义不同,get是用于信息获取,并且应该是安全的和幂等的,固然这里的安全指的是用于获取数据而非是修改数据,所以除了返回结果不会产生其余的反作用,并且绝大部分的get请求都直接被CDN缓存了,大大减小服务器的负担。post是读取修改信息,非幂等的,会产生反作用,因此必须交由web服务器处理。
四、get请求的URL能够被手动修改,请求的URL是能够被搜索引擎收录的,请求的URL能够存在书签里,或者历史里,或者分享给别人。
2三、为何学习NodeJS ?koa,hapi比较?
一、node的是基于google浏览器的v8引擎,保证了NOdeJS的性能和稳定性。二、NodeJS 的开发很是的高效,并且代码简单,并且NodeJS是异步编程,让Nodejs处理IO密集型应用有了明显的优点。三、NodeJS的社区很壮大,不只包的数量在快速增长,包的质量也明显好于其余语言。
不适合的领域:一、计算密集型的应用 二、大内存的应用,因为V8引擎有内存设计的限制。32位环境中最大是1G,64位的环境最大是2G,若是一次读入10G数据对于NodeJS来讲也是没法实现的。三、静态服务器,虽然Node的优点在于IO密集处理,可是和nginx的处理静态资源仍是有很大的差距的。
2四、关于先后端分离的理解。
2五、浏览器的生成页面操做???
一、加载HTML:用户输入域名,浏览器根据域名进行URL解析,向服务器发送请求,服务器返回HTML文件。
二、解析HTML:从HTML解析出DOM tree,CSS 规则树,
三、渲染:根据Dom树和css 规则树构建一个渲染树,rendering tree,
四、绘制:遍历DOM 树,绘制节点。
回流:当操做DOM,某个部分影响布局,就须要去从新渲染页面。
重绘:改变DOM的背景颜色,字体颜色等,不影响元素周围或内部的属性,将引发浏览器的重绘,
前端渲染的优势:
一、减小服务器的资源
二、富交互
三、局部刷新
四、懒加载
五、一次编码多端执行
缺点呢:
一、不利于SEO
二、增长请求次数,渲染页面慢
方法:
一、渲染页面加一下loading效果。
二、部分同构;指先后端共用 JS,首次渲染时使用 Node.js 来输出 HTML
2五、虚拟DOM
虚拟DOM 的核心思想是最小化操做DOM,使执行效率获得保证。
DOM很慢,而javascript对象处理很快。这样咱们用javascript对象表示DOM信息和结构,当状态变动的时候,从新渲染javascript的对象结构。
用新的树和旧的树作对比,记录两棵树的差别。记录下来的不一样就是咱们须要对页面真正DOM操做,而后把他们应用在DOM树上,页面就变动了。这样就能够作到:视图的结构确实是整个全新渲染了,可是最后操做DOM的时候至少变动了不一样的地方
CSS 部分
一、CSS样式的优先级
(1)相同权值状况下,CSS样式的优先级就是就近原则。!important>内联样式>内嵌样式>外链样式
(2)全职不一样是,根据权值来判断,标签的权值是1,类的权值是10,ID的权值是100;
(3)若使用 js 修改,行间样式box.style.background = "red"; > box.className = ("blue");
二、css display属性有哪些值,各有什么表现;
none:元素隐藏,并且元素显示的空间也不会保留,属性visibility:hidden是保留元素的空间的;
block:将元素设置为块级元素,元素单独占一行,能够设置width和height了。
inline:将元素设置为行内元素,元素先后没有换行符。并且没法设置宽高
inline-block:行内块元素。这个属性值融合了inline 和 block 的特性,便是它既是内联元素,又能够设置width和height。
inherit: 规定应该从父元素继承 display 属性的值。
table: 此元素会做为块级表格来显示(相似
一、网站性能优化 (1)减小一个页面访问所产生的http链接次数; 尽可能合并js和css文件,减小独立文件个数;可使用雪碧图 减小图片的数量 (2)将CSS放在页面顶端,JS文件放在页面底端 CSS的引用要放在html的头部header中,JS文件引用尽可能放在页面底端标签的后面,主要的思路是让核心的页面内容尽早显示出来。不过要注意,一些大量使用js的页面,可能有一些js文件放在底端会引发一些难以预料的问题,根据实际状况适当运用便可; (3)使JS,CSS文件内容最小化 使用一些javascript压缩工具对js脚本进行压缩,去除其中的空白字符、注释,最小化变量名等。 (4)尽可能减小外部脚本的使用,减小DNS查询时间 不要在网页中引用太多的外部脚本,首先,一次dns的解析过程会消耗20-120毫秒的时间;其次,若是在页面中引用太多的外部文件(如各类广告、联盟等代码),可能会由于外部文件的响应速度而将你的网站拖得很慢。若是不得不用,那么就尽可能将这些脚本放在页脚吧。不过有一点须要说起,就是浏览器通常只能并行处理同一域名下的两个请求,而对于不一样子的域名则不受此限制,所以适当将本站静态内容(css,js)放在其余的子域名下(如 static.xxx.com)会有利于提升浏览器并行下载网页内容的能力。 (5)最大限度利用用户浏览器的cache来减小服务器的开销。 必需要了解浏览器访问url时的工做机制: a. 第一次访问url时,用户从服务器端获取页面内容,并把相关的文件(images,css,js…)放在高速缓存中,也会把文件头中的expired time,last modified, Tags等相关信息也一同保留下来。 b. 用户重复访问url时,浏览器首先看高速缓存中是否有本站同名的文件,若是有,则检查文件的过时时间;若是还没有过时,则直接从缓存中读取文件,再也不访问服务器。 c. 若是缓存中文件的过时时间不存在或已超出,则浏览器会访问服务器获取文件的头信息,检查last modifed和ETags等信息,若是发现本地缓存中的文件在上次访问后没被修改,则使用本地缓存中的文件;若是修改过,则从服务器上获取最新版本。 (6)动静分离。apache是一个功能完善但比较庞大的web server,它的资源占用基本上和同时运行的进程数呈正比,对服务器内存的消耗比较大,处理并行任务的效率也通常。在一些状况下,咱们能够动静分离