您的位置:首页 > Web前端 > JavaScript

JavaScript知识点整理

2017-08-06 22:56 411 查看
ECMAScript 5种简单(基本)数据类型:Undefined,Null,Boolean,Number,String,一种复杂数据类型:Object

typeof可返回的数据类型:undefined boolean string number object function

注: typeof null==“object”

stringObject.match(regexp) 返回存放匹配结果的数组。该数组的内容依赖于 regexp 是否具有全局标志 g。

说明:match() 方法将检索字符串 stringObject,以找到一个或多个与 regexp 匹配的文本。这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g。

如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。

如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。

注意:在全局检索模式下,match() 既不提供与子表达式匹配的文本的信息,也不声明每个匹配子串的位置。如果您需要这些全局检索的信息,可以使用 RegExp.exec()。

RegExpObject.exec(string) 返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。

说明:exec() 方法的功能非常强大,它是一个通用的方法,而且使用起来也比 test() 方法以及支持正则表达式的 String 对象的方法更为复杂。

如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看得出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。

但是,当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。

重要事项:如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把 lastIndex 属性重置为 0。

提示:请注意,无论 RegExpObject 是否是全局模式,exec() 都会把完整的细节添加到它返回的数组中。这就是 exec() 与 String.match() 的不同之处,后者在全局模式下返回的信息要少得多。因此我们可以这么说,在循环中反复地调用 exec() 方法是唯一一种获得全局模式的完整模式匹配信息的方法。

Location 对象存储在 Window 对象的 Location 属性中,表示那个窗口中当前显示的文档的 Web 地址。它的 href 属性存放的是文档的完整 URL,其他属性则分别描述了 URL 的各个部分。当一个 Location 对象被转换成字符串,href 属性的值被返回。这意味着你可以使用表达式 location 来替代 location.href。

对于这样一个URL

http://www.x2y2.com:80/fisker/post/0703/window.location.html?ver=1.0&id=6#imhere

- window.location.href

整个URL字符串(在浏览器中就是完整的地址栏)

本例返回值: http://www.x2y2.com:80/fisker/post/0703/window.location.html?ver=1.0&id=6#imhere

- window.location.protocol

URL 的协议部分

本例返回值:http:

- window.location.host

URL 的主机和端口部分

本例返回值:www.x2y2.com:80

- window.location.hostname

URL 的主机部分

本例返回值:www.x2y2.com

- window.location.port

URL 的端口部分

如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符

本例返回值:””

- window.location.pathname

URL 的路径部分(就是文件地址)

本例返回值:/fisker/post/0703/window.location.html

- window.location.search

查询(参数)部分

本例返回值:?ver=1.0&id=6

- window.location.hash

锚点

本例返回值:#imhere

location.reload(force)

如果该方法没有规定参数,或者参数是 false,它就会用 HTTP 头 If-Modified-Since 来检测服务器上的文档是否已改变。如果文档已改变,reload() 会再次下载该文档。如果文档未改变,则该方法将从缓存中装载文档。这与用户单击浏览器的刷新按钮的效果是完全一样的。

如果把该方法的参数设置为 true,那么无论文档的最后修改日期是什么,它都会绕过缓存,从服务器上重新下载该文档。这与用户在单击浏览器的刷新按钮时按住 Shift 健的效果是完全一样。

location.replace(newURL)

replace() 方法不会在 History 对象中生成一个新的记录。当使用该方法时,新的 URL 将覆盖 History 对象中的当前记录。

字符串常用操作函数

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

indexOf(str,fromIndex) – fromIndex表示字符串中开始检索的位置,结果返回字符串中str第一处出现的索引。如果没有匹配项,返回 -1 。

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

charCodeAt() - 返回在指定的位置的字符的 Unicode 编码。

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

test() - 检测一个字符串是否匹配某个模式.

match() – 找到一个或多个正则表达式的匹配。返回存放匹配结果的数组。

substring() – 返回字符串的一个子串。传入参数是起始位置和结束位置,会将较大值解析为结束位置,较小值解析为起始位置,负数解析强制为0。

substr() – 返回字符串的一个子串。传入参数是起始位置和想要返回的子串最大长度,起始位置为负自动加上字符串的长度。

replace() – 用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。replace(RegExp,function($1){…}) ‘$1’表示与RegExp中第一个子表达式相匹配的文本 ,若replace第二个参数为函数,则每次匹配成功调用函数,用函数返回值替换

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

slice() – 提取字符串的一部分,并返回一个新字符串,传入参数是想要提取部分的起始和结束位置,负数解析自动加上字符串长度,当起始位置大于结束位置返回空。

split(seperator,howmany) – 字符串分割,将一个字符串分割成一个字符串数组,seperator可以是字符串和正则,返回的数组不包括seperator本身,如果seperator是包含子表达式的正则表达式,那么返回的数组中包括与这些子表达式匹配的字串(但不包括与整个正则表达式匹配的文本)。

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

toLowerCase() – 将整个字符串转成小写字母,返回新的字符串。

toUpperCase() – 将整个字符串转成大写字母,返回新的字符串。

str1.localeCompare(str2) - 用本地特定的顺序来比较两个字符串。如果 str1 小于 str2,返回小于 0 的数。如果 str1 大于 str2,则该方法返回大于 0 的数。如果两个字符串相等,或根据本地排序规则没有区别,该方法返回 0。(把 < 和 > 运算符应用到字符串时,它们只用字符的 Unicode 编码比较字符串,而不考虑当地的排序规则。以这种方法生成的顺序不一定是正确的。)

nodeType 共有12 种不同的节点类型

元素element 1

属性attr 2

文本text 3

注释comments 8

整个文档(DOM 树的根节点)document 9

DOM常用操作

创建节点

createElement()

var node = document.createElement(“div”);

没什么可说的,创建一个元素节点,但注意,这个节点不会被自动添加到文档(document)里。

创建文本节点

createTextNode()

var value = document.createTextNode(“text”);

创建一个文本节点,常用来往元素节点里添加内容,也不会自动添加到文档里。

很多人知道innerHTML,不知道这个方法,这个添加的是静态文本,如果插入的内容不带HTML格式,用createTextNode比innerHTML安全,而innerText又有浏览器不兼容的问题,因此用createTextNode很好使。

插入节点到最后

appendChild()

node.appendChild(value);

将节点插入到最后,上面两个创建的节点不会自动添加到文档里,所以就要使appendChild来插入了。

如果是新的节点是插入到最后,而如果是已经存在的节点则是移动到最后,这点很多人注意不到,理解了这点,再和下面的方法结合,可以方便的移动操作节点。

插入节点到目标节点的前面

insertBefore()

var node = document.createElement(“div”);

var _p = document.createElement(“p”);

var _span = document.createElement(“span”);

node.appendChild(_p);

node.insertBefore(_span, _p);

<span>
节点在
<p>
节点前面插入,其中第二个参数是可选,如果第二个参数不写,将默认添加到文档的最后,相当于appendChild。

同样,appendChild和insertBefore,如果是已存在节点,他们都会自动先删除原节点,然后移动到你指定的地方。

将节点移动到最前面的技巧:

if (node.parentNode.firstChild)

node.parentNode.insertBefore(node, node.parentNode.firstChild);

else node.parentNode.appendChild(node);

复制节点

cloneNode(boolean)

node.cloneNode(true);

node.cloneNode(false);

复制上面的div节点,参数true,复制整个节点和里面的内容;false,只复制节点不要里面的内容,复制后的新节点,也不会被自动插入到文档,需要用到前面的方法去插入。

删除节点

removeChild()

node.removeChild(_p);

把上面的
<p>
节点从
<div>
里删除。不过一般情况下,不知道要删除的节点的父节点是什么,因此一般这么使:node.parentNode.removeChild(node);

替换节点

repalceChild(newNode, oldNode)

node.repalceChild(_p, _span);

把上面的
<span>
节点替换成
<p>
节点,注意无论是
<span>
还是
<p>
,都必须是
<div>
的子节点,或是一个新的节点。

设置节点属性

setAttribute()

node.setAttribute(“title”,”abc”);

不解释了,很容易明白。就说一句,用这个方法设置节点属性兼容好,但class属性不能这么设置。

获取节点属性

getAttribute()

node.getAttribute(“title”);

判断元素是否有子节点

hasChildNodes

node.hasChildNodes;

返回boolean类型,因此将新节点插入到最前面的技巧:

var node = document.createElement(“div”);

var newNode = document.createElement(“p”);

if (node.hasChildNodes) node.insertBefore(newNode, node.firstChild);

else node.appendChild(node);

最后是DOM的属性:

nodeName - 节点的名字(返回的标签名永远是大写);

nodeType - 返回一个整数,代表这个节点的类型,1-元素节点,2-属性节点,3-文本节点;

nodeValue - 返回一个字符串,这个节点的值(对属性节点和文本节点有效);

childNodes - 返回一个数组,数组由元素节点的子节点(包括文本节点,例如 换行)构成;

children-只返回元素子节点

firstChild - 返回第一个子节点;

lastChild - 返回最后一个子节点;

nextSibling - 返回目标节点的下一个兄弟节点,如果目标节点后面没有同属于一个父节点的节点,返回null;

previousSibling - 返回目标节点的前一个兄弟节点,如果目标节点前面没有同属于一个父节点的节点,返回null;

parentNode - 返回的节点永远是一个元素节点,因为只有元素节点才有可能有子节点,document节点将返回null;

Math对象

abs(x) 返回数的绝对值。

ceil(x) 对数进行上舍入。

exp(x) 返回 e 的指数。

floor(x) 对数进行下舍入。

max(x,y) 返回 x 和 y 中的最高值,不接受数组作为参数,如求数组中最大值可用 Math.max.apply(null,array);

min(x,y) 返回 x 和 y 中的最低值。

pow(x,y) 返回 x 的 y 次幂。

random() 返回 0 ~ 1 之间的随机数。

round(x) 把数四舍五入为最接近的整数。

sqrt(x) 返回数的平方根。

Array对象

concat() 连接两个或更多的数组,并返回结果。

join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。

pop() 删除并返回数组的最后一个元素

push() 向数组的末尾添加一个或更多元素,并返回新的长度。

reverse() 颠倒数组中元素的顺序,改变原数组。

shift() 删除并返回数组的第一个元素

unshift() 向数组的起始位置添加一个或更多元素,并返回新长度

slice() 从某个已有的数组返回选定的元素

sort() 对数组的元素进行排序,在原数组上进行排序,不生成副本。sort()用的是快排

如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。

若 a 等于 b,则返回 0。

若 a 大于 b,则返回一个大于 0 的值。

splice(index,howmany,item1,…..,itemX) 删除元素,并向数组添加新元素,该方法会改变原始数组,index表示要删除和插入的元素的位置。

ES5数组方法

indexOf lastIndexOf 同string方法

every() 测试数组的所有元素是否都通过指定函数的测试

function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true


some() 测试数组中是否有元素通过指定函数的测试

function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [2, 5, 8, 1, 4].some(isBigEnough);
// passed is false
passed = [12, 5, 8, 1, 4].some(isBigEnough);
// passed is true


forEach() 为每个元素执行对应的方法

var arr = [1,2,3,4,5,6,7,8];

// Uses the usual "for" loop to iterate
for(var i= 0, l = arr.length; i< l; i++){
console.log(arr[i]);
}
//Uses forEach to iterate
arr.forEach(function(item,index){
console.log(item);
});


forEach是用来替换for循环的

map() 对数组的每个元素进行一定操作(映射)后,会返回一个新的数组

var oldArr = [{first_name:"Colin",last_name:"Toh"},{first_name:"Addy",last_name:"Osmani"},{first_name:"Yehuda",last_name:"Katz"}];

function getNewArr(){

return oldArr.map(function(item,index){
item.full_name = [item.first_name,item.last_name].join(" ");
return item;
});

}

console.log(getNewArr());


filter() 返回一个新的匹配过滤条件的数组

var arr = [
{"name":"apple", "count": 2},
{"name":"orange", "count": 5},
{"name":"pear", "count": 3},
{"name":"orange", "count": 16},
];

var newArr = arr.filter(function(item){
return item.name === "orange";
});

console.log("Filter results:",newArr);


array.find(callback(ele,index)) 返回第一个满足回调函数中条件的元素

function isBigEnough(element) {
return element >= 15;
}

[12, 5, 8, 130, 44].find(isBigEnough); // 130


array.findIndex(callback(ele,index)) 返回第一个满足回调函数中条件的元素的索引

includes() 返回是否包含某个元素

var a = [1, 2, 3];
a.includes(2); // true
a.includes(4); // false


array1.reduce(callbackfn[, initialValue])

function callbackfn(previousValue, currentValue, currentIndex, array1)

在第一次调用回调函数时,作为参数提供的值取决于 reduce 方法是否具有 initialValue 参数。

如果向 reduce 方法提供 initialValue:previousValue 参数为 initialValue, currentValue 参数是数组中的第一个元素的值。如果未提供 initialValue:previousValue 参数是数组中的第一个元素的值, currentValue 参数是数组中的第二个元素的值。

// Define the callback function.
function appendCurrent (previousValue, currentValue) {
return previousValue + "::" + currentValue;
}

// Create an array.
var elements = ["abc", "def", 123, 456];

// Call the reduce method, which calls the callback function
// for each array element.
var result = elements.reduce(appendCurrent);

document.write(result);

// Output:
//  abc::def::123::456


判断一个js对象 a 是不是数组

a instanceof Array; //true

a.constructor==Array; //true 可以判断除null和undefined之外的类型

Array.isArray(a); //true ES5

Object.prototype.toString.call(a) === ‘[object Array]’ //通用,可判定所有类型

判断一个变量是不是string类型

- typeof str==”string”

- str.constructor==String

Date对象getYear()方法和getFullYear()方法区别

使用getYear()函数的本意是获取年份,以2010年为例,如:

var nowd = new Date();
var yf = nowd.getYear();


在IE中是可以正确获取年份:2010,但是在FF等浏览器下则为:110。原因则是 在 FF等浏览器内 getYear 返回的是 “当前年份-1900” 的值(即年份基数是1900)而IE则是 当today的年份大于等于2000的时,直接将1900加上了,返回的 2010。使用getFullYear()在IE和FF中都可以正确获取年份:2010. 所以获取年份推荐都使用:getFullYear()。

至于为什么时间都是从1970-01-01开始算,unix是最早的操作系统,它在1969年被开发出来,1971年正式发布,在这之前没有机器会需要来表示1970-01-01-00:00:00之前的时间。js沿用了这一习惯。

getComputedStyle与currentStyle获取样式

大家都知道,用
document.getElementById(‘element').style.xxx
可以获取元素的样式信息,可是它获取的只是DOM元素style属性里的样式规则,对于通过class属性引用的外部样式表,就拿不到我们要的信息了。 DOM标准里有个全局方法getComputedStyle,可以获取到当前对象样式规则信息,如:
getComputedStyle(obj,null).paddingLeft
,就能获取到对象的左内边距。但是事情还没完,万恶的IE不支持此方法,它有自己的一个实现方式,那就是currentStyle,不同于全局方法getComputedStyle,它是作为DOM元素属性存在的,如:
obj.currentStyle.paddingLeft
,在IE中就获取到对象的左内边距了,兼容性的写法如下:

return window.getComputedStyle ? window.getComputedStyle(obj,null).paddingLeft : obj.currentStyle.paddingLeft;




input textarea中的文本选中后会触发select事件, 相应的有select()方法

获取select对象选中的文本和值

selectObjext.options[selectObject.selectedIndex].text

selectObjext.options[selectObject.selectedIndex].value

公有方法 私有方法 特权方法 静态方法

function User(name,age){
this.name = name;//公有属性
var age = age;//私有属性
var name = name;
function alertAge(){//私有方法
alert(age);
}
this.getName = function(){ //特权方法 访问私有属性的公有方法叫特权方法
return name;//私有属性和方法不能使用this调用
}
}
User.prototype.getName = function(){//公有方法
return this.name;
}
User.myname = 'fire子海';//静态属性
User.getName =function(){//静态方法
return this.myname;
}


对象的外部是不能访问对象的私有属性和私有方法,公有方法不能调用私有方法,但是特权方法可以。静态属性和方法不会被实例继承

15. 深拷贝 浅拷贝

对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的内存,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的内存,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

深拷贝

var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化对象
newobj = JSON.parse(str); //还原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};


浅拷贝

function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}


基本类型 引用类型

基本类型的变量的值存在栈中,引用类型的变量的值是一个地址,地址存在栈中,地址指向的对象存在堆中。

em 相对于父元素的font-size; rem 相对于根元素html的font-size

html {font-size: 62.5%;} /*10 ÷ 16 × 100% = 62.5%*/
body {font-size: 1.4rem;}/*1.4 × 10px = 14px */
h1 { font-size: 2.4rem;}/*2.4 × 10px = 24px*/


在根元素
<html>
中定义了一个基本字体大小为62.5%(也就是10px。设置这个值主要方便计算,如果没有设置,将是以“16px”为基准 )

18. HTML标准中GET POST的区别

本质都是TCP连接,HTTP定义GET取数据,POST更新数据,而HTML标准给GET POST加上了使用规则

GET使用URL传参,且请求会被浏览器缓存,且会加入历史记录,而POST将数据放在BODY中。(如何防止缓存get请求,1.可以在url加上一个随机参数?t=Math.random()或者?date=new Date().getTime();2.利用xhr请求的设置 xmlHttp.setRequestHeader(‘If-Modified-Since’, 0);If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。

如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。

如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。)

一个典型的代理服务器缓存查询请求idempotent request:该代理获取请求,检查头信息,然后发送到服务器,收到服务器的响应后,检查,如果是可缓存的,则将这个响应以URL为key(会携带一部分头信息)以响应为内容缓存起来。这种办法对于Get请求很有效,因为反复调用相同的URL将会有相同的响应。代理可以利用idempotent request来缓存get请求。但是对于不是idempotent request的post请求来讲,不能使用URL和头信息来作为key进行缓存,因为响应可能是不同的,相同的URL但是得到了不同的结果。

- GET 浏览器和服务器对URL会有长度上的限制,则POST的数据则可以非常大。

- POST比GET安全,因为数据在地址栏上不可见。

- GET和POST还有一个重大区别,简单的说:GET产生一个TCP数据包;POST产生两个TCP数据包。长的说:对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。当网络环境好的情况下,1次包跟2次包的在时间上差别基本可以无视。而在网络环境差的情况下,(2次包)TCP的验证数据包完整性上,有非常大的优点,客户端先告诉服务端即将发送的数据包大小,MD5等标识,当服务端告诉客户端收到(ACK包)的时候,客户端再次向服务端发送POST 的DATA。假如网络环境不好,网络延迟、丢包的时候,服务端会等待(延迟时),客户端重发POST的DATA数据到服务单,来确保本次请求的完整性。

19. webpack vs gulp.js

Gulp 的定位是 Task Runner, 就是用来跑一个一个任务的。

放在以前比如我想用sass写css, coffee写js, 我必须手动的用相应的compiler去编译各自的文件,然后各自minify。这时候designer给你了两张新图片,好嘞,接着用自己的小工具手动去压缩图片。

后来前端人不能忍了,搞出个自动化这个流程的 Grunt/Gulp, 比如你写完代码后要想发布production版本,用一句 gulp build 就可以

- rm 掉 dist文件夹中以前的旧文件

- 自动把sass编译成css, coffee编译成js

- 压缩各自的文件,压缩图片,生成图片sprite

- 拷贝minified/uglified 文件到 dist 文件夹

但是它没发解决的是 js module 的问题,是你写代码时候如何组织代码结构的问题.

之前大家可以用 require.js, sea.js 来 require dependency, 后来出了一个 webpack 说 我们能不能把所有的文件(css, image, js) 都用 js 来 生成依赖,最后生成一个bundle呢? 所以webpack 也叫做file bundler.

同时 webpack 为了解决可以 require 不同文件的需求引入了loader, 比如面对sass文件有

sass-loader, 把sass 转换成 css

css-loader, 让 webpack 能识别处理 css

style-loader, 把识别后的 css 插入到 html style中

类似的识别es6 有babel-loader

本来这就是 webpack 的初衷,require everything, bundle everything. 一开始 webpack 刚出来的时候大家都是把它结合着 gulp 一起用的, gulp 里面有个 gulp-webpack,就是让 webpack 专门去做module dependency的事情, 生成一个bundle.js文件,然后再用 gulp 去做一些其他杂七杂八minify, uglify的事情。 后来人们发现 webpack 有个plugins的选项, 可以用来进一步处理经过loader 生成的bundle.js,于是有人写了对应的插件, 所以minify/uglify, 生成hash的工作也可以转移到webpack本身了,挤掉了gulp这部分的市场份额。 再后来大家有发现 npm/package.json 里面的scripts 原来好好用啊,调用任务的时候就直接写一个简单的命令,因为 gulp 也不就是各种插件命令的组合呀,大部分情况下越来越不需要 gulp/grunt 之类的了 ref. 所以你现在看到的很多新项目都是package.json里面scripts 写了一堆,外部只需要一个webpack就够了。

打个不恰当的比方,webpack就像微信一样,本来就是做聊天(module dependency)的,后来生生搞出一个微信小程序(processing files),大家面对简单的需求发现这个比原生app方便使用啊,于是开发原生的人越来越少一样。

所以 LZ 一开始就模仿其他项目用 npm scripts + webpack 就好了,当你发现有哪些任务你没法用 webpack 或者npm scripts 解决起来麻烦, 这个时候再引入task runner 也不迟

20. Async Await

这里我们要实现一个暂停功能,输入N毫秒,则停顿N毫秒后才继续往下执行。

var sleep = function (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, time);
})
};

var start = async function () {
// 在这里使用起来就像同步代码那样直观
console.log('start');
await sleep(3000);
console.log('end');
};

start();


控制台先输出start,稍等3秒后,输出了end。

async 表示这是一个async函数,await只能用在这个函数里面。

await 表示在这里等待promise返回结果了,再继续执行。

await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)

await等待的虽然是promise对象,但不必写.then(..),直接可以得到返回值。

var sleep = function (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 返回 ‘ok’
resolve('ok');
}, time);
})
};

var start = async function () {
let result = await sleep(3000);
console.log(result); // 收到 ‘ok’
};


既然.then(..)不用写了,那么.catch(..)也不用写,可以直接用标准的try catch语法捕捉错误。

var sleep = function (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 模拟出错了,返回 ‘error’
reject('error');
}, time);
})
};

var start = async function () {
try {
console.log('start');
await sleep(3000); // 这里得到了一个返回错误

// 所以以下代码不会被执行了
console.log('end');
} catch (err) {
console.log(err); // 这里捕捉到错误 `error`
}
};


浏览器兼容性

各大浏览器的内核渲染页面的标准不一致导致了浏览器兼容性问题,下面列举遇见过的几个问题

css文件开头写上 *{padding:0;margin:0;box-sizing:border-box} input,textarea,checkbox,radio{padding:6px 10px;border:1px solid #eee}

placeholder颜色

::-moz-placeholder{color:red;} //ff

::-webkit-input-placeholder{color:red;} //chrome,safari

:-ms-input-placeholder{color:red;} //ie10

opacity

opacity:0.5;

filter:alpha(opacity=50); //filter 过滤器 兼容IE678

事件

tar.addEventListener(“click”,function(e){e.target;e.pageX})

tar.attachEvent(“onclick”,function(e){e.srcElement;e.X}) IE8以下

盒子模型

标准模型的width=content width

IE盒模型的width=content width+padding+border IE8以下

BFC

w3c规范中的BFC定义:

浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。

在BFC中,盒子从顶端开始垂直地一个接一个地排列,两个盒子之间的垂直的间隙是由他们的margin 值所决定的。在一个BFC中,两个相邻的块级盒子的垂直外边距会产生折叠。

根据w3c规范,两个margin是邻接的必须满足以下条件:

必须是处于常规文档流(非float和绝对定位)的块级盒子,并且处于同一个BFC当中。

没有线盒,没有空隙(clearance,下面会讲到),没有padding和border将他们分隔开

都属于垂直方向上相邻的外边距,可以是下面任意一种情况

元素的margin-top与其第一个常规文档流的子元素的margin-top

元素的margin-bottom与其下一个常规文档流的兄弟元素的margin-top

height为auto的元素的margin-bottom与其最后一个常规文档流的子元素的margin-bottom

浮动和绝对定位不与任何元素产生 margin 折叠

原因:浮动元素和绝对定位元素不与其他盒子产生外边距折叠是因为元素会脱离当前的文档流,违反了上面所述的两个margin是邻接的条件同时,又因为浮动和绝对定位会使元素为它的内容创建新的BFC,因此该元素和子元素所处的BFC是不相同的,因此也不会产生margin的折叠。

inline-block元素与其兄弟元素、子元素和父元素的外边距都不会折叠(包括其父元素和子元素)

inline-block不符合w3c规范所说元素必须是块级盒子的条件,因为规范中又说明,块级盒子的display属性必须是以下三种之一:’block’, ‘list-item’, 和 ‘table’。

23. flex

container属性

flex-direction:row | row-reverse | column | column-reverse

flex-wrap:nowrap | wrap | wrap-reverse

flex-flow:row nowrap

justify-content:flex-start | flex-end | center | space-between | space-around 项目在主轴上的对齐方式

align-items:flex-start | flex-end | center | baseline | stretch 项目在交叉轴上的对齐方式

align-content:flex-start | flex-end | center | space-between | space-around | stretch 多根轴线的对齐方式

item属性

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。也可以设为固定像素值

flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

align-self:auto | flex-start | flex-end | center | baseline | stretch; 允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

24. clear: left/right/both 清除浮动,让自身不受浮动影响,并不能影响相邻元素

25. arr=object.keys() 获取可枚举属性(非基本数据类型的内置属性,可读属性)

arr=object.getOwnPropertyNames() 获取所有属性

object.hasOwnProperty(item) 可枚举属性

26. clientHeight和clientWidth属性指元素的内容部分再加上padding的所占据的视觉面积,不包括border和滚动条占用的空间。

offsetWidth=content+padding+border;

offsetLeft是相对offsetParent的位置, offsetParent是离元素最近且定位过的上级元素

获取元素绝对位置的坐标

function getElementLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null){
      actualLeft += current.offsetLeft;
      current = current.offsetParent;
    }
    return actualLeft;
  }


获得元素相对位置的坐标,即相对浏览器的坐标,用绝对坐标减去滚动条高度即为相对坐标

function getElementViewLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null){
      actualLeft += current.offsetLeft;
      current = current.offsetParent;
    }
    if (document.compatMode == "BackCompat"){
      var elementScrollLeft=document.body.scrollLeft;
    } else {
      var elementScrollLeft=document.documentElement.scrollLeft;
    }
    return actualLeft-elementScrollLeft;
  }


另外还有一种方法,使用getBoundingClientRect()方法。它返回一个对象,其中包含了left、right、top、bottom四个属性,分别对应了该元素的左上角和右下角相对于浏览器窗口(viewport)左上角的距离。

所以,网页元素的相对位置就是

  var X= this.getBoundingClientRect().left;
  var Y =this.getBoundingClientRect().top;


再加上滚动距离,就可以得到绝对位置

  var X =this.getBoundingClientRect().left+document.documentElement.scrollLeft;

  var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;


可替换元素就是浏览器根据元素的标签和属性,来决定元素的具体显示内容,大多数元素是不可替换元素,即其内容直接表现给用户端(例如浏览器)。

行内元素可以设置border padding和margin值,不过只有左右的padding和margin值影响布局,如果加上border,行内元素会包括上下padding,只是上下padding不影响布局,获得的offsetTop值会考虑padding值,例如,某个行内元素的坐标是0,但是加上padding-top=100px后,offsetTop会变成-100,但视觉上行内元素的位置不变,加上border后,上边框也无法看到,因为已经延伸到可视区域以上。以上是对行内不可替换元素(span a p)来说,而对于行内可替换元素(input img)来说,padding margin 在四个方向都是有效的,宽高和line-height也有效,行为更像是块状元素。对于行内不可替换元素的line-height属性,不影响行内框(元素内容区域)的高度,但是会影响所在行框的高度。

vertical-align:10% 相对的是line-height值的10%

vertical-align对行内元素有效,默认值是baseline,所以块状元素内的行内元素下面会留白,可以将行内元素的vertical-align属性赋为bottom,或者将同一行的文字的line-height设置的小一点,让文字底部与行内框底部贴合,就能消除留白。

两列等高布局

子元素:margin-bottom:-3000px; padding-bottom:3000px;float:left;

父元素:overflow:hidden;

28.

if([]==false){console.log("[]==false")} //输出 []==false
if({}==false){console.log("{}==false")}
if({}==true){console.log("{}==true")}
if([]){console.log("[]")} //输出 []
if({}){console.log("{}")} //输出 {}


Cookie LocalStorage SessionStorage

cooike的性质是绑定在特定的域名下的,每个域名的cookie限制数量因浏览器差异各不相同,如果想存储超过最大限制数量的cookie可以用子cookie,即cookie的名值对中的值是多个名值对。浏览器将一个域名下的所有cookie大小限制在4KB左右 ,主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”,这通常就是通过在 Cookie 中存入一段辨别用户身份的数据(session id)来实现的。服务器可以在HTTP响应头部中设置set-cookie字段来设置Cookie。客户端JavaScript也可以通过浏览器提供的document.cookie来操作Cookie。

下面是一个遵循Netscape cookie草案的完整的Set-Cookie 头:

Set-Cookie:customer=huangxp; path=/foo;domain=.ibm.com; expires= Wednesday, 19-OCT-05 23:12:40 GMT; secure;HttpOnly

Set-Cookie的每个属性解释如下:

Customer=huangxp:一个”名称=值”对,把名称customer设置为值”huangxp”,这个属性在Cookie中必须有。如果指定了名称,值为空( 如Customer=),则表示删除此cookie。

path=/foo:指定与cookie关联的WEB页。值可以是一个目录,或者是一个路径。如果http://www.zdnet.com/devhead/index.html 建立了一个cookie,那么在http://www.zdnet.com/devhead/目录里的所有页面,以及该目录下面任何子目录里的页面都可以访问这个cookie。但是,如果http://www.zdnet.com/zdnn/ 需要访问http://www.zdnet.com/devhead/index.html设置的cookes,该怎么办?这时,我们要把cookies的path属性设置成“/”。在指定路径的时候,凡是来自同一服务器,URL里有相同路径的所有WEB页面都可以共享cookies。如果指定了path,但是path与当前访问的url不符,则此cookie将被忽略。

domain=.ibm.com :指定关联的WEB服务器或域。值是域名,比如zdnet.com。这是对path路径属性的一个延伸。如果我们想让catalog.mycompany.com 能够访问shoppingcart.mycompany.com设置的cookies,该怎么办? 我们可以把domain属性设置成“mycompany.com”,并把path属性设置成“/”。FYI:不能把cookies域属性设置成与设置它的服务器的所在域不同的值。 浏览器会将domain和path都相同的cookie保存在一个文件里,cookie间用*隔开

expires= Wednesday, 19-OCT-05 23:12:40 GMT: 指定cookie失效的时间。如果没有指定失效时间,这个cookie就不会被写入计算机的硬盘上,并且只持续到这次会话结束。 浏览器不会发送cookie的path和有效期给服务器

secure: 如果secure 这个词被作为Set-Cookie 头的一部分,那么cookie只能通过安全通道传输(目前即SSL通道)。否则,浏览器将忽略此Cookie。

如果在Cookie中设置了”HttpOnly”属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击

一旦浏览器接收了cookie,这个cookie和对远端Web服务器的连续请求将一起被浏览器发送。例如 前一个cookie被存入浏览器并且浏览器试图请求 URL http://www.ibm.com/foo/index.html 时,下面的HTTP包头就被发送到远端的Web服务器。

GET /foo/index.html HTTP/1.0

Cookie:customer=huangxp

document.cookie获得的是一系列由分号和空格隔开的名值对:name1=value1; name2=value2; 所有的名值对都是经过URL编码的,必须使用decodeURIComponent()来解码。

设置cookie值: document.cookie=encodeURIComponent(“customer”)+”=”+encodeURIComponent(“huangxp”)+”; path=/foo;domain=.ibm.com; expires= Wednesday, 19-OCT-05 23:12:40 GMT; secure”

- SessionStorage 主要针对会话的小段数据存储,可以将一部分数据在当前会话中保存下来,刷新页面数据依旧存在。但当页面关闭后,sessionStorage 中的数据就会被清空.不同的浏览器窗口的同一页面也不能共享sessionstorage对象。 应用:单页表单拆成多页按步骤填写缓存数据

- LocalStorage 的目的是跨越会话存储数据,localStorage对象在所有同源窗口中都是共享的。应用:管理购物车,H5游戏的本地数据

- 同源Storage对象一般限制在5MB



Cookie使用

function setCookie(key,value){
var dateStr = (new Date()).toGMTString();
document.cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value) + ";expires=" + dateStr; //value加密
}
function getCookie(key){
var idx = document.cookie.indexOf(encodeURIComponent(key) + "=")
if(idx == -1) return;

var start = idx + encodeURIComponent(key).length + 1,
end = document.cookie.indexOf(";", idx);
if(end==-1) end = document.cookie.length;

return decodeURIComponent(document.cookie.substring(start,end));
}


Storage类型

localStorage.clear();
localStorage.setItem('key', 'value');
localStorage.getItem('key');     // => 'value'
localStorage.removeItem('key');
localStorage.length //名值对的个数
localStorage.key(i) //第i个名值对的名

//因为它只能存储字符串,要存JSON只能序列化为字符串
var testObject = { 'one': 1, 'two': 2, 'three': 3 };

// Put the object into storage
localStorage.setItem('testObject', JSON.stringify(testObject));

// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');

console.log('retrievedObject: ', JSON.parse(retrievedObject));


阻止事件传播

event.stopPropagation()

终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。但不能阻止同一个 Document 节点上的其他事件句柄被调用

event.stopImmediatePropagation();

如果某个元素有多个相同类型事件的事件监听函数,则当该类型的事件触发时,多个事件监听函数将按照顺序依次执行.如果某个监听函数执行了 event.stopImmediatePropagation()方法,则除了该事件的冒泡行为被阻止之外(event.stopPropagation方法的作用),该元素绑定的后序相同类型事件的监听函数的执行也将被阻止.

阻止事件默认行为 event.preventDefault();

return false 相当于

•event.preventDefault();

•event.stopPropagation();

•停止回调函数执行并立即返回

如果你使用了”return false“,它只会在你的回调函数执行结束才去取消浏览器的默认行为,但是使用e.preventDefault,我们有更多的选择,它可以随时停止浏览器执行默认动作,而不管你将它放在函数的哪个部分,清楚自己想用什么,少用return false

31. script元素的onload,onreadystatechange事件

IE的 script 元素支持onreadystatechange事件,不支持onload事件。

FF的script 元素不支持onreadystatechange事件,只支持onload事件。

如果要在一个< script src=”xx.js”> 加载完成执行一个操作,FF使用onload事件就行了,IE下则要结合onreadystatechange事件和this.readyState,以 下是IE的一个例子:

< script type="text/javascript" src="xx.js" onreadstatechange="if(this.readyState=='load') alert('loaded');">< /script>


this.readyState的值为’loaded’或者’complete’都可以表示这个script已经加载完成.

如何结合IE和FF的区别?

var script = document_createElement_x('script');

script.src="xx.js";

script.onload = script.onreadystatechange = function(){

if(  ! this.readyState     //这是FF的判断语句,因为ff下没有readyState这人值,IE的readyState肯定有值

|| this.readyState=='loaded' || this.readyState=='complete'   // 这是IE的判断语句

){

alert('loaded');

}

};


function ready(fn){

if(document.addEventListener) {
document.addEventListener('DOMContentLoaded', function() {
document.removeEventListener('DOMContentLoaded',arguments.callee, false);
fn();
}, false);
}

// 如果IE
else if(document.attachEvent) {
// 确保当页面是在iframe中加载时,事件依旧会被安全触发
document.attachEvent('onreadystatechange', function() {
if(document.readyState == 'complete') {
document.detachEvent('onreadystatechange', arguments.callee);
fn();
}
});
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript