JiM-W

keep Moving


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

javascript经典面试题理解this

发表于 2016-09-19 | 分类于 javascript

javascript this 经典面试题

1
2
3
4
5
6
7
8
9
10
function Foo(){
getName = function(){console.log("1");};//这个不属于Foo的属性
return this ;
//如果作为构造函数,那么返回的this就是实例化对象,
//如果作为函数直接执行,那么返回的this就是全局的window对象
}
Foo.getName = function(){console.log("2"); };
Foo.prototype.getName = function(){ console.log("3");};
var getName =function(){console.log("4");};
function getName(){console.log("5");};

预解析之后

1
2
3
4
5
6
7
8
9
10
var getName;//只提升变量声明
function getName(){console.log("5");};//提升函数声明,覆盖变量var声明
function Foo(){
getName = function(){console.log("1");};//这个不属于Foo的属性
return this ;//如果作为构造函数,那么返回的this就是实例化对象,如果作为函数直接执行,那么返回的this就是全局的window对象
}
Foo.getName = function(){console.log("2"); };
Foo.prototype.getName = function(){ console.log("3");};
getName =function(){console.log("4");};

可以在控制台输出看下数据结构

1
2
3
console.dir(Foo);
var res = Foo.getName();//注意没有返回值,如果将Foo看成对象,
console.log(res);

看下面的求值过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Foo.getName();//2
getName();//4
Foo().getName();
//1 先执行了Foo() 函数,Foo函数第一句,getName没有用var声明,改变了输出4的getName,变为输出1
//2 第二句 返回了this,代表当前指向环境的window;相当于执行了 window.getName();
getName();//1 直接调用getName ,上面一行代码改变后的结果
//运算符的优先级 () > 成员访问 . > new 操作符
new Foo.getName();//2 new一个构造函数的时候,构造函数内部的代码会一行一行执行;
// 等价于 new (Foo.getName)();
new Foo().getName();//3 Foo作为构造哦函数,没有给实例化的对象添加任何属性,只能去原型上找
// 等价于 (new Foo()).getName();
new new Foo().getName();//3
// 等价于 new (new Foo().getName)();

————————————- = 运算符面试题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
面试题
*/
// 基本类型和引用类型
// 引用类型变量和对象属性(在内存实际上就是内存地址)
var a = {n:1};
var b = a;
a.x = a = {n:2};//运算符的优先级 .的优先级最高 赋值操作是从右向左运算的
console.log(a.x);//undefined
console.log(b.x);//{n:2}
/*
我们可以先尝试交换下连等赋值顺序(a = a.x = {n: 2};),可以发现输出不变,即顺序不影响结果。
那么现在来解释对象连等赋值的问题:按照es5规范,题中连等赋值等价于
a.x = (a = {n: 2});,按优先获取左引用(lref),然后获取右引用(rref)的顺序,a.x和a中的a都指向了{n: 1}。至此,至关重要或者说最迷惑的一步明确。(a = {n: 2})执行完成后,变量a指向{n: 2},并返回{n: 2};接着执行a.x = {n: 2},这里的a就是b(指向{n: 1}),所以b.x就指向了{n: 2}。
*/

提高网页性能的方法

发表于 2016-09-19 | 分类于 javascript

1 文件合并(减少HTTP请求数量)

  • CSS Sprites

  利用css sprites将网站用到的图片合并成一张图片,通过background-position、width、height控制背景图位置来使用某一个图标,这种方式可以将多个图片请求缩减为一次,生成css sprites的工具也很多,grunt和gulp中都有相关的插件,CssGaga也不错。

  • 合并js和css

  和精灵图一样,合并css和js文件也是减少HTTP请求很重要的方式,对css文件的合并目前来说没有什么争议,但是对于当前js模块化盛行,将所有js文件合并成一个文件,仿佛是一种倒退。正确的方式是遵守编译型语言的模式,保持js的模块化,在生成过程中只对初始请求用到的js文件生成目标文件。

2 使用内容发布网络(减少HTTP请求时间)

  HTTP请求时间另一个影响因素是你与网站web服务器所处的距离,显然距离越远,请求所需的时间也越久,通过CDN可以大大改善这一点。

  CDN是分布在多个不同地理位置的web服务器,用于更加有效的向用户发布内容。CDN最主要的功能是给终端用户存放静态文件,另外也提供下载、安全服务等功能。

​ CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。

3 设置浏览器缓存(避免重复HTTP请求)

  • 使用Expire/Cache-control

  浏览器通过使用缓存可以避免每次都进行重复的请求,HTTP 1.0和HTTP1.1分别有不同的缓存实现方式,Expires(1.0)和Cache-control(1.1)。Web服务器通过expires告诉客户端在指定的时间内,都使用该文件的缓存副本,不再向服务端重复发出请求,例如:

1
Expires: Thu, 01 Dec 2016 16:00:00 GMT (GMT格式)

  这个设置意味着截止到2016年12月1日,都可以使用该缓存副本,无需再发出请求。

  Expires这种通过截止日期的方式,存在一个限制:要求客户端和服务端时钟严格同步,而HTTP 1.1引入的Cache-Control通过指定一个以秒为单位的时间指定缓存日期,则不存该限制,例如:

1
Cache-Control: max-age=31536000

  这个设置意味缓存时间为一年,推荐使用Cache-Control,但是在支持HTTP 1.1的情况下,另外要注意的一点:Cache-Control和Expire同时存在时,Cache-Control具有更高的优先级。

  • 配置或移除ETag

  使用Expire/Cache-Control可以避免第二次访问时,使用本地缓存避免重复HTTP请求,提高网站速度。然而,在用户点击了浏览器刷新或者在expire已过期的情况下,仍然会向服务端发出HTTP GET请求,而此时如果该文件并没有发生变化,服务端不会返回整个文件而是会返回304 Not Modified状态码。

  服务端判断该文件是否发生变化的依据有两个:Last-Modified(最新修改日期)和ETag(实体标签);

  ETag(Entity Tags)是在HTTP 1.1引入的,与Last-Modified同时存在时要有更高的优先级。服务端通过对比客户端发来的ETag(If-None-Match)和当前ETag,若相同返回304 Not Modifed,否则返回整个文件以及200 OK。

  ETag存在一个问题:当浏览器向一个服务器发送GET请求原始组件,之后又向另一台服务器请求该组件时,ETag是不匹配的,当然,如果你的网站寄宿在一台服务器上不存在这个问题,而现在很多网站使用多台服务器,ETag的存在就大大降低验证有效性的成功率。

  存在这个问题是时的解决办法是对ETag进行配置,移除服务器innode值只保留修改时间戳和大小作为ETag值,或者直接移除ETag,使用Last-Modified来验证文件有效性。

4 压缩组件(减小HTTP请求大小)

  通过对HTTP传输的文件进行压缩减小HTTP请求的大小,提高请求速度,GZIP是目前最常用也是最有效的压缩方式。

  然而,并非所有的资源文件都需要压缩,压缩的成本包括服务端需要花费CPU周期进行压缩,而客户端也需要对压缩文件进行解压缩,必须结合自己网站进行权衡。现在绝大多数网站都对其HTML文档进行压缩,部分网站选择对js、css进行压缩,几乎没有网站对图片、PDF等文件进行GZIP压缩,原因在于这些文件是已经被压缩过的,采用HTTP压缩已经被过压缩的东西并不能使它更小。事实上,添加标头,压缩字典,并校验响应体实际上使它变得更大,而且还浪费了CPU。

  如何对网站开启GZIP,需要在所使用的web服务器(IIS、Nginx、Apache等)中进行设置。

5 CSS文件放在首部

  将CSS文件放在首部和放在尾部,并不影响HTTP请求,因此从请求时间上来讲是一致的,然而从用户体验的角度,将CSS文件放在首部,会获得更好的用户体验。

  原因在于浏览器是从上到下依次解析html文档,将CSS文件置于头部,页面会首先对CSS文件发出请求,随后加载DOM树并对其进行渲染,页面会逐步呈现在用户面前。

  而与之相反,如果将CSS文件放置在尾部,页面加载完整DOM之后请求CSS文件,然后对整个DOM树渲染并呈现给用户,从用户的角度,在css文件没有请求完成之前,整个页面是出于白屏状态的,白屏是浏览器的一种行为,David Hyatt对其的解释是这样的

在样式树没有完全加载之前,渲染dom树就是一种浪费,因为在样式树加载完成之后会再次渲染,出现FOUC(无样式内容闪烁)问题。

  另外要注意的一点,使用link而不是@import引入css样式表,使用@import引入的样式即使写在首部,也会在文档最后加载。

6 JS文件放在尾部

  HTTP请求是并行的,不同浏览器并行下载的数目也不一样(2、4、或者8个),并行下载提高了HTTP请求的速度。而将JS文件放在首部,不仅会阻塞后面文件的下载而且会阻塞页面的渲染。

  为什么会这样呢?原因有两个:

  • JS文件中可能存在document.write修改页面的内容,因此页面会在脚本执行完成之后才可使渲染。
  • 不同JS文件不管大小如何,可能存在依赖关系,因此必须按照顺序进行执行,因此在加载脚本的时候并行下载是禁止的。

  所以,最好的方式是讲js文件放置在尾部,等页面所有可视化组件加载完成之后再进行请求,提高用户体验。7

7 图片如果太多的话,使用懒加载的方式

:判断图片位置距离页面顶部的距离,先不加载图片,当用户滚动到该位置的时候将图片的src属性赋值为实际值,data-src可以先缓存图片的真实路径,方便取出;

jQuery选择器

发表于 2016-09-17 | 分类于 jQuery

jQuery中筛选的总结:

1 查找子代 children( ),如果不加选择器,那么将选择所有的子代元素,可以加一个选择器进行筛选;注意仅仅匹配子代元素,不匹配后代(子代的子代);

查找所有后代 find( “ selector” ),可以选择所有的后代元素,包括子代的子代;

2 查找同辈元素:next() prev( ) 查找当前匹配到所有的对象的紧邻的后(前)一个元素;nextAll( ) prevAll( ),查找当前匹配对象的所有的对象的后面(前面)的所有元素;

3 查找匹配元素:first( ) last( ) ,查找匹配元素的第一个或者最后一个元素;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ul id="ulist">
<li>list item 0</li>
<li>list item 1
<ul>
<li>最里面的li</li>
</ul>
</li>
<li id="list">list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
</ul>
$("#ulist").children()
$("#ulist").children("li");//不包括最里面的li
$("#ulist").find("li");//包括最里面的Li
$("#list").prev();//获取list item1
$("#list").prevAll();//获取当前对象前面的所有的同辈元素
$("li").first();//查找匹配元素的第一个或者最后一个元素,此时匹配的是listitem0

the config of require js

发表于 2016-09-16 | 分类于 javascript

1 require源码上可以看出来require.js有三个全局变量 require requirejs 和 define

​ define ([ module1,module2····] ,callback) 中的module路径依赖

​ require([ module1,module2····],callback) 中的module路径依赖

二者的路径依赖如何?

  • 如果设置了data-main,那么module引入路径就是相对于data-main文件所在目录为基准
  • 如果设置了require.config baseUrl 的路径,那么define和require依赖的mudule引入 路径就是相对于baseUrl的

2 以data-main路径为准,且不设置baseUrl

目录如下

1
2
3
4
5
6
7
pathTest
- index.html
- js
- jquery.js
- main.js
- require.js
- test.js

index.html

1
<script src="js/require.js" data-main="js/main"></script>

main.js

1
2
3
require(['test'],function(w){ //引入test模块的路径 js/test.js
console.log(w);
})

test.js

1
2
3
4
define(['jquery'],function(){ //引入jquery模块的路径 js/jquery.js
var w = $(window).width()
return w ;
})

3 设置baseUrl,看下路径变化

改变下目录结构

1
2
3
4
5
6
7
8
pathTest
- index.html
- js
- main.js
- require.js
- test.js
- jq
- jquery.js

main.js 设置baseUrl

关于date-main的实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//源码实现方式
if (isBrowser && !cfg.skipDataMain) {
eachReverse(scripts(), function (script) {
if (!head) {
head = script.parentNode;
}
dataMain = script.getAttribute('data-main');
if (dataMain) {
mainScript = dataMain;
if (!cfg.baseUrl) {
src = mainScript.split('/');
mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath;
}
mainScript = mainScript.replace(jsSuffixRegExp, '');
if (req.jsExtRegExp.test(mainScript)) {
mainScript = dataMain;
}
cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
return true;
}
});
}
1
2
3
4
5
6
require.config({
baseUrl : 'js/jq'
})
require(['../test'],function(w){ //此时如果在想依赖test模块,路径有变化需要向上走一级
console.log(w);
})

test.js 依赖模块路径以js/jq为准

1
2
3
4
define(['jquery'],function(){ //没有变化
var w = $(window).width()
return w ;
})

4 如果直接以 绝对路径 / 引入包,文件名后缀 js 不能再省略了;代表相对于服务器的根目录

scheme:host : port / path 即path根目录

myvirtual 是我的一个虚拟主机

1
2
3
4
5
6
7
8
myvirtual
- test.js
- jquery.js
- pathTest
- index.html
- js
- main.js
- require.js

main.js

1
2
3
require(['/test.js'],function(w){ // 代表域名根路径 myvirtual/test.js
console.log(w);
})

test.js

1
2
3
4
define(['/jquery.js'],function(){ //myvirtual/jquery.js
var w = $(window).width()
return w ;
})

5 通过require.config直接设置模块的路径,requirejs支持跨域获取文件 require.config

1
2
3
4
5
6
7
8
9
10
11
myvirtual //这是一个虚拟主机
- jquery.js
- pathTest
- module1.js
- test.js
- index.html
- js
- main.js
- require.js
myvirtual2 //这是另外一个虚拟主机
- innervirtual2.js

index.html

1
<script src="js/require.js" data-main="js/main"></script>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
require.config({
paths : {
mytest : "../test",//index.html设置data-main属性,所以默认根路径是main文件所在目录
myinner: "http://www.myvirtual2.com/innervirtual2" , //跨域设置路径
myabs : "/module1" ,//通过域的根目录设置包路径
myjquery : '/jquery' //通过域的根目录设置包路径
}
})
require(['mytest','myinner','myabs'],function(arg1,arg2,arg3){
console.log(arg1,arg2,arg3);
})

test.js

1
2
3
4
define(['myjquery'],function(){
var w = $(window).width()
return 'this is test---'+w ;
})

module1.js

1
2
3
4
5
6
7
8
define(function(){
var add = function(a,b){
return a+b;
};
return {
add : add
}
});

myvirtual2 / innervirtual2.js

1
2
3
4
5
6
7
8
define(function(){
var innerV2 = function(){
console.log("this is cross package");
}
return {
innerV2 : innerV2
}
})

6 submit

6.1 如果直接通过路径获取包,如 2,3部分,文件后缀js可以省略

6.2 如果直接通过绝对路径获取包,如4部分,文件后缀js不能省略

6.3 如果设置require.config paths 设置包的路径,文件后缀js可以省略

Git command detail Branch

发表于 2016-09-15 | 分类于 git

在不同的分支上的内容是不一样的,切换到不同分支,工作区的文件内容也是不一样的

分支管理

  • 创建与合并分支
  • git branch 可以查看当前分支状态,分支的个数 此时master一个分支
  • git checkout -b newBranch 新建一个分支 newBranch
  • git branch 此时分支多了一个newBranch
  • git add index.html 将文件的变动添加到newBranch分支上
  • git commit -m’newBranch first’ 新建分支第一次commit,新建分支线延长
  • git checkout master 回到master主分支
  • 在newBranch分支上对文件做的改动并没有在master分支上的文件上显示
  • git merge newBranch 将新建的分支和主分支合并
  • 此时在新建的分支上做的变动会在之分支上显示出来

解决冲突

  • echo ‘content’ > index.html 可以向文件中写入内容,会先清空文件中的内容
  • echo ‘content’ >> index.html 可以向文件中添加内容,原来的内容不会被清空
  • git checkout -b newBranch2
  • git add index.html
  • git commit -m’commitNewBranch2’
  • 以上操作在 newBranch2 将文件内容改动,commit一次
  • git checkout master
  • git add index.html
  • git commit -m’commitmaster2’
  • 以上操作在master主分支将文件改动,commit一次
  • git merge newBranch2 此时合并会发生冲突,根本原因是master分支和newBrach2分支都提交了
  • 注意这个时候必须先手动解决冲突,然后再次提交
  • 在主分支上再次commit
  • git add index.html
  • git commit -m’ conflict fix’
  • git log –graph –pretty=oneline –abbrev-commit 可以查看分支合并的状况

在分支合并之后可以选择将被合并的分支删除

  • git branch -d newBranch 可以删除newBranch 分支

分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward`合并就看不出来曾经做过合并

  • git merge –on-ff -m’merge with –on-ff’ dev dev是一个新的分支,在这个新的分支上做改动

和远程仓库进行对接

  • 本地master ——>push本地master ——>远程就有了master分支 ——> 本地新建分支teacher——> push本地teacher——>

merge之后可以删除分支,不删除也可以

当从远程仓库克隆的时候,仅仅克隆的是master分支,如果想要远程其他分支上的数据,比如master2分支

  • 可以在本地新建一个分支master2,用于存放pull下来的分支
  • 然后切换到本地该分支,进行pull远程仓库那个分支 git pull origin master2

apache virtual and Cross Origin

发表于 2016-09-13 | 分类于 http

写在前面:有兴趣的还是可以阅读下httpd.conf以及httpd-vhosts.conf 文件里面的注释,方便理解;

1 如何搭建本地apache服务器?

下载wamp软件,安装完毕之后,启动apache服务器,在浏览器URL地址栏输入127.0.0.1或者localhost便可以进入apache主页(此时服务器默认的访问路径是(D是我安装在D盘) D/wamp/www/ 文件夹下面的index开头的文件,)

1.1 配置服务器访问路径

找到wamp —>bin —>apache 目录下面的 httpd.conf 修改默认访问路径,将 D/wamp/www/ 比如修改为 F:/mywork/

  • httpd.conf 中 DocumentRoot 可以修改默认访问的路径 F:/mywork/

  • httpd.conf 中 Directory 也要修改默认路径F:/web/

  • 如果该路径F:/mywork/ 里面有index.html index.php 等以index命名的文件,会直接打开该文件,如果没有则进入F:/mywork/该目录

  • 为什么会默认打开index开头的文件呢?在httpd.conf文件中,如下代码设置了默认打开目录下面的文件名字

    DirectoryIndex决定打开虚拟主机的时候,默认打开的文件名称

1
2
3
<IfModule dir_module>
DirectoryIndex index.php index.php3 index.html index.htm
</IfModule>
  • 访问自己的服务器的三种方式:本机的IP地址 127.0.0.1 localhost httpd.conf 文件中listen 可以更改端口
  • 此时在通过localhost或者127.0.0.1 再次进入的时候就会进入F:/mywork目录里面来(如果该目录下面有index开头的文件会默认直接打开该文件,如果没有的话则打开该目录)
  • 只有在这里配置了目录之后,在配置虚拟主机的时候,虚拟主机的目录也必须是这个目录,或者这个目录的子目录
1
2
3
4
5
6
7
8
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot " F:/mywork/" //如果在虚拟主机配置的目录和F:/web不一致,则没有权限进入该目录,无论是通过localhost 还是通过127.0.0.1 都无法进入虚拟主机,必须要和服务器设置的访问路径保持一致;
ServerName test.com
ServerAlias www.test.com
ErrorLog "logs/dummy-host.example.com-error.log"
CustomLog "logs/dummy-host.example.com-access.log" common
</VirtualHost>

1.2 配置服务器通过域名访问 虚拟主机

  • 先要明确配置虚拟主机的目的,上面第一步所实现的功能是,我们可以通过localhsot或者127.0.0.1以及本机ip地址来访问我们的服务器(也就是后来修改的文件目录 F:/mywork/)

httpd.conf 文件中找到 # Virtual hosts 打开这行代码下面一行的 # 号

1
Include conf/extra/httpd-vhosts.conf

当我们打开虚拟主机之后,重启apache服务,在通过localhost或者127.0.0.1已经无法进入 F:/mywork/目录,需要重新配置wamp —>bin —>apache—>extra—>httpd-vhosts.conf文件

1
2
3
4
5
VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
也就是说当我们设置虚拟主机的时候,Apache在所有的VirtualHost container中如果没有找到匹配的serverName或者ServerAlias的时候,会直接进入第一个Virtual Block

如下配置,我设置了三个主机,分别是mainVirtual myVirtual1 myVirtual2 对应不同的路径,但是都是F:/web/或者F:/web/的子目录,然后通过 ServerName ServerAlias设置的对应值,在浏览器的URL地址栏就可以访问了

1.2.1 设置host文件 C:\Windows\System32\drivers\etc 下面的host文件,我们在这里配置的域名,如果在URL地址栏输入该域名,我们就可以访问这个本机虚拟主机;

1
2
3
127.0.0.1 www.mainVirtual.com
127.0.0.1 www.myVirtual1.com
127.0.0.1 www.myVirtual2.com

1.2.2 设置wamp —>bin —>apache—>extra—>httpd-vhosts.conf文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# operation by JiM
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "F:/web/"
ServerName mainVirtual.com
ServerAlias www.mainVirtual.com
ErrorLog "logs/dummy-host.example.com-error.log"
CustomLog "logs/dummy-host.example.com-access.log" common
</VirtualHost>
# this is JiM's test for the Virtual container for myVirtual1
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "F:/web/myVirtual1"
ServerName myVirtual1.com
ServerAlias www.myVirtual1.com
ErrorLog "logs/dummy-host.example.com-error.log"
CustomLog "logs/dummy-host.example.com-access.log" common
</VirtualHost>
# this is JiM's test the Virtual container for myVirtual2
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "F:/web/myVirtual2"
ServerName myVirtual2.com
ServerAlias www.myVirtual2.com
DirectoryIndex doc.html //假如文件目录下有一个doc命名的文件,则DirectoryIndex的设置可以默认打开该文件
ErrorLog "logs/dummy-host.example.com-error.log"
CustomLog "logs/dummy-host.example.com-access.log" common
</VirtualHost>

1.2.3 这个时候我们通过www.mainVirtual.com www.myVirtual1.com www.myVirtual2.com就可以访问我们对应的主机咯(每个路径对应的目录要事先创建好)

2 在本地搭建的服务器测试跨域的几种方案(同一域名下的不同子域之间也受同源策略的限制)

假如 我在之前搭建的www.myVirtual1.com域下,也就是F:/web/myVirtual1文件夹下面有一个文件 test1.php

www.myVirtual2.com这个域内的文件想访问www.myVirtual1.com下面的test1.php文件

URL(Uniform Resource Locator) 地址用于描述一个网络上的资源, 基本格式如下

1
scheme://host[:port#]/path/.../[?query-string][#anchor]

scheme host port三者有一个不一样就发生了跨域,如何解决跨域?

2.1 Access-Control-Allow-Origin:域名 表示设置允许哪个域名进行访问

header(“Access-Control-Allow-Origin: http://www.myvirtual2.com“) 通过对访问的跨域资源设置响应头,允许某个指定的域名来访问该文件;

1
2
3
4
5
6
7
8
9
10
11
12
//F:/web/myVirtual1/test1 .php 这个是我的虚拟主机1 里面的文件
<?php
header("Access-Control-Allow-Origin: http://www.myvirtual2.com");
$username = $_GET['username'];
$array = ["Jhon","Jim","James","Robe"];
$flag = in_array($username,$array);
if($flag){
echo '您可以登录';
}else{
echo "该用户名已经被注册";
}
?>

这个是虚拟主机2 里面的请求文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="test1.php" method="post">
<input type="text" id="username" name="username"/><span id="message"></span><br>
<input type="password" id="psw" name="psw"/>
</form>
<script src="jquery-1.12.4.js"></script>
<script>
$(function(){
$('#username').blur(function(){
var username = $(this).val();
console.log(username);
$.ajax({
url:'http://www.myvirtual1.com/test1.php?username=Jhon',
type:'get',
data:{"username": username} ,//代表发送到服务器的数据
success:function(data){//如果请求成功了,则可以执行该函数
console.log(data);
$("#message").html(data) ;
}
})
})
})
</script>
</body>
</html>

2.2 通过script标签 src属性

1
2
3
4
5
6
7
8
9
<?php
header("Content-Type:text/script;charset=utf-8");//如果没有这个响应头,在开发者network里面可以查看请求和响应的详细信息,默认返回的是Content-Type:text/html文本格式的数据,不过这个也不影响,script标签还是会将其解析成javascript代码运行
$callback = $_GET['callback'];
$username = $_GET['username'];
$array = ["Jhon","Jim","James","Robe"];
$flag = in_array($username,$array);
$data = "{0:'您可以登录',1:'该用户已经被注册'}";
echo $callback.'('.$data.','.$flag.')';
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>请注册</h1>
<form action="" method="get">
<input type="text" id="username" name="username"/><span id="message"></span><br>
<input type="password" id="psw" name="psw"/>
</form>
<script src="jquery-1.12.4.js"></script>
<script>
function getInfo(arg,flag){
if(flag){
console.log(arg);
console.log(typeof arg);
$("#message").html(arg[0]);
}else{
console.log("this count has been rejected");
$("#message").html(arg[1]);
}
}
</script>
<script src='http://www.myvirtual1.com/test1.php?callback=getInfo&username=Jhon'></script>
</body>
</html>

2.3 jQuery.ajax通过jsonp来进行跨域请求,本质上使用script标签发送请求,获取到的数据作为javascript代码直接执行

1
2
3
4
5
6
7
8
9
10
//F:/web/myVirtual1/test1 .php
<?php
header("Content-Type:text/script;charset=utf-8");
$callback = $_GET['callback'];
$username = $_GET['username'];
$array = ["Jhon","Jim","James","Robe"];
$flag = in_array($username,$array);
$data = "{0:'您可以登录',1:'该用户已经被注册'}
echo $callback.'('.$data.','.$flag.')';
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>请注册</h1>
<form action="" method="get">
<input type="text" id="username" name="username"/><span id="message"></span><br>
<input type="password" id="psw" name="psw"/>
</form>
<script src="jquery-1.12.4.js"></script>
<script>
function getInfo(arg,flag){
console.log(flag);
//这个flag一直是undefined,因为echo:flase不会有任何结果,不想改了,主要是理解跨域
if(flag){
console.log(arg);
console.log(typeof arg);
$("#message").html(arg[0]);
}else{
console.log("this count has been rejected");
$("#message").html(arg[1]);
}
}
$(function(){
$('#username').blur(function(){
var username = $(this).val();
$.ajax({
url:'http://www.myvirtual1.com/test1.php',
type:'get',
dataType:'jsonp',
jsonpCallback:'getInfo',//用来替换jQuery自动生成的函数名,以便于直接执行getInfo函数
data:{"username": username} ,//代表发送到服务器的数据
})
})
})
</script>
</body>
</html>

2.4 通过反向代理进行跨域访问

反向代理作用1:减轻源服务器负载  2:保障源服务器安全  3:对源服务器进行负载均衡(Load Balance)。通过在服务器端设置代理服务,可以进行跨域访问

打开httpd-conf文件,打开以下两行代码中的#号

1
2
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

我们在新建两个虚拟主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "F:/web/4myvirtual4"
ServerName myvirtual4.com
ServerAlias www.myvirtual4.com
ErrorLog "logs/dummy-host.example.com-error.log"
CustomLog "logs/dummy-host.example.com-access.log" common
</VirtualHost>
<VirtualHost *:80>
DocumentRoot "F:/web/5myvirtual5"
ServerName myvirtual5.com
ServerAlias www.myvirtual5.com
ProxyRequests Off
ProxyPass /api http://www.myvirtual4.com
#这个时候访问http://www.myvirtual5.com/api 其实就是访问 http://www.myvirtual4.com
</VirtualHost>
  • ProxyRequests Off 指令是指采用反向(reverse)代理
  • ProxyPass 指令允许将一个远端服务器映射到本地服务器的 URL 空间中。

在F:/web/5myvirtual5 下面有一个文件 01proxy.html

1
2
3
4
5
6
7
8
9
10
<script src="jquery.js"></script>
<script>
$.ajax({
type:'get',
url:'/api/01proxy.php',
success:function(data){
console.log(data);
}
})
</script>

在F:/web/4myvirtual4 下有一个文件 01proxy.php

1
2
3
<?php
echo 'this is sonme data from virtual4'
?>

2.5 通过document.domain 设置同一主域不同子域中的页面相同的主域名,来允许不同子域之间进行访问

2.6 通过HTML5postMessage方法进行跨域操作,参见我的博客HTML5-postMessage

2.7 绕开浏览器,直接通过服务器端发送请求

2.8 关于其他跨域问题,比如其他的服务器会通过请求的referer信息进行访问的限制,可以通过设置

1
<meta name=''>

src和href的区别

发表于 2016-09-13 | 分类于 javascript

写代码的时候就经常把这两个属性弄混淆,到底是href还是src,href标识超文本引用,用在link和a等元素上,href是引用和页面关联,是在当前元素和引用资源之间建立联系,src表示引用资源,表示替换当前元素,用在img,script,iframe上,src是页面内容不可缺少的一部分。

  src是source的缩写,是指向外部资源的位置,指向的内部会迁入到文档中当前标签所在的位置;在请求src资源时会将其指向的资源下载并应用到当前文档中,例如js脚本,img图片和frame等元素。

\当浏览器解析到这一句的时候会暂停其他资源的下载和处理,直至将该资源加载,编译,执行完毕,图片和框架等元素也是如此,类似于该元素所指向的资源嵌套如当前标签内,这也是为什么要把js饭再底部而不是头部。

\当浏览器解析到这一句的时候会识别该文档为css文件,会下载并且不会停止对当前文档的处理,这也是为什么建议使用link方式来加载css而不是使用@import。

补充:link和@import的区别

两者都是外部引用CSS的方式,但是存在一定的区别:

区别1:link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。

区别2:link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。

区别3:link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。

区别4:ink支持使用Javascript控制DOM去改变样式;而@import不支持。

ArrayLikeChangedToArray

发表于 2016-09-13 | 分类于 javascript

类数组对象转换为数组对象的简单理解

一 : 关于类数组对象:只包含使用从零 0 开始,且自然递增的整数做键名,并且定义了length表示元素个数的对象

JavaScript中有一些著名的类数组对象,它们看起来很像数组:

  • 拥有length属性 这里强调一下,必须有length属性,且length属性的值必须和元素键值对个数保持一致 如果没有length属性,那么就不是类数组
  • 元素按序保存在对象中,可以通过索引访问

但实际和数组又不是一回事:

  • 没有数组的很多方法
  • 也会有数组没有的方法(e.g. NodeList的item()方法)
  • 有些类数组对象是动态变化的(e.g. NodeList的值是基于DOM结构动态执行查询的结果)
1
2
3
4
5
6
7
8
9
var arrLike = {
0:7,
1:8,
2:9,
length:2 //length属性值小于3 最后一个9不会被添加进去
}
var arr1 = [1,2,3];
arr1.push.apply(arr1,arrLike);
console.dir(arr1);
1
2
3
4
5
6
7
8
9
var arrLike = {
0:7,
1:8,
2:9,
length:3 //length属性值等于3
}
var arr1 = [1,2,3];
arr1.push.apply(arr1,arrLike)
console.dir(arr1);
1
2
3
4
5
6
7
8
9
var arrLike = {
0:7,
1:8,
2:9,
length:5 //length属性值大于3
}
var arr1 = [1,2,3];
arr1.push.apply(arr1,arrLike)
console.dir(arr1);
1
2
3
4
5
6
7
8
var arrLike = {
1:8,
2:9,
length:5 //缺少索引为0 的键
}
var arr1 = [1,2,3];
arr1.push.apply(arr1,arrLike)
console.dir(arr1);

通过以上四种情况,大家可以在自己电脑上输出看下结果,类数组对象的定义大家应该会有一种新的认识;

二 : 将 类数组对象 转换为 数组对象

  • slice 和splice方法都可以,slice不会改变原数组,splice会将改变原数组
1
2
3
4
5
6
Array.prototype.slice.call(arraylike, 0);
Array.prototype.splice.call(arrLike,0);
Array.prototype.slice.apply(arrayLike,[0]) ;//注意咯,这里必须是 数组形式的参数,
Array.prototype.splice.apply(arrLike,[0]);
//参数会传递给slice或者splice方法
1
2
3
4
5
6
7
8
9
10
11
var arrLike = {
0:"name",
1:"age",
2:"address",
length:3
}
// var ret = Array.prototype.slice.call(arrLike,0);
// var ret = Array.prototype.splice.call(arrLike,0);
// var ret = Array.prototype.slice.apply(arrLike,[0]);
// var ret = Array.prototype.splice.apply(arrLike,[0]);
console.dir(ret);
  • push + apply + 空数组(apply会将传入的数组或者类数组拆分开以单个元素的形式传递给push,然后push就可以正常的往数组里面加元素咯)
1
2
3
4
5
6
7
8
9
10
11
12
var arrLike = {
0:"name",
1:"age",
2:"address",
length:3
}
var ret = [];
Array.prototype.push.apply(ret,arrLike);
//Array.prototype.push.call(ret,arrLike); //这个会将arrLike作为一个整体直接push进ret数组中
//arrLike 必须是一个伪数组,length属性不可少,索引值必须从 0 开始递增,不是
console.dir(ret);
//这个方法的关键还是要理解apply方法会对传入的数组进行拆分,这个真的很重要

以上的栗子,大家可以将类数组的length属性去掉试一下看看,就会发现这个属性对于类数组 定义的重要性了

ClientRenderOrServerRender

发表于 2016-09-12 | 分类于 template

模板引擎 (Template Engine)是Web开发中将展现层和数据分离的一项技术。模板引擎根据一定的语义,将数据填充到模板中,产生最终的HTML页面。模板引擎渲染的位置可分为客户端和服务器端。

服务器端渲染:模板引擎在服务器端将模板和数据合成,返回最终的HTML页面

  • 客户端渲染通常使用JavaScript脚本,如果某些客户端不支持JavaScript,就需要在服务器端渲染;
  • 搜索引擎通常不执行JavaScript脚本,要做到SEO友好,就必须实现服务器端渲染;
  • SEO 很多爬虫是不认的。
  • 首次打开速度,各种加载 速度很慢。

客户端渲染:将模板和数据分别传送到客户端,在客户端由JavaScript模板引擎渲染出最终的HTML视图。

  • 可以对模板文件(相对静态)进行缓存和负载平衡,对于流量很大的公众站点非常有价值;
  • 由于将模板渲染的计算转移到客户端,可降低服务器负荷;
  • 各种原来服务器做的事情丢给客户端做了,减少开销。
  • 如果一个前端页面的内容分别来自多个后台系统,而这些后台的架构各不相同(Java、.NET、Ruby等),则服务器端渲染需要采用不同的技术,模板资源无法共享。客户端渲染则不存在这个问题,不同的后台系统可采用相同的客户端渲染技术,这样互相之间的模板资源可以公用,前端页面的整合非常容易;

注意问题

  • 客户端渲染和服务端渲染的时候,文件的语法格式不能一样,否则会冲突

媒体查询 响应式开发

发表于 2016-09-10 | 分类于 mobile

媒体查询:响应式开发

第一种不同终端的宽度自适应代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.container {
width: 1200px;
height: 1000px;
margin: 0 auto;
background-color: red;
}
@media screen and (min-width:1200px){
body{
/*当屏幕大小最小满足1200px即大于1200px的时候 */
/*background-color: pink;*/
}
.container {
width: 1170px;
background-color: pink;
}
}
@media screen and (min-width:992px) and (max-width: 1200px){
.container {
width: 970px;
background: green;
}
}
@media screen and (min-width: 768px) and (max-width: 992px){
.container {
width: 750px;
background-color: blue;
}
}
@media screen and (max-width: 768px){
.container {
width: 100%;
background-color: orange;
}
}
</style>
</head>
<body>
<div class="container"></div>
</body>
</html>

第二种不同终端宽度自适应代码 :代码覆盖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
html,body {
margin: 0 ;
padding: 0;
}
.container {
width: 1200px;
height: 1000px;
margin: 0 auto;
background-color: red;
}
/*以覆盖的方式存在*/
@media (max-width: 768px){
.container {
width: 100%;
background-color: orange;
}
}
@media (min-width: 768px) {
.container {
width: 750px;
background-color: blue;
}
}
@media (min-width:992px) {
.container {
width: 970px;
background: green;
}
}
@media (min-width:1200px){
/*当屏幕大小最小满足1200px即大于1200px的时候 */
/*background-color: pink;*/
.container {
width: 1170px;
background-color: pink;
}
}
</style>
</head>
<body>
<div class="container"></div>
</body>
</html>
1…111213…20
JiM-W

JiM-W

keep fighting!

195 日志
52 分类
90 标签
© 2017 JiM-W
由 Hexo 强力驱动
主题 - NexT.Pisces