前端常见算法和问题
CMD是如何实现同步写法
利用模块的正则匹配,提前把资源文件请求完成,赖执行。
最常用的linux命令
df -h:查看磁盘空间
du -h: 查看文件夹大小
netstat:显示网络状态信息
scp :服务器文件拷贝
crontab:提交和管理用户的需要周期性执行的任务
diff:比较给定的两个文件的不同
find:命令用来在指定目录下查找文件。
tail:在屏幕上显示指定文件的末尾若干行
grep:强大的文本搜索工具
wget:用来从指定的URL下载文件
time:统计给定命令所花费的总时间
free:显示内存的使用情况
top:显示或管理执行中的程序
file:查看文件类型
cat:查看文件内容
pwd:打印当前路径
chmod:改变文件权限,所属用户,所属组,其他人
HTTP原理(一次请求都发生了什么)
敲下回车后,浏览器向dns服务器发起请求,解析域名获得ip,然后想IP地址的服务器器发起请求,经过三次握手建立tcp连接,
js是单线程的
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端
AMD是依赖前置,CMD是依赖就近,Commonjs是同步加载模块,所以适合用在服务器端
input和change事件区别:如果通过dom对象去修改它的value则什么事也不会发生。
混合开发中前端如何跟本地Android通信
WebSetting用处非常大,通过WebSetting可以使用Android原生的JavascriptInterface来进行js和java的通信。
URL解析成对象
function urlArgs() {
var args = {}; // 定义一个空对象
var query = location.search.substring(1); // 查找到查询串,并去掉'? '
var pairs = query.split("&"); // 根据"&"符号将查询字符串分隔开
for (var i = 0; i < pairs.length; i++) { // 对于每个片段
var pos = pairs[i].indexOf('='); // 查找"name=value"
if (pos == -1) continue; // 如果没有找到的话,就跳过
var name = pairs[i].substring(0, pos); // 提取name
var value = pairs[i].substring(pos + 1); // 提取value
value = decodeURIComponent(value); // 对value进行解码
args[name] = value; // 存储为属性
}
return args; // 返回解析后的参数
}
随机生成50个100之间不重复的数
// 如何高效产生m个n范围内的不重复随机数(m<n)
var getRandomNumber = function(n, m){
if(typeof n !== 'number' || typeof m !== 'number'){
throw Error('m和n必须是数字!');
}
if(m >= n){
throw Error('m必须小于n!');
}
var arr = [],
result = [],
i = 0,
j = 0,
tempNumber = 0,
randomNumber = 0;
function selectFrom(lowerValue, upperValue) {
var choices = upperValue - lowerValue + 1;
return Math.floor(Math.random() * choices + lowerValue);
}
for(; i < n; i++){
arr[i] = i;
}
for(; j < m; j++){
randomNumber = selectFrom(j, n - 1);
tempNumber = arr[j];
arr[j] = arr[randomNumber];
arr[randomNumber] = tempNumber;
result.push(arr[j]);
}
return result;
}
console.log(getRandomNumber(100, 50));
假设取50个100范围内的不重复随机数,思路分析:
第1步,为数组的每个数字按其位置(数组的下标)赋值,我们获得一个 100个数字、顺序排列 的数组。
第2步,开始取 i-99 范内的随机数,把每次取到的随机数作为位置(数组的下标)与位置(数组的下标)为 i 的数交换数值。这样做的意义是,将已经取到的随机数在取值范围中排除,下一次仅会在剩下的数字中取随机数。
第2步不太容易理解,举个栗子:假设第一次取到的随机数是39,把 位置39的数 与 位置0的数 交换之后,再从 位置1 开始看该数组,你会惊奇的发现,剩下的是0-99除39以外的所有数字,但它们的位置是1-99,接下来我们仅需要从1-99中取一个随机数,作为数组下标,即可在剩下的数字中取随机数了,以此类推。
判断数组类型
var isArray = Array.isArray || function(o) {
return typeof o === "object" && Object.prototype.toString.call(o) === "[object Array]";
};
随机数生成
Math.floor(Math.random()*(end-start)+start); //{ x | x>=start,x<end,x∈N}
defer和有async的区别
<script async src="script.js"></script>
有async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
<script defer src="myscript.js"></script>
有defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
推荐使用defer
call apply 和 bind 的区别
call是多个参数传参
apply是数组格式传参
bind方法返回的仍然是一个函数,因此后面还需要()来进行调用,参数放在括号里。
.get(),[],.eq() 的区别。
eq返回的是一个jQuery对象,get返回的是一个DOM对象。eq实际上是dom外面包裹一层$,转换成JQuery对象。
成为BFC的条件
一个BFC是一个HTML盒子并且至少满足下列条件中的任何一个:
float的值不为none
position的值不为static或者relative
display的值为 table-cell, table-caption, inline-block,flex, 或者 inline-flex中的其中一个
overflow的值不为visible
根元素
http的content-typ都有哪些
1.text/html
2.text/plain
3.text/css
4.text/javascript
5.application/x-www-form-urlencoded(表单发包形式)
6.multipart/form-data(文件发包形式)
7.application/json
8.application/xml
前面几个都很好理解,都是html,css,javascript的文件类型,后面四个是POST的发包方式。
合并对象的方法
- Object.assign()
var obj = Object.assign(o1, o2, o3);
- JQuery使用$.extend
a = {'a': 1};
b = {'b': 1};
c = $.extend(a, b)
合并数组的方法
- concat
- 使用ES6扩展运算符
var a = [1, 2, 3];
var b = ["a", "b", "c"];
console.log([...a,...b]);
ES6特性
1.函数参数的默认值可以直接放到函数声明里
2.模板对象
3.箭头函数
4.块级作用域和构造let、const
5.解构赋值
6.Symbol类型(独立无二的值)
7.set和map数据结构
8.代理和反射
9.类和对象
10.模块化
vue动态绑定原理
vue原理中defineproperty属性,get和set
js的对象有两种属性: 数据属性和访问器属性。
defineproperty负责修改和创建属性,Vue会遍历实例的data属性,把每一个data都设置为访问器,然后在该属性的getter函数中将其设为watcher,在setter中向其他watcher发布改变的消息。这样,配合发布/订阅模式,改变其中的一个值,会发布消息,所有的watcher会更新自己,这些watcher也就是绑定在dom中的显示信息,比如 v-text=”year” 和 {{ year }} 这些节点。从而达到改变浏dom,在浏览器中实时变化的效果。
gulp/grunt/webpack
1)Gulp / Grunt 可以理解为帮助前端自动化的工具,用于优化前端工作流程。比如自动刷新页面、combo、压缩css、js、编译less等等。二者的区别可以自行百度,个人推荐Gulp。
2)browserify / webpack 提供的是一个前端模块化的方案,和requirejs类似但又有不同。
get和post的区别
GET用于获取查询信息,POST用户更新资源信息
GET数据是明文传输,不安全,POST则把数据放到了http包体内。
GET提交数据有一定限制,POST则没有限制
在后退按钮、书签、缓存方便get都优于post
HTTP协议中的两种发送请求的方法get和post,其实都是基于tcp进行传输,而GET、POST只是不同职能车的一个标签,当然get可以做post的事,反过来也可以,但是GET与POST都有自己的语义,不能随便混用。
最后一点:对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
cookie和session的区别
1.cookie数据存放在客户的浏览器上,session数据放在服务器上。
2.cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3.session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
4.Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。因为Session是用SessionID来确定当前对话所对应的服务器Session,而SessionID是通过Cookie来传递的,禁用Cookie相当于失去了SessionID,也就得不到Session了。
单向数据流和双向绑定
1单向数据流 数据流动方向可以跟踪,流动单一,追查问题的时候可以跟快捷。缺点就是写起来不太方便。要使UI发生变更就必须创建各种action来维护对应的state
2 双向流动 值和UI双绑定,这种好处大家都懂。但是由于各种数据相互依赖相互绑定,导致数据问题的源头难以被跟踪到,子组件修改父组件,兄弟组件互相修改有有违设计原则。 但 好处就是 太特么方便了。
Ajax相关
缺点:
1.破坏了浏览器的后退机制,Gmail采用的解决方法是通过创建一个隐藏的IFRAM搜索数据,实现后退。
2.安全问题
3.破坏了浏览器的异常机制,调试困难。
注意点:如果是 GET/HEAD请求,send()方法一般不传参或传 null。不过即使你真传入了参数,参数也最终被忽略,xhr.send(data)中的data会被置为 null
json转换和遍历##
JSON.parse(jsonstr); //可以将json字符串转换成json对象
JSON.stringify(jsonobj); //可以将json对象转换成json对符串
function showJSON() {
var user = {
"username": "andy",
"age": 20,
"info": {
"tel": "123456",
"cellphone": "98765"
},
"address": [{
"city": "beijing",
"postcode": "222333"
}, {
"city": "newyork",
"postcode": "555666"
}
]
}
alert(user.username);
alert(user.age);
alert(user.info.cellphone);
alert(user.address[0].city);
alert(user.address[0].postcode);
}
url转换为json对象
function parseQueryString(url) {
var obj = {};
var keyvalue = [];
var key = "",
value = "";
var paraString = url.substring(url.indexOf("?") + 1, url.length).split("&");
for (var i in paraString) {
keyvalue = paraString[i].split("=");
key = keyvalue[0];
value = keyvalue[1];
obj[key] = value;
}
return obj;
}
vue组件通信相关
vuex只能用于单个页面中不同组件(例如兄弟组件)的数据流通。
在通信中,无论是子组件向父组件传值还是父组件向子组件传值,他们都有一个共同点就是有中间介质,子向父的介质是自定义事件,父向子的介质是props中的属性。抓准这两点对于父子通信就好理解了.
父组件向子组件传值
1.创建子组件,在src/components/文件夹下新建一个Child.vue
2.Child.vue的中创建props,然后创建一个名为message的属性
3.在App.vue中注册Child组件,并在template中加入child标签,标签中添加message属性并赋值
子组件向父组件通信:
1.在子组件的响应该点击事件的函数中使用$emit来触发一个自定义事件,并传递一个参数
2.在父组件中的子标签中监听该自定义事件并添加一个响应该事件的处理方法
手写一个快速排序算法
function quickSort(arr) {
// 变量
var leftArr = [];
var rightArr = [];
var length = arr.length;// 数组长度
var midIndex = Math.floor(length/2);
var midItem = arr[midIndex];
var nowIndex = null;
if (arr.length <= 1) {
return arr;
} else {
while(length--) {
nowIndex = length;
if (nowIndex !== midIndex) {
if (arr[nowIndex] > midItem) {
rightArr.push(arr[nowIndex]);
} else {
leftArr.push(arr[nowIndex]);
}
}
}
}
return arguments.callee(leftArr).concat([midItem]).concat(arguments.callee(rightArr));
}
quickSort([3,45,6,32,4,24,3,12,76,6]);
手写一个冒泡排序
function bubbleSort(arr) {
var temp;
var length = arr.length;
var time = length;
// 循环次数
while (time--) {
for (var i = 0; i <= time; i++) {
if (arr[i] > arr[i + 1]) {
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
console.log(arr);
}
bubbleSort([2,45,3,324,34,1,23,54,6,7,85,3]);
手写一个二分查找
/**
* 二分查找,递归实现。
*/
function binarySearch(target,arr,start,end) {
var start = start || 0;
var end = end || arr.length-1;
var mid = parseInt(start+(end-start)/2);
if(target==arr[mid]){
return mid;
}else if(target>arr[mid]){
return binarySearch(target,arr,mid+1,end);
}else{
return binarySearch(target,arr,start,mid-1);
}
return -1;
}
/**
* 有序的二分查找,返回-1或存在的数组下标。不使用递归实现。
*/
function binarySearch(target,arr) {
var start = 0;
var end = arr.length-1;
while (start<=end){
var mid = parseInt(start+(end-start)/2);
if(target==arr[mid]){
return mid;
}else if(target>arr[mid]){
start = mid+1;
}else{
end = mid-1;
}
}
return -1;
}
斐波那契数列
// 递归实现方式
public static int fibonacci(int n){
if(n <= 2){
return 1;
}else{
return fibonacci(n-1) + fibonacci(n-2);
}
}
// 递推实现方式
public static int fibonacciNormal(int n){
if(n <= 2){
return 1;
}
int n1 = 1, n2 = 1, sn = 0;
for(int i = 0; i < n - 2; i ++){
sn = n1 + n2;
n1 = n2;
n2 = sn;
}
return sn;
}
数组去重
时间复杂度:o(n^2)
function unique(a){
var len = a.length,item;
while(len--){
item = a.shift();
if(a.indexOf(item)===-1)
a.push(item);
}
return a;
}
时间复杂度O(nlogn)
Array.prototype.uniq = function() {
if(!this.length ||this.length===0){return this;}
this.sort();
var res=[this[0]];
for (var i = 1, len = this.length; i < len; i++) {
if (this[i] !== this[i-1]) {
res.push(this[i]);
}
}
return res;
}
//使用ES6的set
var set =new set(arr);
var res = Array.form(set);
请手写一个简洁的原生ajax
function createXHR() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
var xhr = createXHR();
// onreadystatechange
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status <300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("error:" + xhr.status);
}
}
};
xhr.open("POST", "example.php", "true");
xhr.send("a=1&b=2");
手写一个bind函数
Function.prototype.bind = Function.prototype.bind || function (context) {
var self = this;
return function () {
return self.apply(context, arguments);
}
}
请手写一个拖拽dom
//clientX:鼠标点击位置距离窗口的左边距
//offsetLeft:da:鼠标点击容器距窗口左边距离
var oDiv = document.getElementById('div1');
oDiv.onmousedown = function(ev){
var oEvent = ev||event;
//求出鼠标点击距当前容器的左边距和右边距
var disX = oEvent.clientX - oDiv.offsetLeft;
var disY = oEvent.clientY - oDiv.offsetTop;
document.onmousemove = function(ev){
var oEvent = ev||event;
oDiv.style.left = oEvent.clientX - disX +'px';
oDiv.style.top = oEvent.clientY - disY +'px';
};
document.onmouseup = function(){
document.onmouseup = null;
document.onmousemove = null;
oDiv.releaseCapture&&oDiv.releaseCapture();
};
oDiv.setCapture&&oDiv.setCapture();
return false;
};
};
什么是闭包,解释下闭包以及其应用
答:js中的每一个函数会形成一个作用域,作用域内的函数可以访问同一个作用域里面的变量,并且如果找不到这个变量就会向外层查找,一直找到最外层的作用域,还找不到的就认为这个变量是不存在的。而内部环境可以访问所有的外部环境,但外部环境不能访问内部环境中任何的变量和函数,而且这些变量不会随上一级函数的执行完成而销毁。这属于闭包的应用。
闭包特性也可以用于创建私有函数或方法。
闭包带来的问题:
1.闭包会携带函数作用域,因此会占更多内存。
2.闭包只能取得包含函数中任何变量的最后一个值。
3.闭包会改变this指向,非严格模式下都为window。
this指向受什么影响
三种方式
1.call,apply改变
2.当函数被作为某个对象的方法调用是,this指向那个对象。(这里要注意是如果有多个对象最后一个对象)
3.在没有明确的调用对象情况下this就是window
获取网路图片宽高
一、通过complete与onload一起混合使用
为了测试缓存效果,注意以下测试图片的url都不加时间戳
// 图片地址
var img_url = 'http://www.qttc.net/static/upload/2013/13643608813441.jpg';
// 创建对象
var img = new Image();
// 改变图片的src
img.src = img_url;
// 判断是否有缓存
if(img.complete){
// 打印
alert('from:complete : width:'+img.width+',height:'+img.height);
}else{
// 加载完成执行
img.onload = function(){
// 打印
alert('from:onload : width:'+img.width+',height:'+img.height);
};
}
二、通过定时循环检测获取
看看以下例子,为了避免从缓存里读取数据,每一次请求都带时间戳:
// 图片地址
var img_url = 'http://www.qttc.net/static/upload/2013/13643608813441.jpg?'+Date.parse(new Date());
// 创建对象
var img = new Image();
// 改变图片的src
img.src = img_url;
// 定时执行获取宽高
var check = function(){
document.body.innerHTML += '<div>from:<span style="color:red;">check</span> : width:'+img.width+',height:'+img.height+'</div>';
};
var set = setInterval(check,40);
// 加载完成获取宽高
img.onload = function(){
document.body.innerHTML += '<div>from:<span style="color:blue">onload</span> : width:'+img.width+',height:'+img.height+'</div>';
// 取消定时获取宽高
clearInterval(set);
};
解释下MVP,MVVM
MVP跟MVVM两者原理相似
各部分之间的通信,都是双向的。
View 与 Model 不发生联系,都通过 Presenter 传递。
View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
解释下跨域
一个域名组成由:
- 协议(http://)
- 子域名(www)
- 主域名(baidu.com)
- 端口号(8080)
- 请求资源地址(main/jq.js)
当协议,子域名,主域名,端口号中任意一个不相同时,都算做不同域,需要进行跨域调用(jsonp)
如何使用 iframe 实现跨域
1.document.domain:页面设置相同的主域
2.window.name::ifram作为代理
什么是repaint(重绘)和reflow(重排)
一个页面由两部分组成:
- DOM:描述该页面的结构
- render:描述DOM节点在页面上如何呈现
当 DOM 元素的属性发生变化 (如 color) 时, 浏览器会通知 render 重新描绘相应的元素, 此过程称为repaint。 如果该次变化涉及元素布局 (如 width), 浏览器则抛弃原有属性,重新计算并把结果传递给render 以重新描绘页面元素, 此过程称为 reflow。这两个过程是很耗费浏览器性能的, 因此编写DOM交互时如果不注意就会导致页面性能低下。
如何优化页面性能
1.避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行:
2.集中修改样式
3.文件合并
4.使用CDN服务
5.对图片、代码等资源进行压缩。
减少http请求,使用css spirte,将多个css、js文件进行合并
请用原生方法动态创建一个img元素
//创建节点
var img = document.createElement("image");
img.url="";
//添加属性
img.alt = "我是图片"
document.body.appendChild(img);
请列举数组以及字符串常用的处理方法
Array常用方法
- pop - push - shift - unshift - splice
- sort - reverse
- slice
- join
String常用方法
- charAt - indexOf - lastindexOf
- search - match -repalce
- substr - substring - slice
- split
大小写转换方法
- toLocalLowerCase()把字符串转换为小写
- toLocalUpperCase()把字符串转换为大写
- toLowerCase()把字符串转换为小写
- toUpperCase()把字符串转换为大写
12和34是相对应的,只是特定于一些语言的区别。
ajax的四种状态
0:未初始化。尚未调用open()方法。
1:启动。open调用
2:发送。已经调用send()方法,但尚未调用send()方法
3:接收。已经收到部分相应数据。
4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
点击ul的每一条输出对应的index
<ul id="test">
<li>这是第一条</li>
<li>这是第二条</li>
<li>这是第三条</li>
</ul>
考察点:闭包!!!
var lis = document.getElementsByTagName(li);
for(var i = 0, len = lis.length; i < len; i++){
lis[i].onclick = (function(index){
return function(){
alert(index);
}
})(i);
}
封装一个事件监听函数
function addListener(el,type,listener){
if(el.addEventListener){
addListener = function(el,type,listener){
el.addEventListener(type,listener,false);
}
} else if(el.attchEvent){
addListener = function(el,type,listener){
el.attachEvent('on'+type,function(){
//处理attachEvent事件处理函数的作用域问题
listener.call(el);
});
}
} else {
addListener = function(el,type,listener){
el['on' + type] = listener;
}
}
//绑定事件,第一次才会执行
addListener(el,type,listener);
}
给String对象的每一个字符添加一个空格
function add(s){
return s.replace(/\s+/g,"").split('').join(' ');
}
add("hello world");
定义一个log方法,让它可以代理console.log的方法
function log(){
return console.log.apply(console,arguments);
}
在JavaScript中什么是伪数组?
NodeList,HTMLCollection,arguments,可以向数组一样的遍历,但是却不能使用数组的方法。
function toArray(obj){
return Array.prototype.slice.call(obj);
}
对作用域上下文和this的理解,看下列代码:
var User = {
count: 1,
getCount: function() {
return this.count;
}
};
console.log(User.getCount());// what?
var func = User.getCount;
console.log(func()); //what?
第一个输出:1,作用域是User 第二个输出:undefined,作用域是全局,而全局作用域里没有count变量
那么如何确保User总是能访问到func的上下文,确保返回1
Function.prototype.bind = Function.prototype.bind || function(context){
var self = this;
return function(){
self.apply(context,arguments);
}
}
var fnc = User.getCount.bind(User);
位操作符实现浮点数转整数
function convertToInt(num) {
return num >> 0;
}
convertToInt(-Math.PI); // -3
convertToInt(12.921); // 12
同理,num | 0也是可以的。
函数柯里化问题
//要求实现sum函数如下:
sum(1) // 1
sum(1)(2) // 3
sum(1)(2)(3) // 6
function sum(item) {
var cur = item;
var inner = function(next) {
if (next != null) cur += next;
return inner;
};
inner.toString = function() {
return cur;
}
return inner;
}
判断一个字符串中出现次数最多的字符,并统计这个次数
var arr = "aaaaabbbc".split("");
var obj = {};
var length = 0;
var str;
arr.forEach( function(value, key) {
if (value in obj) {
obj[value] ++;
} else {
obj[value] = 0;
}
})
for (var key in obj) {
if (length <= obj[key]) {
length = obj[key];
str = key;
}
}
console.log(key);
console.log(length);
JS中的继承
组合继承
// 父类
function Father(name) {
this.name = name;
}
Father.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Father.call(this, name); // 第二次调用Father
this.age = age;
}
方法1:
Child.prototype = new Father();// 第一次调用Father,为了避免父类的构造函数在类定义过程中的潜在影响,我们一般会建造一个临时类去做代替父类 new 的过程。
方法2:
Child.prototype = Object.create(Father.prototype)
Child.prototype.constructor = Child
Son.prototype.sayAge = function() {
console.log(this.age);
};
var son1 = new Son("Bob", 23);
JavaScript内存回收机制
-
引用计数垃圾收集
缺点:无法解决循环引用问题 -
标记-清除算法
缺点:那些无法从根对象查询到的对象都将被清除
函数防抖和函数节流
- 函数防抖
当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间 - 函数节流
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期
函数节流与 函数防抖都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
浏览器缓存方式
promise问题
Promise是为解决函数金字塔问题
var taskA = function() {};
var taskB = function() {};
var taskC = function() {};
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.then(taskC)
.catch(function() {
console.info("the End");
});
Promise的状态
从Promise模式的角度看,完成一个任务,可分成3种状态。
pending - 未完成,准备状态
resolve 任务成功时调用
reject 任务失败时调用
Promise的状态转化只发生一次(从pending变成resolve或变成reject),即状态会被凝固,不再改变。从这点看来,Promise似乎非常适合异步操作,比如浏览器加载一张图片,要么加载成功(resolve),要么加载失败(reject)。
XML和JSON的优缺点对比
XML是扩展标记语言
JSON一种轻量级的数据交换格式
(1).可读性方面。
JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些。
(2).可扩展性方面。
XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
(3).编码难度方面。
XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
(4).解码难度方面。
XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
(5).流行度方面。
XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。
(6).解析手段方面。
JSON和XML同样拥有丰富的解析手段。
(7).数据体积方面。
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
(8).数据交互方面。
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。
(9).数据描述方面。
JSON对数据的描述性比XML较差。
(10).传输速度方面。
JSON的速度要远远快于XML。
【事件的代理/委托】的原理以及优缺点
事件代理是靠事件的冒泡机制来实现的,优点是:
1、可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒
2、可以实现当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适
缺点是可能会造成误判。
[编程题] 判断链表是否有环
分析:通过两个指针,分别从链表的头节点出发,一个每次向后移动一步,另一个移动两步,两个指针移动速度不一样,如果存在环,那么两个指针一定会在环里相遇。
代码如下:
//判断单链表是否存在环,参数circleNode是环内节点,后面的题目会用到
bool hasCircle(Node *head,Node *&circleNode)
{
Node *slow,*fast;
slow = fast = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
circleNode = fast;
return true;
}
}
return false;
}
[编程题] 输出二叉树的最小深度
将二叉树分为这么几种情况:
传入的根节点为空,返回NULL;
传入根节点不为空,左子树为空,右子树为空,返回最小深度1;
传入根节点不为空,左子树为空,右子树不为空,返回右子树的最小深度+1;
传入根节点不为空,左子树不为空,右子树为空,返回左子树的最小深度+1;
传入根节点不为空,左右子树都不为空,则返回左右子树中最小深度的较小值+1.