@tsingwong
2017-11-16T01:17:14.000000Z
字数 52670
阅读 2340
实习
IE-Trident,Chrome及安卓4.4以上-Blink(Webkit分支),Safari-Webkit,FireFox-Gecko,Opera-原Presto先Blink
具体了解一下:
-ms-
;-webkit-
;-moz-
;-o-
;-webkit-
CSS规范中,每个元素都由display属性来确定其类型,“block”为块级元素,“inline”为行内元素。
行内元素: 水平方向排列,不能包含块级元素,设置width,height无效(可以使用line-height),margin、padding上下无效,如:a b span img input select strong tesxarea等。
块级元素: 垂直方向排列,各占据一行,如:div ul ol li dl dt dd h1-h6等。
设置diplay
属性为block
(即块级元素),设置为inline
(即行内元素),也可以设置为inline-block
(行内块元素)。
不会为自身内容形成新的块,而让内容分布在多行中的元素叫做行内级元素。此类元素可以与其它行内级元素在同一行中显示而不会另起一行,例如span,strong。
在面试时,当被问到行内级元素可否设置宽高时,根据我们的经验往往会回答不能。但是这样往往着了面试官的道,因为有一些特殊的行内元素,比如img,input,select等等,是可以被设置宽高的。
一个内容不受CSS视觉格式化模型控制,CSS渲染模型并不考虑对此内容的渲染,且元素本身一般拥有固有尺寸(宽度,高度,宽高比)的元素,被称之为置换元素。比如img是一个置换元素,当不对它设置宽高时,它会按照本身的宽高进行显示。所以这个问题的正确答案应该是置换元素可以,非置换元素不可以。
浮动元素脱离文档流,不占用空间。浮动元素碰到包含他的元素的边框或者其他浮动元素的边框停留。按照原理可以归结为两种方法:
clear:both
和 构造 BFC 法。
方法 | 分类 |
---|---|
浮动末尾添加新标签,设置样式为 clear:both |
clear:both |
浮动末尾添加<br clear='both'/> |
clear:both |
使用::after 伪元素 |
clear:both |
父元素设置display:table |
构造BFC |
父元素设置overflow:auto/hidden |
构造BFC |
父元素也浮动 | 构造BFC |
<style type="text/css">
.div1{border:1px solid red}
.div2{background:#800080;border:1px solid black;height:200px;margin-top:10px}
.left{float:left;width:40%;height:200px;background:#DDD}
.right{float:right;width:30%;height:200px;background:#C0A16B}
/*2.父级div定义 伪类:after 和 zoom */
/*清除浮动代码*/
.clearfloat:after{
content:"clear";
display:block;
clear:both;
visibility:hidden;
height:0;
}
.clearfloat{zoom:1}
</style>
</head>
<body>
<div class="div1 clearfloat">
<div class="left">Left</div>
<div class="right">Right</div>
</div>
<div class="div2">
div2
</div>
</body>
很少很少的情况是不得已使用hack才能解决的。追求页面样式无hack也是提高CSS技能不错方法之一。
color:blue; /*所有浏览器*/
color:red\9; /*IE8以及以下版本浏览器*/
*color:green; /*IE7及其以下版本浏览器*/
_color:purple; /*IE6浏览器*/
content-box: 宽度高度分别应用到元素的内容框。即宽度高度之外绘制元素的内边距和边框。
border-box: 内边距和边框都将在已经设定的宽度和高度内绘制。内容的宽度和高度等于已设定的宽度和高度分别减去边框和内边距。在移动端收到推崇。原因是如果在移动端配置两个宽度为50%的,注IE8以上,且需要写各种兼容代码。
1px的边框在
devicePixelRatio=2
的retina屏下会显示成2px,在iphone 6 plus 下,更显示成3px。由其影响美感。
IOS 8 已经开始支持 0.5px,但是之前版本 IOS 及其他安卓浏览器并不支持 0.5px,会解析为 0px。
使用 viewport + REM
<!DOCTYPE>
声明位于HTML文档的首行,作用是告诉浏览器的解析器用什么文档标准解析这个文档。如果DOCTYPE不存在或格式不正确,则文档使用兼容模式呈现。
标准模式的排版和JS运作模式都是以该浏览器支持的最高标准运行。在兼容模式中,页面是以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点出现错误。
<!DOCTYPE HTML>
# HTML5
<!DOCTYPE HTML>
# HTML4.01
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
HTML5 不是基于 SGML(标准通用置标语言),因此不需要对DTD(文档类型定义)进行引用,但仍然需要doctype来规范浏览器的行为。
HTML4.01 基于 SGML,故需要对DTD引用,才能告知浏览器文档所使用的文档类型。
- link 标签是XHTML标签,除加载CSS外,还可以定义RSS,定义rel链接属性等,而@import是CSS提供的,只能用于加载CSS;
- link 在页面加载的同时会同步加载,@import在页面加载完毕后才加载;
- @import 是CSS2.1提出的,只在IE5以上被识别,而link是XHTML标签,不存在兼容问题。
- 忘记在哪个网站上看到过说他们之前存在权重高低问题。我特别测试了一下,并不存在权重,只存在覆盖,即后者会覆盖前者。
# link语法
<link rel="stylesheet" href="style.css" type="text/css">
# @import语法
<style type="text/css">
@import url(style.css");
</style>
HTML5并不是SGML(标准通用置标语言)的子集,主要新特性如下:
1. 画布API(canvas);
2. 多媒体API(audio,video);
3. 地理API(geoloction);
4. 本地离线存储localStorage长期存储数据,浏览器关闭数据不丢失;
5. sessionStorage数据在浏览器关闭后自动删除;
6. 表单控件,如:calendar,date,time,email,url,search等;
7. 新技术,如:webworker,websocket等;
8. 更多语义化明显的标签,如:article,aside, footer, header, nav, section等HTML5中移除元素:
1. 纯表现的元素,如:basefont, big, center, s, font, s, strike, tt, u等;
2. 对可用性产生负面影响的元素,如: frame, frameset, noframes;IE8/7/6 支持通过
document.createElement
方法创建的标签,所以可以使用这一特性使浏览器使用HTML5标签,当然还需要为标签添加默认样式。
较为好的方式是直接使用成熟的框架,目前使用最多的是html5shiv | html5shif
框架:
<!--[if lt IE 9]>
<script> src="http://html5shiv.googlecode.com/svn/trunk/html5.js"</script>
<![endif]-->
至于区分问题,上面介绍的HTML5与HTML4.1的DOCTYPE声明就可以区分吧(个人看法),还有新增的结构元素和功能元素。
语义化是根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者读写更优雅的代码,同时让浏览器的爬虫和机器更好的解析。
作用:
1. 在没有CSS情况下,页面也呈现出很好的内容结构、代码结构;
2. 有利于SEO:搜索引擎的爬虫也依赖HTML标记来确定上下文和关键字的权重;
3. 用正确的标签做正确的事情;
4. HTML语义化让页面的内容结构化,结构更清晰,便于浏览器、搜索引擎解析;
5. 便于团队开发和维护,语义化更具可读性。
基本类型:Undefined, Null, Boolean, Number, String。
数据类型:String Object null undefined Array Boolean Number
Number和String,刚才这些都属于数据封装类对象,Function,Arguments,Math,Date,RegExp,Error等。
在JS高程中给的解释是这样的,this对象是在运行时基于函数的执行环境绑定的;全局函数中,this等于window,当函数被作为某个对象的方法调用时,this等于那个调用的对象。
this总是指向函数的直接调用者(非间接调用者);
如果使用new关键字,this指向new出来的那个新对象;
在事件中,this指向触发这个事件的对象,特殊的是,IE中attatchEvent中的this总是指向全局对象。
eval()函数可以计算某个字符串,其中包含要计算的JS表达式或者要执行的语句。
应该尽量避免使用eval(),因为eval不安全,且非常消耗性能(2次,一次解析成js语句,一次执行)。
在JSON字符串转换成JSON对象可以使用eval方法,var obj = eval("("+ json + ")")。
然,个人感觉还是使用原生JS的parse方法好一点,obj = JSON.parse(json).
#创建节点
var newH3 = document.createElement("H3"); # 创建元素节点、
var newText = document.createTextNode("Text"); # 创建文本节点
# 插入节点
newH3.appendChild(newText);
#创建属性
newH3.setAttribute("id","123"); # 创建属性时,前者是名称后者是值
#获取属性
newH3.getAttribute("id");
#删除节点
newH3.removeChild();
#替换节点
newH3.replaceChild(newnode, oldnode);
#在已有节点之前插入一个节点
list.insertBefore(newnode, existingnode);
#查找节点
document.getELementsByTagName("li"); # 通过标签名字查找
document.getElementsByName("wang"); # 通过元素的name属性的值来查找
document.getElementById("123"); # 通过元素ID查找,具有唯一性
null 与 undefined 都表示“无”,且在if语句中,都会被自动转换为false。
在最初设计时,null是表示一个“无”的对象,转换为数值时为0;undefined是一个表示“无”的原始值,转换为数值为NaN。
null表示“没有对象”,即此处不该有值,典型用法:
1. 作为函数的参数,表示该函数的参数不是对象;
2. 作为对象原型链的终点。
undefined表示“缺少值”,即此处应该有一个值,但是还没定义,典型用法:
1. 变量被声明后,并没有赋值时,它就等于undefined;
2. 调用函数时,应该提供的参数没提供,该参数就等于undefined;
3. 对象没有赋值的属性,该属性的值为undefined;
4. 函数没有返回值时,默认返回undefined。
- 创建一个空对象,并且this变量引用该对象,同时还继承该对象的原型;
- 属性和方法被加入到this引用的对象中;
- 新创建的对象由this所引用,并且最后隐式返回this。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
JSON(JavaScript Object Notation),是一种数据格式,其语法来说,有三种类型:
1. 简单值:与JavaScript语法相同,可表示字符串,数值,布尔型和null(唯独除了undefined),如: 5,"Hello World"(字符串必须使用双引号);
2. 对象:一组无序的键值对,每个建值对中的值可以是简单值,也可以是对象或数组;
3. 数组:有序的值的列表,可以通过数值索引来访问其中的值,数组的值也可以是任意类型——简单值,对象,数组。
定义是:
apply([thisObj[,argArray]]): 应用某一个对象的一个方法,用另一个对象替换当前对象;
call([thisObj[,arg1[, arg2[, [,.argN]]]]]): 调用一个对象的一个方法,以另一个对象替换当前对象。
个人感觉最大的区别就在于,传入参数列表的形式不同,一个是以数组的形式,一个是直接的参数列表。
call和apply多用来改变函数的作用域(上下文),即将this指针指向方法的第一个参数。
var name = "tsingwong";
function ftn(name){
console.log(name);
console.log(this.name);
console.log(this);
}
ftn("101");
var obj = {
name:"wq"
};
ftn.call(obj,"102");
# 第一次输出结果为101、tsingwong、window对象
# 第二次输出结果为102、wq、obj对象,因为call()方法将this指向了obj对象。
伯乐网讲解
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;
}
总体来说分为五大类:
1. 100-199 【信息性状态码】:用于指定客户端应相应的某些动作;
2. 200-299 【成功状态码】:用于表示请求成功;
3. 300-399 【重定向状态码】:用于已经移动的文件并且场被包含在定位头信息中指定新的地址信息;
4. 400-499 【客户端错误状态码】:用于指出客户端的错误;
5. 500-599 【服务器错误状态码】:用于指出服务器的错误。
- 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】服务器暂时无法处理请求(可能是过载或者维护)
优化方向 优化手段 求数量 合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域 请求带宽 开启GZip,精简JavaScript,移除重复脚本,图像优化 缓存利用 使用CDN,使用外部JavaScript和CSS,添加Expires头,减少DNS查找,配置ETag,使AjaX可缓存 页面结构 将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出 代码校验 避免CSS表达式,避免重定向
雅虎前端优化14条:
1. 减少 HTTP 请求次数:使用CSS Sprites组合多个图片到一张图片之后使用background-position来取图,js、css的源码压缩等;
2. 使用 CDN (Content Delivery Network,内容分发网络):分布静态内容,大大减少响应时间;
3. 增加 Expires Header:设置指定文件的缓存时间;
4. 压缩压面元素:使用Gzip在服务器端压缩后再传输;
5. 将 CSS 样式表放在头部:样式表放在head中;
6. 将 JS 脚本放在底部:放在body的闭合标签之前;
7. 避免使用 CSS 表达式:CSS 表达式执行次数超乎想象,会严重影响性能;
8. 将 JS 和 CSS 放到外部文件中:外部文件可以被浏览器缓存,所以会加快页面显示速度;
9. 减少 DNS 查询:DNS用于映射主机名和IP地址,一个页面所包含的域名数尽量控制在2-4个;
10. 压缩 JS 代码:压缩代码可以降低下载时间;
11. 避免重定向:每一次重定向就意味着多一次web请求,重要的是更降低了用户体验;
12. 删除重复的脚本文件:重复的JS文件会建立不必要的HTTP请求和额外的JS执行,影响性能;
13. 配置 ETags (实体标签):ETags是给浏览器缓存用的,用于确定浏览器缓存中元素是否与Web Server中的元素匹配。
14. 缓存 Ajax :Ajax缓存与HTTP缓存效果相同。
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
1. 当页面中元素都移除或替换时,若元素绑定的事件仍未被移除,在IE中会有不恰当处理,故此时应该先手动移除事件,否则会产生内存泄露;
2. 闭包可以维持函数内局部变量,使其得不到释放。
3. 自动类型转换,在IE中会导致内存泄露,所以所有值类型做计算之前,应该先显式转换一下;
进程,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,是计算机系统资源的基本单位
线程,是进程的一部分,是CPU调度的基本单位。
一个程序至少有一个进程,一个进程至少有一个线程。
- png24位的图片在IE6浏览器下出现背景,解决方法做成PNG8;
- 浏览器默认的margin和padding不同,解决方法,加一个全局的*{margin:0;padding:0;}来统一(建议不要这样做,效率很低,一般做法是只将部分样式重置即可);
- IE6双边距BUG:块级元素有float,有横向的margin情况下,IE6显示的margin是设置的两倍。解决方法:在float标签样式控制中加入display:inline;,作用是将其转化为行内属性。
- hack css中区分IE8/7/6
#tip{
background:blue;/*Firefox背景变蓝色 所有浏览器都支持*/
background:red\9;/*IE8背景变红色 IE6、7、8、9支持覆盖上面样式*/
*background:black;/*IE7背景变黑色 IE6、7支持又一次覆盖上面样式*/
_background:orange;/*IE6背景变橘色 紧IE6支持又一次覆盖上面样式*/
}
给不想要提示的form表单或者input输入框添加一个autocomplete属性设置为off即可。
调用 localstorge、cookies 等本地存储方式。
Adobe Flash Socket 、 ActiveX HTMLFile (IE) 、 基于 multipart 编码发送 XHR 、 基于长轮询的 XHR。(看了不少没怎么看懂websocket的原理,感觉是比comet节约资源)
两种盒子模型,IE盒子模型、标准 W3C 盒子模型。
盒子模型都由:内容(content)、填充(padding)、边框(border)、边距(margin)组成。
其中IE的content部分海包括了border和padding。
- id 选择器(#myid)
- 类选择器(.myclassname)
- 标签选择器(div,h1,p)
- 相邻选择器(h1 + p)
- 子选择器(ul > li)
- 后代选择器(li a)
- 通配符选择器(*)
- 属性选择器(a[rel="external"])
- 伪类选择器(a:hover, li:nth-child)
可以继承的样式:
1. font-size
2. font-family
3. color
4. text-indent
不可以继承的样式:
1. border
2. padding
3. margin
4. width
5. height
优先级算法:
1. 优先级就近原则,同权重时样式定义最近者为准;
2. 载入样式以最后载入的定位为准;
3. !important > id > class > tag(!important比内联优先级高,但内联比id要高)。
注:标签权重为1,class权重为10,id权重为100
CSS3新增的伪类距离:
1. p:first-of-type 选择属于其父元素的首个 <p>
元素。(等用于:nth-of-type(1))
2. p:last-of-type 选择属于其父元素的最后 <p>
元素。(等同于:nth-last-of-type(1))
3. p:only-of-type 选择属于其父元素唯一的 <p>
元素。
4. p:only-child 选择属于其父元素的唯一子元素的每个 <p>
元素。
5. p:nth-child(2) 选择属于其父元素的第二个子元素的每个 <p>
元素。
6. :enabled :disabled 控制表单控件的禁用状态。
7. :checked 单选框或复选框被选中。
div的居中,只需要添加margin: 0 auto属性即可。
浮动元素垂直居中:
div {
width: 200px;
height: 100px;
margin: -50px 0 0 -100px; #必须加否则会默认左上角在中心点,向上偏移1/2宽度,向左偏移1/2长度
position: absolute; # 此处一定要是用绝对定位
background-color: #eee;
left:50%;
top: 50%;
}
垂直居中2:
.absoulte-center {
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
- inline: 默认值,内联元素,元素前后没有换行符,即行内元素;
- block: 块级元素,元素前后会带有换行符;
- inline-block:行内块元素,像行内元素一样显示,但其内容像块级元素一样显示;
- none: 此元素不会显示(区别于visibility:hidden,前者是彻底消失,后者是隐藏,但元素所占空间还在)
- static: 默认值,没有定位,元素出现在正常的流中(自动忽略top,bottom,left,right或者z-index声明);
- absolute:绝对定位,相对于static定位之外的第一个父元素定位,元素位置可以使用top,bottom,left,right或z-index声明;
- fixed:绝对定位,相对于浏览器窗口,同样元素位置也支持使用top,bottom,left,right或z-index声明;(老版IE浏览器不支持)
- relative:相对定位元素,相对于其正常位置进行定位,即"left:20px"就是向元素的左方向添加20像素;
- inherit:从父元素继承position属性的值。
BFC(Block Formatting Context),直译为“块级格式化上下文”,简单来说,它提供了一个独立布局的环境,每一个BFC都遵守同一套布局规则,如在同一个BFC内,盒子会一个挨着一个排列,相邻的盒子间距由margin决定,且垂直方向上的margin会重叠。注:相邻 BFC 上下 margin 不会重叠。
其决定了元素如何对其内容进行定义,以及与其他元素的关系和相互作用。
IE 6、7 下没有 BFC 概念,但有类似概念: layout。故 IE 6、7 下很多 bug 可以通过设置元素 has layout 来解决,如 “height:1%”、 “zoom:1”、“display:inline-block”、“overflow:hidden” 等。
触发 BFC:
float
的值为非 none
overflow
的值为 atuo
、scroll
或 hidden
display
的值为 table-sell
、table-caption
或 inline-block
position
的值为 非 relative
和非 staitc
CSS预处理器,定义了一种新的语言,其基本思想是,使用一种专门的变成语言,为CSS增加一些编程特性,将CSS作为目标生成文件,然后开发者只要使用这种语言进行编程工作即可。
现在比较流行的有Sass、LESS和Stylus。(bootstrap是由Less构建的,官方给提供了一套Sass移植版)
多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔位1/60*1000ms = 16.7ms
移除空格、使用margin负值、父容器使用font-size:0、letter-spacing、word-spacing等。链接地址
- 默认使用四个空格缩进;
- 函数名后添加空格;
- 参数与括号之间不要添加空格;
- 对象字面量中冒号后加空格;
- 条件语句中判断句前后都要加空格;
- 即使在不必使用花括号的时候,也应该使用花括号。(如只有一条执行语句的for循环);
- 所有变量必须在使用之前进行声明,建议都使用var定义,尽量避免全局变量;
- var定义变量放在函数的首部,最好将每个变量声明语句单独放在一行,并且加上注释;
- 变量命名由26个大小写英文字母、10个数字、和
_
,美元符号$
组成,并且只能用字母,_
或$
打头。大多数变量和方法名应该是以小写字符开头。构造函数名应该使用大写字符定义。全局变量应该全部大写;- 使用===和!==来比较,例如null和undefined在==下判断他俩是相等的;
- 使用对象字面量来代替
new Array
这种形式;- for循环中的变量,应该是用var关键字明确限定作用域,从而避免作用域污染;
最后建议多看看阮一峰老师的JavaScript编程风格
// 跨浏览器通用事件处理程序
var eventUtil = {
// 页面加载完成后
readyEvent: function(fn) {
if (fn === null) {
fn = document;
}
var oldonload = window.onload;
if (typeof window.onload !== "function") {
window.onload = fn;
} else {
window.onload = function() {
oldonload();
fn();
}
};
},
// 能力判断:dom2||IE||dom0 来绑定事件
// 参数: 操作元素,事件名称(去掉on),事件处理程序
addHandler: function(element, type, handler) {
if (element.addEventListener) {
// 事件类型,需要执行的函数,是否捕捉(true捕获,false冒泡)
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
// 移除事件
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
// 获取event对象
getEvent: function(event) {
return event?event:window.event;
},
// 获取事件目标
getTarget: function(event) {
return event.target||event.srcElement;
},
// 阻止事件默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 立刻停止事件在DOM的传播
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
}
Node.js 是一个JavaScript运行环境(runtime)。实际上是对Google V8引擎的封装。简单来说
Node.js
就是运行在服务端的JavaScript。
主要适用于高并发、聊天、实时消息推送上(即长链接推送),从底层到库是完全异步的。
JavaScript语言并不支持“类”,要想实现类需要用到以下三个:
constructor:构造函数,定义属性和方法,但是这些属性和方法只能通过构造函数来访问,不能通过实例访问。
prototype:原型,定义实例方法,被所有实例共享。
instance object:定义实例属性,每个实例都有属于自己的属性。定义类有以下三个步骤:
1. 定义构造函数,构造函数内部定义
一、 构造函数法
经典方法,它用构造函数模拟“类”,在其内部用this关键字指代实例对象,生成实例时,使用new关键字,类的属性和方法可以使用
function Cat() {
this.name = "我是猫";
}
Cat.prototype.makeSound = function() {
alert("喵喵喵");
}
var cat1 = new Cat();
alert(cat1.name); // 我是猫
cat1.makeSound(); // 喵喵喵
该方法使用较为复杂,需要使用this
和prototype
,编写和阅读都很费劲。
使用new
构造函数生成实例对象有一个缺点,就是无法共享属性和方法。可以使用prototype属性来弥补这个缺点。
function Dog(name) {
this.name = name;
}
Dog.prototype = { species: "犬科"};
var dog1 = new Dog("金毛");
var dog2 = new Dog("泰迪");
alert(dog1.species); //犬科
alert(dog2.species); //犬科
Dog.prototype.species = "猫科";
alert(dog1.species); //猫科
alert(dog2.species); //猫科
二、 Object.create()方法
为方便生成对象,ES5中提出了一个新方法Object.create()
。
使用这个方法,“类”就是一个对象,不是函数。直接使用Object.create()
生成实例,不需要使用new
。
var Cat = {
name: "我是猫",
makeSound: function() {
alert("喵喵喵");
}
}
var cat1 = Object.create(Cat);
alert(cat1.name); // 我是猫
cat1.makeSound(); // 喵喵喵
目前各大浏览器已基本兼容此方法,如果遇到老式浏览器,可以使用下面代码部署:
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
该方法其实只做了一件事,就是把子对象的prototype属性,指向父对象,从而使得子对象与父对象连接在一起。
该方法比“构造函数法”简单,但是不能实现私有属性和方法,实例对象之间也不能共享数据,对“类”的模拟不够全面。
三、极简主义法
该方法不使用this
和prototype
,代码部署起来非常简单,这大概是“极简”。
首先,它也是一个对象模拟“类”。在这个类里,定义一个构造函数createNew(),定义一个实例对象,把这个实例对象作为返回值。使用时,调用createNew()方法,就得到该实例对象。
var Cat = {
createNew: function() {
var cat = {};
cat.name = "我是猫";
cat.makeSound = function() {
alert("喵喵喵");
};
return cat;
}
};
var cat1 = Cat.createNew();
alert(cat1.name); // 我是猫
cat1.makeSound(); // 喵喵喵
该方法的好处是,容易理解,结构清晰优雅,符合传统的“面向对象编程”的构造,因此可以方便地使用继承、私有属性和私有方法、数据共享等。
【继承】:让一个类继承另一个类,实现起来很方便。只需在子类的createNew()方法中,调用父类的createNew()方法即可。
var Animal = {
createNew: function() {
var animal = {};
animal.sleep = function() {
alert("我在睡觉");
};
return animal;
}
};
var Cat = {
createNew: function() {
var cat = Animal.createNew();
cat.name = "我是猫";
cat.makeSound = function() {
alert("喵喵喵");
};
return cat;
}
};
var cat1 = Cat.createNew();
cat1.sleep(); // 我在睡觉
【私有属性和私有方法】:在createNew()方法中,只要不是定义在cat对象上的方法和属性,都是私有的。
var Cat = {
createNew: function() {
var cat = {};
var sound = "喵喵喵"; // 私有属性
cat.makeSound = function() {
alert(sound);
};
return cat;
}
};
var cat1 = Cat.createNew();
cat1.makeSound(); // 喵喵喵
alert(cat1.sound); // undefined
【数据共享】:有时我们需要所有实例对象,能够读写同一项内部数据。这个时候,只要把这个内部数据,封装在类对象的里面、createNew()方法的外面即可。
var Cat = {
sound: "喵喵喵",
createNew: function() {
var cat = {};
cat.makeSound = function() {
alert(Cat.sound);
};
cat.changeSound = function(x) {
Cat.sound = x;
};
return cat;
}
};
var cat1 = Cat.createNew();
var cat2 = Cat.createNew();
cat1.makeSound(); // 喵喵喵
cat2.changeSound("汪汪汪");
cat1.makeSound(); // 汪汪汪
主要有两种继承方式:原型链继承(对象间的继承)、类式继承(构造函数间的继承)
原型链继承的缺点是字面量重写会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
类式继承缺点是虽然解决上面的两个问题,但是没有原型,则复用无从谈起。
所以这时候引入了原型链继承+类式继承,大体思路是使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。这样保证了在原型上定义方法实现了函数复用,又保证了每个实例都有属于自己的属性。
最简单的原型链继承,将子对象构造函数的prototype
属性指向父对象的一个实例
function Parent(){
this.name = 'mike';
}
function Child(){
this.age = 12;
}
Child.prototype = new Parent();//Child继承Parent,通过原型,形成链条
var test = new Child();
alert(test.age);
alert(test.name);//得到被继承的属性
//继续原型链继承
function Brother(){ //brother构造
this.weight = 60;
}
Brother.prototype = new Child();//继续原型链继承
var brother = new Brother();
alert(brother.name);//继承了Parent和Child,弹出mike
alert(brother.age);//弹出12
# 此时Child的prototype属性被重写了,指向一个新对象,但该新对象的constructor属性却没有正确指向child,所以需要手动将Child的原型对象的constructor属性重新指向Child
Child.prototype.constructor = Child;
Brother.prototype.constructor = Brother;
类式继承
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
function Child(age){
Parent.call(this,age);
}
var test = new Child(21);
alert(test.age);//21
alert(test.name);//mike,jack,smith
test.name.push('bill');
alert(test.name);//mike,jack,smith,bill
组合继承
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
Parent.prototype.run = function () {
return this.name + ' are both' + this.age;
};
function Child(age){
Parent.call(this,age);//对象冒充,给超类型传参
}
Child.prototype = new Parent();//原型链继承
var test = new Child(21);//写new Parent(21)也行
alert(test.run());//mike,jack,smith are both21
事件,就是文档或浏览器窗口中发生一些特定的交互瞬间。
事件流,从页面中接收事件的顺序。IE与Netscape团队分别提出完全相反的事件流概念。
IE的事件流是事件冒泡流,即事件开始时由最具体的元素(文档嵌套层次最深的节点)接收,然后逐级向上传播到较为不具体的节点直到文档对象(document对象或window对象),简单说来是自下而上,自内向外。所有现在浏览器都支持事件冒泡。
Netscape的事件流是事件捕获流,即事件开始时从不太具体的元素接收,然后逐级向下传播到较为具体的节点,直到最具体节点接收事件。用意在于事件到达预定目标之前捕获它。IE9、Safari、Chrome、Opera、Firefox不但支持冒泡还是支持捕获。
如果要阻止冒泡和捕获的话,在DOM中可以使用event.stopPropagation();
,在IE中可以使用event.cancelBubble = true;
(注:IE中只支持事件冒泡)
函数可以记住且访问所在的词法作用域就产生了闭包。闭包,函数在自己定义的词法作用域之外执行,仍然保持对该作用域的引用。
常见方法是,在一个函数内部创建另一个函数,通过另一个函数来访问这个函数的局部变量。
由于在JavaScript语言中,只有函数内部的子函数才能读取函数的局部变量,所以将闭包简单理解位定义在函数内部的函数,本质上来说,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包应用在许多的地方,最大作用有三点,一是读取函数内部的变量,二是让那些变量值始终保持在内存中,三是设计私有的方法和变量。
闭包有三个特性:一是函数嵌套函数,二是函数内部可以引用外部的参数和变量,三是参数和变量不会被垃圾回收机制回收。
function f1() {
var n = 999;
nAdd = function() {
n += 1;
};
function f2() {
alert(n);
}
return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000
result = null; // 解除引用,等待垃圾回收
闭包的好处:
1. 希望一个变量长期驻扎在内存中;
2. 避免全局变量的污染;
3. 私有成员的存在。
闭包的缺点:
1. 闭包会使得函数中的变量被保存在内存中,内存消耗较大,故不能滥用闭包,否则会导致页面的性能问题,在IE中可能会导致内存泄露,解决方法是在退出函数之前,将不再使用的局部变量全部删除(即赋值为空);
2. 闭包在父函数外部,改变父函数内部变量的值。所以父函数作为对象(object)使用,把闭包当做其公用方法(Public Method),把内部变量当做其私有属性(private value),这时一定要小心,不要随便改动父函数内部变量的值。
阮一峰老师的学习Javascript闭包
另一篇不错的闭包讲解
typeof 返回一个表达式的数据结构的 字符串,返回结构为js基本的数据类型,如number,boolean,string,object,undefined,function等。语法为
typeof(data)
或typeof data
。(typeof会把Array还有用户自定义函数返回object)
instanceof 判断一个对象是否为某一数据类型,或变量是否为对象的实例,返回boolean类型,语法为o instanceof a
constructor 返回 字符串 ,返回对创建此对象的数组函数的引用。(一般很少使用。)
<script src="/example/html5/demo_defer.js" defer="defer"></script>
,脚本在页面完成解析时执行(相当于将script标签放在页面body标签的底部);<script src="/example/html5/demo_defer.js" async="async"></script>
, 脚本相对页面的其他部分异步地执行(当页面继续进行解析时,脚本将被执行);如果 async 属性为 true,则脚本会相对于文档的其余部分异步执行,这样脚本会可以在页面继续解析的过程中来执行。
如果 async 属性为 false,而 defer 属性为 true,则脚本会在页面完成解析时得到执行。
如果 async 和 defer 属性均为 false,那么脚本会立即执行,页面会在脚本执行完毕继续解析。
跨域安全策略:默认情况下,XHR对象(XMLHttpRequest对象)只能访问与包含它的页面位于同一个域的资源。(只要
协议、域名、端口
如有任何一个不同,即当做不同的域)同源策略:同一ip、端口、协议视为同一个域,一个域的脚本仅仅具有本域内的权限,可以理解为本域的脚本只能读写本域内的资源,而无法访问其他域的资源。浏览器安全的基本。
跨域并非浏览器限制了发起跨站请求的这种能力,恰恰相反,我们可以发出请求,服务端也可以接收到请求并正常返回数据,只不过在返回之后浏览器会阻止非同源数据
(response),从而在控制台打出一系列报错信息。
CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C的工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS背后基本思想是,使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或相应成功或失败。
简单来说CORS,就是在Ajax请求中添加Origin
字段,服务器提交请求的头部header中设置header{"Access-Contorol-Allow_Origin: *"}
,任意一个请求过来之后服务器端都可以进行处理和相应。一般为了安全起见,将*改为请求来源的地址。链接到阮一峰老师的CORS解析
图像Ping,是与服务器进行简单、单向的跨域通信的一种方式。请求的数据是通过查询字符串形式发送的,而相应可以是任意内容,但通常位像素图或204响应。浏览器得不到任何数据,但可以通过load和error事件,来获取收到响应的时间。多用于跟踪用户点击页面或动态广告曝光次数。主要缺点:只能发送GET请求;无法访问服务器的响应文本,所以图像Ping只能用于浏览器与服务器间的单向通信。
callback({"name": "TsingWong"});
优点是能直接访问响应文本支持在浏览器服务器之间的双向通信。缺点是:只支持GET请求,并不支持POST请求等其他HTTP请求。 script
标签,通过script
标签引入一个js文件,这个文件载入成功后执行在url参数中指定的函数,并且将我们需要的json数据作为参数传入。window
对象有一个name
属性,该属性有个特征,即在一个窗口(window)的生命周期内,窗口载入的所有页面都是共享一个window.name
的,每个页面对window.name
都有读写的权限,window.name
是持久存在一个窗口载入过程的所有页面中。document.domain
设为同一个主域,前提条件是,这两个域名必须属于同一个基础域名,而且所用的协议,端口都一致,否则无法利用它跨域。如flash、在服务器设置代理业面等方法,不做过多的解释,详情见js中几种实用的跨域方法原理详解
模块就是实现特定功能的一组方法,只要吧不同的函数(以及记录状态的变量)简单地放在一起就就算是一个模块。有了模块,便于我们更方便地使用别人的代码。模块开发需要遵循一定的规范。
目前比较通用的js模块规范有三种:AMD规范
、CMD规范
、CommonJS规范
AMD(Asynchronous Module Definition),中文直译过来是“异步模块定义”的意思,它是浏览器端模块化开发的规范。采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这一模块的语句,都定义在一个回调函数中,等加载完成后,回调函数才会运行。
AMD规范只定义了一个函数define
,它是全局变量。
define(id, dependecies, factory);
# id:定义模块的名字;
# dependencies:当前模块依赖的,已被模块定义的模块标识的数组字面量;
# factory:模块初始化要执行的函数或对象。如果是函数,应该只被执行一次。如果是对象,应位模块的输出值。
目前,实现AMD的库有:RequireJS、curl、Dojo、Nodules等。
CMD(Common Module Definition),与AMD相同也是浏览器端模块化开发的规范。
# AMD 是 RequireJS 在推广过程中将模块定义的规范化产出;
# CMD 是 SeaJs 在推广过程中对模块定义的规范化产出;
# 对于依赖的模块,AMD是提前执行,CMD是延迟执行
# AMD:提前执行(异步加载:依赖先执行)+ 延迟执行
# CMD:延迟执行(运行到需加载,根据顺序执行)
# AMD 推崇依赖前置
define(['./a','./b'],function(a,b){ # 依赖必须一开始就写好
a.doSomething();
b.doSomething();
})
# CMD 推崇依赖就近
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
var b = require('./b'); # 依赖可以就近书写
b.doSomething();
})
# AMD 的API默认是一个当多个用;
# CMD 的API严格区分,推崇职责单一。
CommonJS 是服务器端模块的规范,Node.js采用了这个规范。一个单独的文件就是一个模块,,每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非是定义为global对象的属性。
TCP/IP
连接,。解析是渲染引擎中非常重要的过程,解析文档即将其转化位表达文档结构的节点树,成为解析树或语法树。CSS解析成一颗CSS规则树。DOM树与CSS规则树共同生成一个规则(Render)树。
总之感觉这里还有很多很多东西,由于个人能力有限表达不出来。先写这些,等之后提高后再过来填坑。
浏览器加载显示HTML页面的顺序:
1. IE下载的顺序是从上到下,渲染的顺序也是自上而下的,下载和渲染是同时进行的;
2. 在渲染到页面的某一部分时,其上面所有部分都已经下载完成(这里强调并不是所有相关联的元素都下载完);
3. 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式表的下载过程会启用单独连接进行下载;
4. 并且在下载后进行解析,解析过程中,停止页面所有往下元素的下载;
5. 样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含之前已经渲染的)重新进行渲染;
6. JS、CSS中如果存在重定义,后定义函数会覆盖前定义函数。
拓展阅读内容:底层的从输入URL到浏览器接受的过程
不区分大小,但是要保证HTML结构与CSS样式中一致,建议都使用小写。
没有可以,margin-top/bottom 作用是让元素远离自身顶部和底部的元素。在向一个行内非替换元素应用外编剧,它对行高没有任何影响。
有效,内联元素设置padding-top/bottom的值,如果有背景色,行内元素的背景会向上向下延伸。
<p>
元素设置字体大小:10rem,用户调节浏览器窗口大小,文本是否相应变化?REM,是CSS3中新增的单位,官网上如是说——“font size of the root element”。即rem是相对于根元素
<html>
,所以浏览器窗口大小变化,文本并不能做到随之改变元素字号。当改变<html>
根元素时,字体随之大小改变。
与之相应的是 EM,相对于当前行内文本尺寸。
对于选择器中给定的各个ID属性值,加“0,1,0,0”。
对于选择器中给定的各个类属性值,属性选择或伪类,加"0,0,1,0"。
对于选择器中给定的各个元素为伪元素,加“0,0,0,1”。
结合符和通配符“*”以及":not()"没有任何的加分权。
对于行内样式,加为“1,0,0,0”
对于"!important"加分高于上面的一切,将变成“1,0,0,0,0”
HTML中的img,只要页面加载,图片就会加载。但在CSS中的背景图片如果没有被引用,就不会被加载。
window.global
,当离开局部变量的作用域后,又重回到全局变量的作用域。
function test() {
alert(a); // undefined
var a = 4;
alert(a); // 4
}
test();
alert(a); // 报错
上述代码相当于:
function test() {
// 第5行的变量声明提到其作用域顶部,但当前并未赋值,故其值为undefined
var a;
alert(a);
// 之前第5行除声明外的部分仍在原位置执行
a = 4;
alert(a);
}
test();
alert(a); // 由于没有全局变量的a所有报错
(function test() {
alert(window.a); // undefined
a = 4;
alert(a); // 4
})();
alert(a); // 4
上述代码相当于:
var a; // 第3行全局变量声明提升
(function test() {
alert(window.a);
a = 4;
alert(a);
})();
# 立即执行函数
(function() {
}());
# 匿名包裹器
(function() {
})();
函数声明会覆盖变量声明
但如果变量声明的同时初始化变量,情况有所不同。因为函数声明与变量声明都提升后,函数赋值还会保留原位置,所以会再次被覆盖为变量。
function foo(a) {
alert(arguments.length);
}
function foo2(a) {
alert(foo2.length);
}
foo(1, 2, 3); // 3
foo2(4, 5, 6); // 1
arguments取得是实参的个数,而foo2.length取得是形参个数。
为准确无误地把数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包发送出去后,TCP不会对传送后的情况置之不理,一定会向对方确认是否成功送达。握手过程中使用TCP的标志:
SYN
和ACK
。
三次握手在网页访问中发生在浏览器获取到主机IP地址之后,建立连接的时候。
ACK
是TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须位1。
SYN
是在连接建立时用来同步序号。当SYN=1且ACK=0时,表明这是一个连接请求报文。若对方同意建立连接,则响应报文中SYN=1且ACK=1。因此,SYN=1表示这是一个连接请求或连接接受报文。
FIN
表示完成、终结的意思,用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
三次握手过程:
SYN/ACK
标志的数据包以示传达确认信息。ACK
标志的数据包,代表“握手”结束。若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。发送确认是为了防止失效的连接请求报文突然由传送到B,因而产生错误。四次挥手过程:
FIN
,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在FIN
包之前发送的数据,如果没有收到回应的ACK
确认报文,主动关闭方仍然会重发这些数据),但是,此时主动关闭方还可以接受数据;FIN
包后,发送一个ACK
给对方,确认序号位收到序号+1(与SYN
相同,一个FIN
占用一个序号);FIN
,用来关闭被动关闭方到主动关闭方的数据传送,即告诉主动关闭方,我的数据也发送完了,不会再给你发数据了;FIN
后,发送一个ACK
给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。TCP/UDO
TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,即在正式发送数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“握手”才能建立。
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接把数据包发送过去。UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。
Ajax是一种与服务器交换数据无需刷新页面的技术,Asynchronous Javascript And XML(异步JavaScript和XML)
XMLHttpRequest
对象,也就是创建一个异步调用对象;
function createXHR() {
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
retrun xmlhttp;
}
var xhr = createXHR();
xhr.onreadystatechange = function () {
/**
* XMLHttpRequest的readystate有五个状态
* 0 还没有调用open方法
* 1 已调用open方法,尚未调用send方法
* 2 已调用send,但尚未接收到响应
* 3 已接收到部分响应数据,可以用来做Comet
* 4 已经接收到到全部数据,而且可以在客户端使用
*/
if (xhr.readyState == 4) {
//状态码在200到300表示请求成功,状态码304表示资源没有被修改,可以直接使用缓存中的版本
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.statusText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
//设置请求头,open()方法之后send()方法之前。
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//序列化表单
var form = document.getElementById('test-form');
xhr.send(null);
# jQuery代码
$(function () {
$("input").click(function () {
$.ajax({
type : "POST",
url: 'test.php',
data:{
url: 'baidu.com'
},
timeout: 10000,
success : function(response,status,xhr){
$('#box').html(response);
}
})
})
});
优点:
1. 无刷新更新数据
2. 异步与服务器通信
3. 前端和后端负载平衡
4. 基于标准被广泛支持
5. 界面与应用分离开
缺点:
1. 破坏了浏览器的机制,即Back和History功能
2. AJAX存在一些安全问题
3. 对搜索引擎支持较弱
4. 不能很好的兼容移动设备
渐进增强:首先针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级:首先构建完整的功能,然后在针对低版本进行兼容。
HTTP协议通常承载于TCP协议之上,在HTTP与TCP之间添加一个安全协议层(
SSL
或TSL
),这就成为了我们说的HTTPS。
默认HTTP端口为80,HTTPS的默认端口号为443。
- 尽量使用
CSS3
动画,开启硬件加速;- 适当使用
touch
事件代替click
事件;- 避免使用
CSS3
渐变阴影效果;- 可以用
transform: tanslateZ(0)
来开启硬件加速;- 不滥用float。float在渲染时计算量比较大,尽量减少使用;
- 不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用;
- 合理使用requestAnimationFrame动画代替setTimeout;
- CSS中的属性(transitions、3D transitions、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过度使用会引发手机耗电增加,温度过热等;
栈的插入和删除都是在一段进行的,而队列的操作是两端进行的;
队列先进先出,栈先进后出;
栈只允许在表尾一端插入和删除,队列只允许在表尾插入,在表头删除。
工厂模式:
好处是可以消除对象的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。
工厂模式解决了重复实例化的问题,但存在一个问题,即识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。
function createObject(name, age, profession) {
// 集中实例化的函数
var obj = new Object();
obj.name = name;
obj.age = age;
obj.profession = profession;
obj.move = function() {
return this.name + ' at '+this.age+' engaged in '+this.profession;
};
return obj;
}
var test1 = createObject('tsingwong', '23', 'programmer'); // 实例一
var test2 = createObject('mike',25,'engineer'); // 实例二
构造函数模式:
使用构造函数方法,即解决了重复实例化的问题,又能解决了对象识别的问题。
该方法与工厂模式的不同之处在于:
1. 构造函数的方法没有显示的创建对象;
2. 直接将属性和方法赋值给this对象;
3. 没有return语句。
function Man(name, age, profession) {
this.name = name;
this.age = age;
this.profession = profession;
# 使用该方法继承较为麻烦,而且每次创建新实例都重定义方法move()
/*this.move = function() {
return this.name + ' at '+this.age+' engaged in '+this.profession;
};*/
}
# 这里使用Object.prototype.方法名,而不是Object.prototype,是为了避免重写定义好的原型对象
Man.prototype.move = function() {
return this.name + ' at '+this.age+' engaged in '+this.profession;
}
var test1 = new Man('tsingwong', '23', 'programmer'); // 实例一
var test2 = new Man('mike',25,'engineer'); // 实例二
优点是:
1. 通过良好的编程,控制保存在cookie中的session对象大小;
2. 通过加密和安全传输技术(SSL),减少cookie被破解的可能性;
3. 只在cookie中存放不敏感数据,即使被盗也不会有重大损失;
4. 控制cookie的生命周期,使之不会永远有效。故拦截者可能获取的是一个过期的cookie。
缺点是:
1. Cookie数量和长度有限制。IE6-20个,IF7+50个,Firefox50个,chrome和Safri没有数量限制。每个cookie长度最大约为4k,否则会被截断;
2. 安全性问题。如果cookie被人拦截,可以获取所有的session信息。即使加密也没用,拦截者不需要知道cookie的意义,只需原样转发cookie就可以达到目的。
3. 有些状态不可能保存在客户端。例如,为了防止重复提交表单,在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
FOUC(Flash Of Unstyled Content,文档样式闪烁),一般指的是IE在加载页面时,出现短暂的CSS样式失效。
问题原因大致有三点
1. 使用import方式导入样式表,如<style type="text/css" media="all">@import "../fouc.css";</style>
2. 将样式表放在页面底部;
3. 有几个样式表,放在HTML结构的不同位置。
基本原理是:当样式表晚于结构性html加载,当加载到此样式表时,页面将停止之前的渲染。此样式表被下载和解析后,将重新渲染页面,也就是出现了短暂的花屏现象。
其实引用CSS文件使用@import
经常是造成这个现象的罪魁祸首,IE会先加载整个HTML文档的DOM,然后再去导入外部的CSS文件,因此在DOM加载完成到CSS导入完成这段时间页面是没有样式的。
解决方法是在<head>
之间加入一个<link>
或<script>
元素即可。
GET:用于信息获取,使用URL传递参数,对所发送信息的数量也是由限制的,一般在2000个字符;
POST:一般用于修改服务器上的资源,对发送的信息没有限制。
GET方式使用Request.QueryString
来取得变量的值,而POST方式通过Request.Form
来获取变量的值,即GET是通过地址栏来传值的,POST是通过表单来传值的。
在以下情况下只能使用POST请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量的数据(POST没有数据量限制)
- 发送包含未知字符的用户输入时,POST比GET更稳定也更可靠。
网站重构:在不改变外部行为的前提下,简化机构、添加可读性,而在网站前端保持一致的行为。即在不改变UI的情况下,对网站进行优化,在拓展的同时保持一直的UI。
对传统老网站的重构通常是:
对移动平台的重构:
深层次的网站重构考虑以下方面;
速度优化也是重构的一个重点:
git pull:相当于从远程获取最新版本,并merge(融入)本地。
git fetch:相当于从远程获取最新版本到本地,但不会自动merge。
事件代理,又称事件委托。是JavaScript中绑定事件的常用技巧。“事件代理”即把原来需要绑定的事件委托给父元素,让父元素担当事件监听的职务。其原理是DOM元素的事件冒泡。由于DOM操作是十分消耗资源的,所以重复的事件绑定非常占用资源。事件代理的核心思想就是,通过尽量少的绑定,去监听尽量多的事件。
通俗的讲,事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。即利用冒泡的原理,把事件加到父级上,触发执行效果。
当子元素的事件冒泡到父元素时,你可以检查事件对象的target属性,捕获真正被点击的节点元素的引用。
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
function eventProxy() {
var aUl = document.getElementsByTagName("ul")[0];
var aLi = aUl.getElementsByTagName("li");
// 这里事件绑定是使用的dom0级绑定,应该区分开dom2级|IE|dom0级
aUl.onmouseover = function(event) {
var event = event || window.event;
var target = event.target || event.srcElement;
if (target.nodeName.toLowerCase() == "li") {
target.style.background = "red";
}
}
aUl.onmouseout = function(event) {
var event = event || window.event;
var target = event.target || event.srcElement;
if (target.nodeName.toLowerCase() == "li") {
target.style.background = "";
}
}
}
window.onload = eventProxy();
</script>
</body>
attribute翻译过来是“特性”,property翻译过来是“属性”。
attribut是一个特性节点,每个DOM元素都有对应的attribute属性按照名值对的形式存放存放这所有attribute节点。其类型为NameNodeMap。
<div class="box" id="box" gameid="123" ah="ha">hello</div>
上面div元素中的class、id,和自定义的gameid、ah这些特性都被存在attribute中。
[class="box", id="box", gameid="123", ah="ha"]
获取特性名称与值的方法有两种:
var elem = document.getElementById( 'box' );
// 使用类似数组的NameNodeMap
console.log( elem.attributes[0].name ); // class
console.log( elem.attributes[0].value ); // box
// getAttribute()方法
console.log( elem.getAttribute('gameid') ); // 880
设置与删除attribute节点
elem.setAttribute('testAttr', 'testVal');
console.log( elem.removeAttribute('gameid') ); // undefined
总结:attribute是会随着添加或删除attribute节点动态更新的。
property就是属性,如果把DOM元素看成一个普通的Object对象,那么property就是以名值对形式存放在Object的属性中,故增加和删除property与普通对象没有区别:
elem.testProp = "test";
console.log(elem.testProp); // test
delete elem.testProp;
之所以attribute与property经常混淆是因为对于id、class等HTML标签定义的属性的attribute节点还有一个对应的property属性。
console.log( elem.getAttribute('id') ); // box
console.log( elem.id ); // box
elem.id = 'hello';
console.log( elem.getAttribute('id') ); // hello
但对自定义的attribute节点,或自定义的property,两者就没有关系了
console.log( elem.getAttribute('gameid') ); // 880
console.log( elem.gameid ); // undefined
elem.areaid = '900';
console.log( elem.getAttribute('areaid') ) // null
对于IE6-7来说,并没有区分attribute和property:
// 下面为IE6下运行情况
console.log( elem.getAttribute('gameid') ); // 880
console.log( elem.gameid ); // 880
elem.areaid = '900';
console.log( elem.getAttribute('areaid') ) // 900
最后为了更好的区分attribute和property:大多数实际应用中,DOM操作都是使用property
。
只有以下两种情况使用attribute:
工业流程上一般分为五层,从上到下,越往上的层越靠近用户,越下面的层越靠近硬件。
思路:父元素和子元素同时左浮动,然后父元素相对左移50%,再然后子元素相对右移50%,或者子元素相对左移-50%。
<style media="screen">
.p {
position: relative;
left: 50%;
float: left;
}
.c {
position: relative;
float: left;
right: 50%;
}
</style>
<body>
<div class="p">
<h1 class="c">Test Float Center</h1>
</div>
</body>
思路:负边距+定位,使用绝对定位将content的顶点定位到body的中心,然后使用负margin(content宽高的一般),将content的中心店移到body的中点,以此实现水平垂直居中的效果。
<style media="screen">
.align-center {
position: absolute;
left: 50%;
top: 50%;
width: 400px;
height: 400px;
margin-top: -200px;
margin-left: -200px;
border: 1px solid #333;
}
</style>
<body>
<div class="align-center"></div>
</body>
方法一:自身浮动法。即左栏左浮动,右栏右浮动。
<style>
.left,
.right {
height: 300px;
width: 200px;
}
.right {
float: right;
background-color: red;
}
.left {
float: left;
background-color: #080808;
}
.middle {
height: 300px;
margin: 0 200px;
background-color: blue;
}
</style>
<body>
<div class="right"></div>
<div class="left"></div>
<!-- 这里需要注意的是middle必须是最后一个否则它后面的会另起一行 -->
<div class="middle"></div>
</body>
方法二:margin负值法
<style>
body {
margin: 0px;
padding: 0px;
}
.left,
.right {
height: 300px;
width: 200px;
float: left;
}
.right {
margin-left: -200px;
background-color: red;
}
.left {
margin-left: -100%;
background-color: #080808;
}
.middle {
height: 300px;
width: 100%;
float: left;
background-color: blue;
}
</style>
<body>
<!-- 这里需要注意的是middle必须是第一个 -->
<div class="middle"></div>
<div class="right"></div>
<div class="left"></div>
</body>
方法三:绝对定位法。即左右两栏采用绝对定位,分别固定在左右两侧,中间使用左右两margin撑开距离
<style>
body {
margin: 0px;
padding: 0px;
}
.left,
.right {
top: 0;
height: 300px;
width: 200px;
position: absolute;
}
.right {
right: 0;
background-color: red;
}
.left {
left: 0;
background-color: #080808;
}
.middle {
height: 300px;
margin: 0 200px;
background-color: blue;
}
</style>
<body>
<!-- 这种情况不强制要求middle放在某个地方 -->
<div class="middle"></div>
<div class="right"></div>
<div class="left"></div>
</body>
Array.prototype.unique = function() {
var n = []; // 创建一个临时数组
for (var i = 0; i< this.length; i++) { // 遍历当前数组
// 如果当前数组中第i个内容已经存入临时数组,那么跳过;
// 否则将当前项push到临时数组中
// indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
if (n.indexOf(this[i]) == -1) {
n.push(this[i]);
}
}
return n;
}
(1) 单例模式: 任何对象都是单例,无需特别处理
var obj = {name: "tsingwong", age: 24};
(2) 工厂模式:同种形式参数返回不同的实例
function Person() {this.name = "Person1"};
function Animal() {this.name = "Animal1"};
function Factory() {}
Factory.prototype.getInstance = function (className) {
return eval('new' + className + '()');
}
var factory = new Factory();
var obj1 = factory.getInstance("Person");
var obj2 = factory.getInstance("Animal");
(3) 代理模式: 新建类调用父类接口
function Person() {}
Person.prototype.sayName = function() {
console.log("tsingwong");
}
Person.prototype.sayAge = function() {
console.log(24);
}
function PersonProxy() {
this.person = new Person();
var that = this;
this.callMethod = fucntion (functionName) {
cosnole.log('before proxy:', functionName);
that.person[functionName](); // 代理
console.log('after proxy:', functionName);
}
}
var pp = new PersonProxy();
pp.callMethod('sayName'); // 代理调用Person的sayName()方法;
pp.callMethod('sayAge'); // 代理调用Person的sayAge()方法;
(4) 观察者模式: 即事件模式,如按钮的onClick等应用
function Publisher() {
this.listeners = [];
}
Publisher.prototype = {
'addListener': function (listener) {
this.listeners.push(listener);
},
'removeListener': function (listener) {
delete this.listeners[listener];
},
'notify': function (obj) {
for(var i = 0; i < this.listeners.length; i++) {
var listener = this.listeners[i];
if (typeof listener !== 'undefined') {
listener.process(obj);
}
}
}
};
function Subscriber() {}
Subscriber.prototype = {
'process': function(obj) {
console.log(obj);
}
};
var publisher = new Publisher();
var subscriber = new Subscriber();
publisher.addListener(subscriber);
publisher.notify({name:"tsingwong", age:24});
publisher.notify('这是我发布的字符串');
for/in 语法遍历一个对象的可枚举属性
for 按照设置的条件循环执行包含的语句块
var mycars = new Array();
mycars[0] = "1";
mycars[2] = "3";
mycars[4] = "5";
// for/in遍历
for(i in mycars) {
console.log(mycars[i]); // 1, 3, 5
}
// for遍历
for(var y = 0; y < mycars.length; y++) {
console.log(mycars[y]); // 1, undefind, 3, undefind, 5
另外值得强调的是for/in不会按照属性的下标来排列输出,for/in总是会访问该对象的原型,查看原型链中是否存在属性,这无疑给遍历增加了负担。
所以建议不要对于数组使用for/in循环。必须使用的时候,要加一个判断hasOwnProperty()
去掉从原型链中继承的属性。
对象的属性要使用 for/in,不能使用for循环,因为对象没有长度属性。
数组的每一项可以保存任意类型的数据,即数组的第一个位置可以是字符串,第二个位置是数值,第三个是对象。
数组的length不是只读的,是可以修改的,所以可以通过这个属性操作数组的末尾增加或移除数位。
检测数组
value instanceof Array // 返回一个布尔值
Array.isArray(value) // ES5新方法,返回一个布尔值
所有对象都具有的转换方法
var colors = ["red", "blue", "green"];
// toString()方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分割的字符串
console.log(colors.toString()); //red,blue,green
// valueOf()方法返回的
console.log(colors.valueOf()); // ["red", "blue", "green"]
// alert()方法接受字符串参数,所以后台调用toString()方法
alert(colors.valueOf()); // red,blue,green
// join()方法,只接受一个参数,即作为分隔符的字符串
console.log(colors.join(",")); // red,blue,green
栈方法
栈是LIFO(Last-In-First-Out),主要有推入和弹出两方法,
// push()方法可以接受任意数量的参数,将他们逐个加入到数组末尾,并返回修改后的**数组长度**
var colors = ["red", "balck"];
console.log(colors.push("green", "white")); // 4
console.log(colors); //["red", "balck", "green", "white"]
// pop()方法从数组末尾移除最后一项,减少数组的length,然后返回移除的项
console.log(colors.pop()); // "white"
队列方法
队列是FIFO(First-In-First-Out),队列即末端添加项,前端移除项。
var colors = [];
console.log(colors.push("red", "black", "green")); // 3
// shift()方法移除数组中的第一个项并返回该项,同时将数组长度减一
conosole.log(colors.shift()); // "red"
// ES5新加的unshift()方法,与push()类似,只不过它是在数组的前端添加任意项,并返回数组长度
console.log(colors.unshift("blue", "yellow")); // 4
重新排序方法
var value1 = [1, 2, 3, 4, 5];
// reverse()方法会翻转数组项的顺序,返回排序之后的数组
console.log(value1.reverse()); // [5, 4, 3, 2, 1]
// sort()方法按照升序排列数组项,但该方法会先调用每一项的toString()方法,之后比较的是字符串,返回排序之后的数组
var value2 = [0, 1, 5, 10, 15];
console.log(value2.sort()); // [0, 1, 10, 15, 5]
// sort()方法可以接受一个比较函数作为参数,比较函数接受两个参数,如果第一个参数应该位于第二个之前则返回负数,反之返回一个正数,相同返回0。
function compare (x, y) {
return x - y; // 升序,降序的话是 y - x
}
操作方法
# concat() 方法可以基于当前数组中的所有项创建一个新数组,然后再将接受的参数添加到数组的末尾,返回**新建的数组**。
var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);
// ["red", "balck", "green", "yellow", "black", "brown"]
# slice() 方法可以根据当前数组中的一个或多个项创建一个**新的数组**,接受一或两个参数,即返回项的起始和结束位置,包前不包后,该方法不会影响原数组。
var colors = ["red", "balck", "green", "yellow", "black", "brown"];
var colors2 = colors.slice(1, 4);
// ["balck", "green", "yellow"]
# splice() 方法主要用于往数组中部插入项,有以下三种使用方法
# 删除:删除任意数量的项,只需指定两个参数,要删除的第一项和删除的项数,返回从原始数组删除的数组;
# 插入: 向指定位置插入任意数量的项,只需提供三个参数,起始位置,0(要删除的项),要插入的项。插入多个项,可以在后面继续写第四、五等项
# 替换: 与插入基本相同,只是第二个参数改为要删除的项数
var colors = ["red", "balck", "green", "yellow", "black", "brown"];
console.log(colors.splice(2, 2)); // ["green", "yellow"]
console.log(colors.splice(2, 0, "orange")); // []
console.log(colors.splice(2, 2, "purple")); // ["orange", "black"]
位置方法
# indexOf()方法是ES5的新方法,接受两个参数,要查找的项和查找起点的索引(可选的),该方法从数组的开头(索引0)或第二个参数开始往后查找,返回查找项的索引位置,或没找到的情况下返回-1
var num = [1, 2, 3, 4, 5, 4, 3, 2, 1];
console.log(num.indexOf(4)); // 3
console.log(num.indexOf(4, 4)); // 5
# lastindexOf()方法是ES5的新方法,同indexOf()基本相同,只不过它是从后往前查找的
console.log(num.lastindexOf(4)); // 5
console.log(num.lastindexOf(4, 4); // 3
迭代方法
ES5位数组定义了5个迭代方法,每个方法都接受两个参数:要在每个项上运行的函数,运行该函数的作用域对象(可选)。
每个运行函数都会接受三个函数:数组项的值,该项在数组中的索引位置和数组本身。
# every()方法:对数组中每一项运行给定函数,如果该函数对每一项都返回true,则返回true
# some()方法: 对数组中每一项运行给定函数,如果该函数对任一项都返回true,则返回true,与every()方法正好相对应
var num = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var everyResult = num.every(function(item, index, array){
return (item > 2);
});
console.log(everyResult); // false
var someResult = num.some(function(item, index, array) {
return (item > 2);
});
console.log(someResult); // true
# filter()方法: 返回该函数会返回true的项组成的数组
var num = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var filterResult = num.filter(function(item, index, array) {
return (item > 2);
});
console.log(filterResult); // [3, 4, 5, 4, 3]
# map()方法: 返回函数调用之后的结果组成的数组
var num = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var mapResult = num.map(function(item, index, array) {
return (item * 2);
});
console.log(mapResult); // [2, 4, 6, 8, 10, 8, 6, 4, 2]
# forEach()方法: 没有返回结果,其本质上与for循环迭代数组一样
var num = [1, 2, 3, 4, 5, 4, 3, 2, 1];
num.forEach(function(item, index, array) {
console.log(item); //[1, 2, 3, 4, 5, 4, 3, 2, 1]
});
归并方法
ES5新增了两个归并数组的方法
# reduce()方法: 从数组的第一项开始迭代数组的所有项,然后构建一个最终返回的值,接受两个参数,要在每项上调用的函数和作为归并基础的初始值(可选)。调用函数可接受四个参数,前一个值,当前值,项的索引和数组对象。该函数返回的任意值都会作为第一个参数传给下一项。
# reduceRight()方法: 与reduce()方法完全一致,区别在于从哪头开始遍历数组
var num = [1, 2, 3, 4, 5];
var sum = num.reduceRight(function(prev, cur, index, array){
return (prev + cur);
});
alert(sum); // 15
原型链是实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
实例通过__proto__ || [[prototype]]
连接到其构造函数的prototype
上,其构造函数的prototype
通过__proto__ || [[prototype]]
层层向上最终到Object.prototype
,再往上是原型链的重点null
。
构造函数通过prototype
属性连接到它的prototype
属性上,剩下的原型链过程同上。同样构造函数本身也存在__proto__ || [[prototype]]
连接到它的原型上Function.prototype
。
Function.prototype
有点特殊,因为他的构造函数是Function
,其构造函数的原型还是Function.prototype
。这就相当于是鸡生蛋、蛋生鸡一样。
还忘记提一点constructor
,是从构造函数的原型prototype
指向构造函数的。
Jquery中的解析JSON的parseJSON()方法时默认会添加一个空字符串
人: 阮一峰,黄达峰, 司徒正美,张云龙,sofish(小鱼),尤雨溪
网站: 以上几个人的博客,,阮一峰是
ruanyifeng.com
,黄达峰有个软件Growth,司徒正美去哪儿的前端,在博客园写博客,《javascript框架设计》的作者,张云龙在github上写博客,现在是全民TV的研发,尤雨溪是vue.js的作者。还有就是伯乐在线,V2EX,前端乱炖这些技术论坛,还有开发者头条,掘金上的优秀博文。
freecodecamp,建站两年左右,在github上收获16万star
git add <filename> # 添加文件
git add *
git commit -m "注释" # 这时候改动已经提交到HEAD中,但还没有提交到远端仓库
git push <origin> master # 推送到主分支,可以修改为任意分支
git branch 新分支名 # 创建新分支
git chekcout 分支名 # 切换到另一分支
git checkout -b 新分支名 # 创建并切换到新分支上
git branch -a # 查看分支列表
git branch -r # 查看远程分支列表
git push origin 新分支名 # 向想成提交本地新开分支
git push origin --delete 远程分支名 # 删除远程仓库的分支
git branch -d 分支名 # 删除本地分支
git fetch -p # 更新分支列表信息
git pull # 更新本地仓库到最新改动 等与fetch(获取)+ merge(合并)
git merge 分支名 # 合并其他分支到你当前分支
基础知识的话,主要是从w3school学习html和CSS的,javascript也在w3school上看了一些,之后是看《javascriptDOM编程艺术》,把书上代码都敲了一遍,之后是jquery的学习,《锋利的jquery》,bootstrap学习——瓢虫俱乐部的李炎恢老师的视频教程,《JS高级程序设计》之后是几个框架的熟悉吧。日常就是关注开发者头条和掘金,从上面学习一些技术。
body {
background-attachment: scroll/fixed/inherit; // 默认滚动/不滚动/继承
background-color: yellow/#00ff00/rgb(255, 0, 255);
background-image: url("URL"); //背景图片
background-position: top left / 10% 20% / 10px 15px; //后两个都是相对于左上角定位
background-repeat: repeat/repeat-x/repeat-y/no-repeat/inherit;
}
// 所有背景属性写在一个声明中
body{
background: #ff0000 url(/i/eg_bg_03.gif) no-repeat fixed center;
}
现在有一个动物对象的构造函数:
function Animal () {
this.species = "动物";
}
还有一个猫对象的构造函数
function Cat (name, color) {
this.name = name;
this.color = color;
}
有以下方法可以使猫继承动物
方法一:构造函数绑定
最简单的方法,使用call()或apply()方法,将父对象的构造函数绑定在子对象,即在子对象构造函数中加一行
function Cat (name, color) {
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
方法二:prototype模式
更为常见的移动方法,使用prototype属性。猫的prototype属性指向Animal实例。那么所有的猫实例,都能继承Animal了。
Cat.prototype = new Animal();
// 当前constructor指向Animal,所以手动纠正为指向Cat
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
注: 在编程时务必遵守一点规则,即如果替换了prototype对象,那么下一步一定要为新的prototype对象加上constructor属性,并将这个属性指向原来的构造函数。
o.prototype = {};
o.prototype.construtor = o;
方法三:直接继承prototype
这是对第二种方法的改进。将不变属性直接写入Animal.prototype,所以Cat()跳过Animal(),直接继承Animal.prototype。
function Animal() {}
Animal.prototype.species = "动物";
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
这样写效率较高(不需要执行和建立Animal的实例),节省内存,但Cat.prototype和Animal.prototype都指向同一个对象,故对Cat.prototype的修改,都会反应到Animal.prototype上。
方法四:利用空对象作为中介
由于直接继承prototype存在上面说的缺点,所以利用一个空对象作为中介来继承。
// 这个extend函数,就是YUI库实现继承的方法
function extend(Child, Parent) {
// 利用空对象作为中介。即使修改Cat的prototype对象,也不会影响到Animal的prototype对象。
var F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
// 为子对象设置一个uber属性,直接指向父对象的prototype属性。可以直接调用父对象的方法,实现继承的完备性
Child.uber = Parent.prototype;
}
extend(Cat, Animal);
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species);
方法五: 拷贝继承
上面采用都是prototype对象实现继承,也可以换一种思路,纯粹采用“拷贝”方法实现继承。简单说,将父对象的所有属性和方法,拷贝到子对象中,也能实现继承。
// 首先还是将Animal的所有不变属性,都放到prototype对象上
function Animal() {}
Animal.prototype.species = "动物";
// extend2函数实现属性的拷贝,就是将父对象的prototype对象中的属性,一一拷贝到Child对象的prototype对象。
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
extend2(Cat, Animal);
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
例如两个普通对象,他们不是构造函数,无法使用构造函数方法实现"继承"。
var Chinese = {
nation: "中国"
}
var Doctor = {
career: "医生"
}
方法一: object()方法
// object()函数,将子对象的prototype属性指向父对象,从而使得父对象和子对象关联在一起
function object(o) {
function F() {}
F.prototype = o ;
return new F();
}
var Doctor = object(Chinese);
Doctor.career = "医生";
alert(Doctor.nation); //中国
在 ES5 中有Object.create()
规范了这种继承方式,其名字为:原型式继承。
方法二: 浅拷贝
将父对象属性,全部拷贝给子对象,也能实现继承
function extendCopy(p){
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
var Doctor = extendCopy(Chinese);
Doctor.career = "医生";
alert(Doctor.nation); // 中国
注: 这样拷贝存在一个问题,即父对象的属性如果是一个数组或其他对象的话,子对象只能获得一个内存地址,并不是真的拷贝,因此当修改子对象的属性同时也会修改父对象。
方法三: 深拷贝
所谓深拷贝,局势能够实现真正意义上的数组和对象的拷贝。
// 递归调用“浅拷贝”就行,目前jQuery库使用的这种继承方法
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if(typeof p[i] == "object"){
// 个人认为这里也能使用 Array.isArray(p[i])
c[i] = (p[i].constructor === Array)? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
var Chinese = {
nation: "中国"
}
Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
var Doctor = deepCopy(Chinese);
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港
- 所有标记都必须要有一个相应的结束标记。
- 所有标签的元素和属性的名字都必须是小写。
- 所有的XML元素标签都必须正确嵌套
- 所有的属性必须用引号("")括起来
- 把所有<和&特殊符号用编码表示
- 给所有属性赋一个值
- 不要在注释内容中使用“--”
- 图片必须由说明文字
- 前端开发所写的代码,能直接浏览器上看到,非常有成就感。
- 虽然大家都说前端门槛很低,但是现在前端技术日新月异飞速发展,需要掌握的东西太多了。我想要接受这样的挑战。下定决心,就风雨兼程!
即同一时间针对同意域名下的请求有一定数量限制。
预加载,提前加载图片,当用户需要查看时可以从本地缓存中渲染,但这样无疑是增加了前端压力。
方法一: 使用CSS和JavaScript实现预加载
方法二: 仅使用JavaScript实现预加载
方法三: 使用Ajax实现预加载
这里主要介绍第三种方法,该方法利用DOM,不仅仅预加载图片,还可以预加载CSS、JavaScript等相关东西,且加载不会影响当前页面,简洁高效。
主要思路是,先使用Ajax请求获取到预加载的资源,然后使用javaScript的DOM方法实现加载
setTimeout(function() {
// XHR to request a JS and a CSS
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.js');
xhr.send('');
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.css');
xhr.send('');
// preload image
new Image().src = "http://domain.tld/preload.png";
}, 1000);
setTimeout(function() {
// reference to <head>
var head = document.getElementsByTagName('head')[0];
// a new CSS
var css = document.createElement('link');
css.type = "text/css";
css.rel = "stylesheet";
css.href = "http://domain.tld/preload.css";
// a new JS
var js = document.createElement("script");
js.type = "text/javascript";
js.src = "http://domain.tld/preload.js";
// preload JS and CSS
head.appendChild(css);
head.appendChild(js);
// preload image
new Image().src = "http://domain.tld/preload.png";
}, 1000);
懒加载,延迟加载图片或符合某些条件时才加载图片。节省了用户在打开首页的等待时间,也节省了服务器的流量。
基本思路是不给img标签写src属性,而是写到后面可以操作的属性中,如data-src中,然后在需要加载的时候,加载图片,图片地址到src中。
<div class="img">
<img data-src="XX.png" alt="logo"/>
<br/>
<button class="showImg">
点我显示图片
</button>
<script type="text/javascript">
$(".showImg").click(function() {
var show = $(".img > img");
show.attr("src", show.attr("data-src"));
});
</script>
</div>
现在一般都使用插件preload.js和lazyload.js来完成资源的预加载和懒加载。
前两年,通过大量的编码提高JS能力,同时尝试各种JS框架和库,寻找适合自己的框架。感觉说的通俗点就是多造轮子。
然后两年,拓宽知识面,做到一专多精。在提升JS能力的同时多方面发展。制作一个性能高、交互好、视觉美的页面,需要从前端框架选型、架构设计、构建工具,到后端通信机制、设计与交互、网络和浏览器优化等方面的知识。同时写一些技术博客,提交参与开源项目等。
使用innerHTML程序效率会有数量级上的提高,尤其是要向DOM中添加大量节点时,效率提高更加明显。
# appendChild()插入节点
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++)
{
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
# innerHTML()插入节点
# 这个地方值得注意的是之前我一直使用的都是加法字符串拼接,后来发现使用数组的join()方法效率似乎更高一点
var html = [];
for (var i = 0; i < 1000; i++)
{
html.push('<p>' + i + '</p>');
}
document.body.innerHTML = html.join('');
在一个技术团队中,距离用户最近的无疑是前端。最需要去揣测用户的想法。
前端充满着创新。
前端技术入门容易,深入很难,这是对个人的一种挑战。
一专多长
<input maxkength="20" readonly="readonly" />
<body>
<ul id="menu">
<li>一级菜单1
<ul>
<li>二级菜单11</li>
<li>二级菜单12</li>
<li>二级菜单13</li>
</ul>
</li>
<li>一级菜单2
<ul>
<li>二级菜单21</li>
<li>二级菜单22</li>
<li>二级菜单23</li>
</ul>
</li>
</ul>
<script type="text/javascript">
function menu() {
var elem = document.getElementById("menu");
var ul = elem.getElementsByTagName("ul")
// 初始化隐藏二级菜单
for (var i = 0; i < ul.length; i++) {
ul[i].style.display = "none";
}
//bind the action
var li = elem.getElementsByTagName("li");
for (var i = 0; i < li.length; i++) {
// 鼠标悬停上面,显示二级菜单
li[i].onmouseover = function() {
var inli = this.getElementsByTagName("ul");
for (var j = 0; j < inli.length; j++) {
inli[j].style.display = "block";
}
};
// 鼠标离开上面,隐藏二级菜单
li[i].onmouseout = function() {
var inli = this.getElementsByTagName("ul");
for (var j = 0; j < inli.length; j++) {
inli[j].style.display = "none";
}
}
}
}
menu();
</script>
</body>
- 你觉得我适合这个职位吗?
- 如果我有幸被贵公司录取,请问我会负责些什么?需要我做什么准备?
行内元素margin-top/bottom是无效的,margin-left/right有效。
行内元素padding-top/bottom是脱离文档流的,不会向上向下顶开距离。padding-left/right有效。
JSON在数据传输流程中,是以文本,即字符串的形式传递的。而JS操作的是JSON对象,所有JSON对象和JSON字符串之间相互转换是关键。
JSON字符串:
var str1 = '{"name": "tsingwong", "age": 23}';
JSON对象:
var str2 = {"name": "tsingwong", "age": 23};
通常AJAX返回结果时,都是JSON字符串。所以首先要转化成JSON对象。
var obj = eval('(' + str1 + ')');
或
var obj = JSON.parse(str);
HTML、JavaScript、JSON、XML
最简单的轮播就是:
1. 定义一个数组保存图片;
2. 一个定时器去执行按序号显示对应的图片,每显示一张图片记录这张图片在数组中的序号;
3. 当播放到最后一张图片后,将序号归0,重新开始。
var arr = new Array();
arr[0] = ""; // 图片地址
arr[1] = ""; // 图片地址
arr[2] = ""; // 图片地址
arr[3] = ""; // 图片地址
var count = 0;
setInterval(turnpic, 4000); // 4秒切换一次图片
function turnpic () {
imgSrc = document.getElementById("turnImg");
if (count == arr.length - 1){
num = 0;
} else {
num += 1;
}
imgSrc.src = arr[count];
记得月影老师讲过封装出一个轮播图的库。
User Agent
(用户代理)属性,判断是否为移动端,是则跳转移动端页面,同时在此基础上,用响应式对移动界面不同分辨率下进行一定程度的优化;在设计时遵循移动优先、性能递增的原则,使用viewport
禁止缩放;
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
width:控制 viewport 的大小,可以指定的一个值,如果 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
height:和 width 相对应,指定高度。
initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放
CSS部分用媒体查询@media
写一下规则。
这个方法是在微博上看到的
# 两个div嵌套,内div垂直水平居中
<style media="screen">
.div1 {
width: 400px;
height: 200px;
border: 1px solid #000;
vertical-align: middle;
display: table-cell;
}
.div2 {
width: 200px;
height: 50px;
margin: 0 auto;
}
</style>
<body>
<div class="div1">
<div class="div2"></div>
</div>
</body>
<script type="text/javascript">
//DOM没有提供insertAfter()方法
function insertAfter(newElement, targetElement) {
var parent = targetElement.parentNode;
if (parent.lastChild == targetElement) {
// 如果最后的节点是目标元素,则直接添加。因为默认是最后
parent.appendChild(newElement);
} else {
parent.insertBefore(newElement, targetElement.nextSibling);
//如果不是,则插入在目标元素的下一个兄弟节点 的前面。也就是目标元素的后面
}
</script>
}
jq 对象转换成 DOM 对象: [index]
和 .get(index)
。
[index]
来获取相应的 DOM 对象get(index)
,得到相应的 DOM 对象
var $v = $('#v'); // jQuery 对象
var v1 = $v[0]; // DOM 对象
var v2 = $v.get(0); // DOM 对象
DOM 对象转换成 jq 对象:
$()
将 DOM 对象包装起来,即可获得 jq 对象。
var v = document.getElementById('v');
var $v = $(v);
左侧为工作区,右侧为版本库。版本库中标记 index
的区域为暂存区,标记为 master 是 master 分支所代表的目录树。
此时,HEAD 实际上是指向 master 分支的一个“游标”。objects 标识的区域为 git 的对象库,实际位于 .git/objects
目录下。
对于工作区文件修改之后执行 git add
命令,暂存区的目录树会相应更新,同时工作区修改的文件会被写入到对象库中的一个新对象中,该对象的 id 被记录在暂存区的文件索引中。
当提交操作即 git commit
时,暂存区的目录树会写入版本库(对象库)中, master 分支会做相应的更新,即 master 最新指向的目录树就是提交时原暂存区的目录树。
当执行 git reset HEAD
时,暂存区的目录树会被重写,会被 master 分支指向的目录树所替换,但工作区不受影响。
当执行 git rm --cached
时,会直接从暂存区删除文件,工作区则不会改变。
当执行 git checkout .
或 git checkout --
时,会用暂存区全部的文件或指定的文件替换工作区的文件。该操作非常危险, 会清除工作区中未被添加到暂存区的改动。
当执行 git checkout HEAD .
或 git checkout HEAD
时,会用 HEAD 指向的 master 分支中的全部或部分文件替换暂存区和工作区中的文件。该命令也是非常危险,会清除工作区和暂存区未被提交的改动。
重排:部分渲染树需要重新分析并且节点尺寸需要重新计算。至少会重排一次——即初始化页面布局
重绘:由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新
任何改变用来构建渲染树的信息都会导致至少一次的重绘或重排。
display: none
彻底隐藏 DOM 节点,触发重排和重绘visibility: hidden
隐藏 DOM 节点,只触发重绘,因为没有几何变化