0. 序
本文没有太多基础性的js内容,推荐一本书《JavaScript高级程序设计》,基础不好的同学建议先学习该本书。重点内容:事件,闭包,作用域练,原型,继承。
1.情简述一下javascript的执行环境(执行上下文)以及所涉及到到一些概念?(该文的整体笔记丢失,详细内容建议查看引用链接)
每当控制器转到可执行环境时,就会进入一个执行环境。
而执行环境大致分为三类:
全局环境函数环境eval(个人不了解,开发也不会用到不做讲解)
执行环境是靠栈来存储,每当开始执行js代码的时候,就进入到了全局执行环境,于是乎,就把全局执行环境压到了这个栈(我们暂时称它为执行环境栈)中。
而在全局代码中,会定义很多函数,函数中又会定义很多函数,而每当控制器执行到函数时,则就进入到了这个函数的执行环境中。
http://www.jianshu.com/p/cd3fee40ef59
2.sessionStorage,localStorage,cookie区别
共同点:都是浏览器端的数据存储,同源;不同点:
cookie在同源的http请求中携带,浏览器与服务器之前回传。cookie有路径的概念;cookie大小不超过4k。sessionStorage(浏览器关闭窗口前有效)和localStorage(一直有效)达到5M或者更大。cookie在设置的有效期前有效session不在不同的浏览器窗口中共享,loacl共享,cookie也共享。sessionStorage和localStorage支持事件机制
3.localStorage应该如何进行存储?
export function saveToLocal(id, key, value) {
let seller =
window.localStorage.__seller__;
if (!seller) {
seller = {};
seller[id] = {};
}
else {
seller =
JSON.parse(seller);
if (!seller[id]) {
seller[id] = {};
}
}
seller[id][key] = value;
window.localStorage.__seller__ =
JSON.stringify(seller);
};
export function loadFromLocal(id, key, def) {
let seller =
window.localStorage.__seller__;
if (!seller) {
return def;
}
seller =
JSON.parse(seller)[id];
if (!seller) {
return def;
}
let ret = seller[key];
return ret || def;
};
4.GET与POST的区别?
GET与POST都是HTTP协议中的请求发送方式,实际上他们都是TCP,所能做的事情都是一样的。不同在于,HTTP规定,发送GET请求时,在HTTP Header的请求行上就声明GET,反之POST就声明POST。HTTP要求,GET把数据放在url上,所以GET常用于发少量的数据用于查询;POST把数据放在body中,数据量相对较大用来存储。GET请求只发一次,POST发两次,header返回后再发送date。
5.同源策略指的是什么?
同源指的是以下三个都相同:
协议相同域名相同端口相同 所谓同源策略指的是:浏览器对不同源的脚本或者文本的访问方式进行的限制。比如源a的js不能操作引入的源b的元素属性。限制主要为:
Cookie、LocalStorage 和 IndexDB 无法读取。DOM无法获取AJAX请求不能发送
6.如何才能跨域,跨域方式有哪些?
设置document.domain
Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页的一级域名相同,只是二级域名不相同,浏览器允许通过设置document.domain共享Cookie。
在 www.a.com/a.html 中
document.domain =
'a.com';
var ifr =
document.createElement(
'iframe');
ifr.src =
'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload =
function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
ifr.cooike = doc.cookie;
};
在 script.a.com/b.html 中
document.cookie =
"test1=hello";
document.domain =
'a.com';
这样不仅能访问b的cookie,还可以访问b的dom,但是无法访问到LocalStorage 和 IndexDB,而且主要限制是a,b必须一级域名必须相同。
window.name
浏览器窗口都有window.name这个属性,这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页就可以读取它。
在b.com/data.html中有这样的数据
<script>
window.name = '我是你们想要的数据。';
</script>
现在a.com/index.html想获取这个数据应该怎么办?通过iframe充当中间人
<script>
function getDate(url){
var iframe = document.createElement('iframe');
iframe.style.display='none';
var state = 0;
iframe.onload = function(){
if(state == 1){
var dataPage = iframe.contentWindow;
var data = dataPage.name;
console.log(data);
dataPage.document.write('');
dataPage.close();
document.body.remove(iframe);
}else
{
state = 1;
iframe.contentWindow.location = url;
}
};
iframe.src = 'a.com/b.html';
}
getData('b.com/data.html');
</script>
些人可能会问为什么不直接把iframe的src设置为目的源(b.com/data.html)来获取数据,而是在设置为目的源之后,还要把src设置为同域名下的其他源(a.com/b.html)才获取数据?
如果直接设置src,那么iframe和本网页(a.com/index.html)会因为同源策略限制不能访问。而把iframe先设置为目的源,再设置为同域名下的其他源,那么同域名下的其他源就和目的源共享了一个窗口,故拥有同样window.name,并且由于是同域名下的源,并且设置了domain,故可以访问目标源的window.name。
state用来干什么 ?
每次设置src,都会刷新,state是标志位,让获取了数据就销毁掉。
window.postMessage
上面的方法都是破解,H5提供了官方的API:window.postMessage。允许跨窗口通信,不论这两个窗口是否同源。
// 举例来说,父窗口http:
//aaa.com向子窗口http:
//bbb.com发消息,调用postMessage方法就可以了。
var popup = window.open(
'http://bbb.com',
'title');
popup.postMessage(
'Hello World!',
'http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
window.opener.postMessage(
'Nice to see you',
'http://aaa.com');
window.addEventListener(
'message',
function(e) {
console.log(e.data);
},
false);
下面的例子是,子窗口通过event.source属性引用父窗口,然后发送消息。
window.addEventListener(
'message', receiveMessage);
function receiveMessage(event) {
event.source.postMessage(
'Nice to see you!',
'*');
}
AJAX
利用jsonp
// 首先,网页动态插入
<script>元素,由它向跨源网址发出请求。
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
阮一峰老师:浏览器同源政策及其规避方法
7. AJAX模型是什么?
AJAX全称为“AsynchronousJavaScript and XML” 异步的JavaScript和Xml,是一种创建交互式网页应用开发的新技术。
运用AJAX
function createXmlHttp(){
var xmlHttp;
if(
window.XMLHttpRequest){
xmlHttp =
new XMLHttpRequest();
}
else{
xmlHttp =
new ActiveXObject(
'Microsoft.XMLHTTP');
}
return xmlHttp;
}
var xhr = createXmlHttp();
xhr.open(
'GET',url+
'?date='+
new Date().getTime(),
true);
xhr.send();
xhr.onreadystatechange=
function(){
if(xhr.readyState ==
4 && xhr.status ==
200){
document.getElementById(
"myDiv").innerHTML=xhr.responseText;
}
}
8.为什么说jsonp不是真正的ajax?
为什么说jsonp是ajax?
因为他们目的一样,都是请求一个url,然后把服务器返回的数据进行处理。故jquery把jsonp封装为ajax的一种形式。
那为什么jsonp不是真正的ajax?
ajax和jsonp其实本质上是不同的东西,ajax的核心通过XmlHttpRequest获取非本页面内容,而jsnop的核心是动态加载script来调用服务器提供的js脚本。
ajax 和jsonp 不是一码事 细读详解
9.property 和 attribute有什么区别?
property表示DOM的基础属性。
<input id='ipt' value='123' other='
1111' />
console.
log(document.getElementById('ipt'));
可以发现有attributes,value,id,以及很多我们并没有赋值的属性,但是并没有other属性。value,id这样的就叫做DOM的基础属性。
正如打印出来的结果还有一个叫attributes的属性,类型是NamedNodeMap。这里就可以说attributes是DOM 的property的其中一个。
点击开这个你会发现有
0: id
1: value
2: other
length: 3
__proto__: NamedNodeMap
这个属性包含了显示定义在标签上的属性。
console.
log(ipt.attributes.other);
并且
console.log(
typeof ipt.attributes.other);
返回的是一个对象。
property能够从attribute中得到同步,attribute不会同步property上的值;
in1.
value =
'new value of prop';
console.log(
in1.
value);
console.log(
in1.attributes.
value);
in1.attributes.
value.
value =
'new value of attr';
console.log(
in1.
value);
console.log(
in1.attributes.
value);
10. 关于==的强制类型转换
image
重点:
Number与String比较,String转Number。Number与Object比较,Object转String。当比较中出现Boolean,无论另一个数据是什么类型,都先把Boolean转为Number。undefined与null,undefined与undefined, null与null都返回true。Object 与 Object只有引用相同返回true。
数据类型转化为Boolean的规则:
String的 “” 转换为Boolean为false其他都为trueNumber的0和NaN转换为Boolean为false其他都为trueObject的null转换为Boolean为false其他都为trueUndefined转换为false 不能转换为true
[] == ![] //
true
//
1.由于!的优先级比较高,先执行![],[]是空数组,数组是对象,由
2.3(需要了解的知识文字序号),则[]转换为boolean结果为
true,![]结果就为
false,表达式变为判断 []==
false
//
2.根据
1.3,将
false转为
Number,结果为
0,表达式变为判断 [] ==
0
//
3.根据
1.2,将[]变为
String,结果为
"",表达式变为判断
"" ==
0
//
4.根据
1.1,将
""变为
Number,结果为
0,表达式变为判断
0 ==
0
返回结果
true
console.log(
1 ==
true); // 文字
1.3,
Number(
true) =
1 ->
1 ==
1 true
console.log(
2 ==
true); // 文字
1.3,
Number(
true) =
2 ->
2 ==
1 false
console.log(
0 ==
false);//文字
1.3,
Number(
false)=
0 ->
0 ==
0 true
console.log(NaN == NaN);// 图片
1.c.i/
1.c.ii
false
console.log({} == {});// 图片
1.f {}是对象,比较引用指向的空间,因为是两个不同的空对象,地址也不一样
false
console.log([] == []);// 同理
console.log(null ==
0);// 文字
1.2 null是对象,
String(null) ==
"null" ->
"null" ==
0 ,文字
1.1 Number(
"null") == NaN -> NaN ==
0 false
console.log(undefined ==
0);// 这里将执行
String(undefined),之后执行步骤同上
总结:
undefined == null,结果是
true。且它俩与所有其他值比较的结果都是
false。
String == Boolean,需要两个操作数同时转为
Number。
String/Boolean ==
Number,需要
String/Boolean转为
Number。
Object ==
Primitive,需要Object转为Primitive(具体通过valueOf和toString方法)。
11.支持正则表达式的方法:
RegExp 对象方法
let str =
'woman1manm';
let patt =
/(wo)?man/g;
let str2 = str.replace(patt,
'2222');
let patt2 =
/2222/g;
patt.compile(patt2);
let str3 = str2.replace(patt,
'woman');
let str =
'22222womanmmmmmmmanmmmmman';
let patt =
/(wo)?(man)/g;
let what = patt.exec(str);
console.log(what);
console.log(patt.lastIndex)
what = patt.exec(str);
console.log(what);
String对象方法
// 1. search(patt),搜索字符串是否含有这个匹配,如果有就返回其实位置下标,没有就返回-
1。
// 2. match(patt), 在字符串内检索指定的模式,返回存放匹配结果的数组,该数组内容依赖于regexp是否具有g。
// 如果没有g,则返回的结果与exec相同。既,str.match(patt) 和 patt.exec(str)的返回结果相同。如果有g,是全局匹配,则会返回所有匹配结果。
let str =
'22222womanmmmmmmmanmmmmman';
let patt =
/(wo)?(man)/g;
let result = str.match(patt);
console.log(result);
// [
'woman',
'man',
'man' ]
// 3. replace(patt,str) ,返回一个新的字符串,如果有g将所有匹配值换成目标字符串,没有则替换第一个。
// $1、
$2、...、
$99代表圆括号所匹配的值
var name =
"Doe, John";
console.log(name.replace(
/(\w+)\s*, \s*(\w+)/,
"$2 $1"));
// John Doe
12.常用的正则表达式:
匹配一个邮箱:
/^+*@++/
开始必须是数组英文字母开头,然后是可以是任意数字字母下划线或者点,然后@,之后是邮箱名,域名。
匹配ip地址:
/^(
\d{1,3})
\.(
\d{1,3})
\.(
\d{1,3})
\.(
\d{1,3})
$/
匹配电话号码
/^[
1][
34578][
0-9]{9}$/
检查输入字符串是否是带小数的数字格式,可以是负数
/^-?(
\d+)[
\.]?(
\d+)$/
13. es6中的let,const和var有什么区别?
let的作用域是外层块,不是外层函数,而var是外层函数。
if(
true){
let a =
0;
var b =
0;
}
console.log(a)
console.log(b)
let没有声明提升,但是有暂时性死区。
console.log(a);
let a =
0;
if(
true){
var c =
0;
let c =
0;
}
重新声明会报错const与let一样,不同在于const引用的地址不能改变,值也不能改变。声明必须赋值。
14.var f = function g(){ return 23; }; typeof g()结果是什么?为什么?
typeof f :function,因为f本来就是一个函数。typeof f():number,因为f()先执行,返回了一个数字,23.typeof g:undefined,因为typeof一个未声明的变量,都默认返回undefined。typeof g():报错,g未定义。因为function是函数表达式的形式,并且赋值给了f,所以这个函数就算f,而g只是一个匿名,只能在函数f中使用,在全局访问不到。
15.最完美的数组去重:
function normalize(arr) {
if (arr &&
Object.prototype.toString.call(arr) !==
'[object Array]') {
return;
}
const objectSet = {};
objectSet.number =
Object.create(
null);
objectSet.string =
Object.create(
null);
objectSet.array =
Object.create(
null);
objectSet.boolean =
Object.create(
null);
objectSet.object =
Object.create(
null);
objectSet.undefined =
Object.create(
null);
let len = arr.length, temp,
type, map;
for (
let i = len -
1; i >=
0; i--) {
temp = arr[i];
if(
Object.prototype.toString.call(temp) ===
'[object Array]'){
map = objectSet.array;
}
else{
type =
typeof temp;
map = objectSet[
type];
}
if (temp
in map) {
arr.splice(i,
1);
}
else {
map[temp] =
true;
}
}
return arr;
}
const arr = [
1,
'1',
1,
'toString', [
'toString'],
1,
'',
2,
'',
null,
'null',
2,
2,
null,
3,
3];
console.log(normalize(arr));
16. 把字符串转化为大小写:
toUpperCase(): 转大写
toLowerCase(): 转小写
17. 为什么js是阻塞加载的?
当引用了js的时候,浏览器发送一个js请求,就会一直等待请求的返回,因为浏览器需要一个稳定的dom结构,而js中很有可能直接改变了dom结构,为了防止渲染好的树又被js代码修改,所以就会阻塞其他的下载和呈现。
18. 数组长度问题:
为什么结果不是3?
var arr = [];
arr[
0] =
'a';
arr[
1] =
'b';
arr.foo =
'c';
console.log(arr.length);
length返回的是array数组索引长度。
var arr = [];
arr[
9] =
1;
console.
log(arr.
length);
console.
log(arr[
8]);
19. ToPrimitive()是什么?
简单来说,就是将对象(object)转化为原始类型(undefined, null, boolean ,string, number)的方法,在计算一些强制类型转换时,都需要将对象转化为原始类型再进行计算。
ToPrimitive(obj)等价于,obj.valueOf(),如果为原始值则返回结果,否则,计算obj.toString(),如果是原始值返回,否则抛出异常。
注:此处有个例外,即Date类型的对象,它会先调用toString()方法,后调用valueOf()方法。
不同对象的valueOf,toString结果不同
console.log([,
2,
'ss'].valueOf());
console.log([,
2,
'ss'].toString());
console.log({
a:
11,
b:
'uu'}.valueOf());
console.log({
a:
11,
b:
'uu'}.toString());
console.log(
function(){
return 1}.valueOf());
console.log(
function(){
return 1}.toString());
20. '+new Array(017)' 的结果?
017是8进制,为15 -> + new Array(15);+为强制类型转Number -> Number(new Array(15));new Array(15) -> ToPrimitive([,,,,,,,,,,,,]);ToPrimitive([,,,,,,,,,,,,]) -> [,,,,,,,,,,].valueOf() 结果为 [,,,,,,,,,,][,,,,,,,,,,].toString() -> ',,,,,,,,,'Number(,,,,,,,,,) 为NaN
21. 不能用变量提升的思路取思考
var foo = {
n:
1};
var bar =
function(foo){
console.log(foo.n)
var foo = {
n:
2};
}
bar(foo);
这里有正常的传参和执行。
22. innerHTML, outerHTML, innerText, outerText的区别?
<
div id=
"div1"><span>abcd</span></
div>
//写
//
div.innerHTML =
"<p>大米</p>"; //
div保留
//
div.outerHTML =
"<p>大米</p>"; //
div也被取代了
//
div.innerText =
"米老鼠";
//console.log(
div); //
div中包裹米老鼠
div.outerText =
'<p>www</p>' //将原来单元素直接变成了纯文本,包括外围<
div>
23. Array方法的返回结果?
返回本身:reverse(),sort(),返回一个副本:concat(),slice(),map(),filter返回其他:
改变数组:
pop:返回arr最后一个元素push:返回新的长度shift:返回arr第一个元素unshift:返回新的长度splice:返回被删除的项目 不改变:
join:返回字符串some/every:booleanfindIndex:下标
24. 常用排序时间复杂度?
image
25. AMD 和 CMD 的区别有哪些?
AMD规范:github.com/amdjs/amdjs-api/wiki/AMD,是RequireJS在推广过程中对模块化定义的规范化产出。CMD规范:github.com/seajs/seajs/issues/242CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。区别
对于模块的依赖,AMD是提前执行,CMD是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.CMD 推崇依赖就近,AMD 推崇依赖前置。AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
define(function (require, exports, module) {
var a = require(
'./a')
a.doSomething()
var b = require(
'./b')
b.doSomething()
})
define(['./a', './b'], function (a, b) {
a.doSomething()
b.doSomething()
})
世界上,有两种比较流行的 JavaScript 模块化体系,一个是 Node 实现的 CommonJS,另外一个是 AMD。很多类库都同时支持 AMD 和 CommonJS,但是不支持 CMD。或许国内有很多 CMD 模块,但并没有在世界上流行起来。
26.keydown、keypress、keyup的区别
keypress主要用来捕获数字(shift+数字的符号)、字母(区分大小写)、小键盘等除了F1-12、SHIFT、Alt、Ctrl、Insert、Home、PgUp、Delete、End、PgDn、ScrollLock、Pause、NumLock、{菜单键}、{开始键}和方向键外的ANSI字符。keypress事件不能对系统功能键(例如:删除,后退等,还有中文输入法)进行正常的响应。keypress只能响应单个字符keydown和keyup可以响应除prscrn的所有按键,可以捕捉组合键。keydown和keyup不可以判断字符大小写,keypress可以。(keyCode)keypress事件的which值无法区分主键盘上的数字键和附键盘数字键的,而keydown、keyup的which值对主附键盘的数字键敏感。
27. 原生实现点击按钮切换弹框的隐藏,且点击弹框以外的地方使弹框隐藏:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
html {
height: 100%;
}
body {
height: 100%;
}
.div {
height: 300px;
width: 300px;
background-color: rosybrown;
transition: opacity 0.4s ease;
}
</style>
</head>
<body>
<button class="btn1">toggle
</button>
<div class="div" style="opacity: 1;">
<button class="btn2">console1
</button>
<button class="btn3">console2
</button>
</div>
<br />
<div class="div"></div>
<script>
var toggle = document.getElementsByTagName('button')[0];
var console1 = document.getElementsByTagName('button')[1];
var console2 = document.getElementsByTagName('button')[2];
var div = document.getElementsByClassName('div')[0];
var isShow = true;
toggle.onclick = function () {
if (isShow) {
div.style.opacity = '0';
isShow = false;
} else {
div.style.opacity = '1';
isShow = true;
}
}
div.addEventListener('click', function (e) {
e.stopPropagation();
}, false);
console1.addEventListener('click', function (e) {
console.log(1);
}, false);
console2.onclick = function (e) {
console.log(2);
}
document.body.addEventListener('click', function (e) {
var target = e.target;
if(target === toggle){
return;
}
div.style.opacity = '0';
isShow = false;
}, false);
</script>
</body>
</html>
思路:切换隐藏很简单,主要是点击周围的地方隐藏弹框。那么就在body上绑定一个事件,点击页面任何一个地方都隐藏,然后再去除弹框区域就行了。如何去除,就在弹框上绑定一个click事件,此事件发生后停止冒泡,那么点击弹框上任何内容的时候,事件都会冒泡到弹框上,然后弹框再停止冒泡,那么事件就不会走到body上,也就不会在弹框区域触发隐藏弹框事件。
28. js单例模式:
var Universe;
(
function () {
var instance;
Universe =
function Universe() {
if (instance) {
return instance;
}
instance =
this;
this.start_time =
0;
this.bang =
"Big";
};
} ());
var a =
new Universe();
var b =
new Universe();
alert(a === b);
a.bang =
"123";
alert(b.bang);
var single = (
function(){
var unique;
function getInstance(){
if( unique ===
undefined ){
unique =
new Construct();
}
return unique;
}
function Construct(){
}
return {
getInstance : getInstance
}
})();
js实现单例模式
作者:yozosann
链接:http://www.jianshu.com/p/3f03996d6502
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。