未分类

实习招聘面试经历-2

Experiment Of a Boy

1. Angular双向绑定的实现

嗯…面试三次,每个面试官都会问我这个问题,这里还是贴一下参考的文章吧:
Angular沉思录(一) 数据的双向绑定
AngularJS 数据双向绑定揭秘
简易实现版本:

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
52
53
54
55
56
57
58
59
60
61
62
63
var Scope = function () {
this.$$watchers = [];
}
Scope.prototype.$watch = function( watchExp, listener ) {
this.$$watchers.push( {
watchExp: watchExp,
listener: listener || function () {}
});
};
Scope.prototype.$digest = function() {
var dirty;
do {
dirty = false;
for (var i = this.$$watchers.length - 1; i >= 0; i--) {
var newValue = this.$$watchers[i].watchExp(),
oldValue = this.$$watchers[i].last;
if( oldValue !== newValue) {
this.$$watchers[i].listener(newValue, oldValue);
dirty = true;
this.$$watchers[i].last = newValue;
}
};
} while(dirty);
};
var $scope = new Scope();
$scope.name = 'Ryan';
$scope.$watch(function () {
return $scope.name;
}, function ( newValue, oldValue ) {
console.log('Input Value has update:' + newValue + ' and Old Value is: ' + oldValue);
element[0].value = newValue;
tips.innerHTML = newValue
});
/** 视图到模型 **/
var element = document.querySelectorAll('input'),
tips = document.querySelectorAll('#tips')[0];
element[0].addEventListener('keyup', function () {
$scope.name = element[0].value;
$scope.$digest();
})
/** 模型到视图 **/
var updateScopeValue = function () {
$scope.name = 'Bob';
$scope.$digest();
}
var btn = document.getElementsByTagName('button')[0];
btn.addEventListener('click', function () {
updateScopeValue();
})

自己又在纸上仔细捋了一遍,发现之前面试说的还是有些不太对的地方:

  • $$watch存放的不只是模型,准确来说是一个对象数组,每个对象存储着需要监控的变量和更新时执行的监听函数
  • $digest是遍历$$watch,发现数据脏了就执行$$watch里的对应的监控的变量的监听函数
  • 在监听函数里将数据绑定到界面上,实现模型->视图
  • 视图到模型的更新通过监听事件,直接设置value

jQuery和Zepto的区别

  1. jQuery: 历史悠久,对PC端友好,体积相对于Zepto过大,但有丰富的插件支持和社区支持
  2. Zepto: 专门为移动端定制,比如tap事件,体积小,一些功能没有jQuery那么完善,不支持链式调用,不支持高级选择器(可以用原生选择器再包装),插件比较少,和jQuery不兼容

贴一篇文章: zepto和jquery的区别,zepto的不同使用8条小结
啊,属性选择器是支持的=.= 之前一直以为不支持:

  1. Zepto 的选择器表达式: [name=value] 中value 必须用 双引号 “ or 单引号 ‘ 括起来
    例如执行:$(‘[data-userid=123123123]’)
    结果:Error: SyntaxError: DOM Exception 12
    
    解决办法: $(‘[data-userid=”123123123]”‘) or $(“[data-userid=’123123123’]”)

觉得其他比较明显的不同是:

  • 不能自定义事件;但可以:$('').bind('my', function(){});
  • 选择selectedcheckedprop方法
    其他在上面的文章写的挺清楚的.但是一般还是用了jQuery了哈哈哈

JavaScript原生事件

感觉自己运气真好..面试前有比较仔细的看了这部分.看的是红色的那本JavaScript高级程序设计,讲的很明白很透彻:

事件流

从页面中接受事件的顺序
IE:事件冒泡
Netscape:事件捕获
DOM事件流: 捕获阶段,处于目标阶段,事件冒泡阶段(高版本浏览器会在捕获阶段触发事件)

事件处理程序

  1. HTML事件,函数有局部变量event,this等于事件目标元素;紧密耦合,时差问题
  2. DOM0级,btn.onclick = function () {};this引用当前元素,在冒泡阶段处理,删除通过 btn.onclick = null;
  3. DOM2级,addEventListener,第三个参数:true:捕获阶段调用,false:冒泡阶段调用;可以添加多个处理程序,按顺序触发,this指向当前元素,用false兼容大部分浏览器
  4. IE:attachEvent,冒泡,作用域为全局作用域,this为window,顺序相反

事件对象

  1. DOM&HTML: event对象:this指向currentTarget,target包含事件的实际目标;用type处理多个事件;eventPhase确定处于哪个阶段,从1开始
  2. IE:DOM0级:window.event,attach:event。用event.srcElement比较保险(attach中this是window);阻止:returnValue = false;cancelBubble = false

如何改变this的指向

面试的时候想到了函数绑定bind.面试官让我写出来=.=啊当时就比较慌了.想了一下,觉得还是说自己会的就好,就说了用apply或者call来实现.后面翻了一下书也确实是这么写的:

1
2
3
4
5
function bind(fn, context) {
return function () {
return fn.apply(context, arguments);
};
}

函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数.该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同事保留代码执行环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var handler = {
message: "Event handled",
handleClick: function (event) {
alert(this.message);
}
};
var btn = document.getElementById('my-btn');
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));
//Event handled
//ES5:
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));

只要是将某个函数指针以值的形式进行传递,同时该函数必须在特定环境中执行,就需要这个绑定函数.

需要克隆元素并绑定之前所有的事件/移除一个元素所有绑定的事件/让事件执行的顺序都相同?

这个之前没想过,但是有看到一篇文章说这个.
感觉是会维护一个数组,数组保存着所有用户自己定义的事件,然后克隆的时候直接遍历这个数组绑定事件/移除事件.让事件执行顺序相同就根据浏览器(IE),逆序绑定事件达到所有事件执行顺序都相同.
说是这么说,也不知道是不是真的这么干,明天查查资料.断网啦睡觉啦.~~

Node的IO的了解

这个真不了解=.= 下面摘抄自<<深入浅出Nodejs>>

在Node中,除了JavaScript是单线程外,Node自身其实是多线程的,只是I/O线程使用的CPU较少.另一个需要重视的观点是,除了用户代码无法并行执行外,所有的I/O(磁盘I/0和网络I/O)则是可以并行起来的.

Node的执行模型包括:事件循环,观察者,请求对象,I/O线程池
JavaScript的代码通过调用C++核心模块进行下层的操作.
从JavaScript调用Node的核心模块,核心模块调用C++内建模块,内建模块通过libuv进行系统调用;libuv有两个平台的实现,实际上调用uv_fs_open()方法;
在uv_fs_open()调用过程中,创建了一个FSReqWrap请求对象,JS层传入的参数和方法都封装在这个请求对象中,回调函数是oncomplete_sym:
req_wrap->object_->Set(oncomplete_sym, callback);
包装完毕后,Windows下调用QueueUserWorkItem()将这个FSReqWrap对象推入线程池中等待执行.
至此,由JavaScript层面发起的异步调用第一阶段就此结束.JavaScript线程可以继续执行当前任务的后续操作,I/O操作就在线程池中等待执行.达到异步的目的.
执行回调:线程池中的IO操作调用完毕后,通过PostQueuedCompletionStatus()通知IOCP(IO完成端口),提交执行状态,并将线程归还线程池.
这个过程中,事件循环的IO观察者都会检查线程池中是否有执行完的请求,如果存在,将请求对象加入队列,作为事件处理.
IO观察者的回调函数就是取出请求对象的result属性作为参数,oncomplete_sym作为方法,调用执行.达到调用JavaScript中传入的回调函数的目的.
有张图好想贴上来!!就在书上~~ 看多几遍大概了解这个工作流程了.

## Cookie与Session的区别

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上;
  2. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session;
  3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE;
  4. 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K;

参考文章:理解Cookie和Session机制

分享到