You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functioninstance_of(a,b){varbPrototype=b.prototype;// 取 b 的显示原型a=a.__proto__;// 取 a 的隐式原型while(true){if(a===null)returnfalse;if(bPrototype===a)returntrue;a=a.__proto__;}}
示例:
// 为了方便表述,首先区分左侧表达式和右侧表达式FooL=Foo,FooR=Foo;// 下面根据规范逐步推演O=FooR.prototype=Foo.prototypeL=FooL.__proto__=Function.prototype// 第一次判断O!=L// 循环再次查找 L 是否还有 __proto__ L=Function.prototype.__proto__=Object.prototype// 第二次判断O!=L// 再次循环查找 L 是否还有 __proto__ L=Object.prototype.__proto__=null// 第三次判断L==null// 返回 false
functionSuperType(){this.colors=["red","blue","green"];}functionSubType(){//inherit from SuperTypeSuperType.call(this);}varinstance1=newSubType();instance1.colors.push("black");alert(instance1.colors);//"red,blue,green,black"varinstance2=newSubType();alert(instance2.colors);//"red,blue,green"
组合继承:
超类型的原型中定义的方法对子类型不可见,也不能函数复用,因为每次 new 都会创建新的函数。所以采用组合继承。
var createAssigner = function (keysFunc, undefinedOnly) {
return function (obj) {
//...
keys = keysFunc(source)
//...
return obj;
};
};
createAssigner(allKeys)(a, b)
createAssigner(keys)(c, b)
document.getElementById("parent-list").addEventListener("click",function(e){if(e.target&&e.target.nodeName=="LI"){console.log("List item ",e.target.id.replace("post-")," was clicked!");}});
<body><imgdata-src="http://farm8.staticflickr.com/7060/6969705425_0905bf6bba_o.jpg"src="blank.gif"class="lazy"><script>
!function (window) {functionloadImage(el){varimg=newImage();varsrc=el.getAttribute('data-src');img.onload=function(){if(!!el.parent)el.parent.replaceChild(img,el)elseel.src=src;};img.src=src;}functionelementInViewport(el){varrect=el.getBoundingClientRect();return(rect.top>=0&&rect.left>=0&&rect.top<=(window.innerHeight||document.documentElement.clientHeight))}
var images = [];
var $img = $q('img.lazy');
var processScroll = function () {for(vari=0;i<images.length;i++){if(elementInViewport(images[i])){loadImage(images[i]);}}};for(vari=0;i<$img.length;i++){images.push($img[i]);}processScroll();addEventListener('scroll',processScroll);}(window)
</script></body>
varevents=(function(){vartopics={};return{publish: function(topic,info){console.log('publish a topic:'+topic);if(topics.hasOwnProperty(topic)){topics[topic].forEach(function(handler){handler(info ? info : {});})}},subscribe: function(topic,handler){console.log('subscribe a topic:'+topic);if(!topics.hasOwnProperty(topic)){topics[topic]=[];}topics[topic].push(handler);}}})();//主题监听函数varhandler=function(info){console.log(info);};//订阅hello主题events.subscribe('hello',handler);//发布hello主题events.publish('hello','hello world');
思路:使用一个队列来维护任务列表,通过返回 this 来实现链式调用,为了在任务队列中先 push 完所有任务然后再依次执行,添加上 setTimeout 函数
function_LazyMan(name){this.tasks=[]var_this=thisvarfn=(function(){console.log(`Hi! This is ${name}!`)_this._next()})this.tasks.push(fn)setTimeout(function(){_this._next()},0)}_LazyMan.prototype._next=function(){varfn=this.tasks.shift()fn&&fn()}_LazyMan.prototype.eat=function(name){var_this=thisvarfn=(function(){console.log(`Eat ${name}`)_this._next()})this.tasks.push(fn)returnthis}_LazyMan.prototype.sleep=function(time){var_this=thisvarfn=(function(){setTimeout(function(){console.log(`Wake up after ${time} s`)_this._next()},time*1000)})this.tasks.push(fn)returnthis}_LazyMan.prototype.sleepFirst=function(time){var_this=thisvarfn=(function(){setTimeout(function(){console.log(`Wake up after ${time} s`)_this._next()},time*1000)})this.tasks.unshift(fn)returnthis}functionLazyMan(name){returnnew_LazyMan(name)}LazyMan('GGG').sleep(3).eat('milk').eat('fish').sleep(2).eat('water').sleepFirst(2)
varmemoize=function(func){varcache={};returnfunction(key){if(!cache[key])cache[key]=func.apply(this,arguments);returncache[key];}}varfibonacci=memoize(function(n){returnn<2 ? n : fibonacci(n-2)+fibonacci(n-1);});
functionlist(){returnArray.prototype.slice.call(arguments);}varlist1=list(1,2,3);// [1, 2, 3]// Create a function with a preset leading argumentvarleadingThirtysevenList=list.bind(undefined,37);varlist2=leadingThirtysevenList();// [37]varlist3=leadingThirtysevenList(1,2,3);// [37, 1, 2, 3]
介绍JavaScript的基本数据类型
6种原始数据类型
Undefined、Null、Boolean、Number 和 String
和对象类型 Object
ES6 新增 Symbol
保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。
介绍JavaScript有哪些内置对象?
Object 是 JavaScript 中所有对象的父对象
数据封装类对象:Object、Array、Boolean、Number 和 String
其他对象:Function、Arguments、Math、Date、RegExp、Error
JavaScript有几种类型的值?,你能画一下他们的内存图吗?
在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。
原始值
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
引用值
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
如何将字符串转化为数字,例如'12.3b'?
parseFloat('12.3b');
JavaScript原型,原型链 ? 有什么特点?
1.JavaScript 不包含传统的类继承模型,而是使用prototype原型模型。
2.函数的
prototype
属性指向函数的原型对象。3.每个对象都有一个
__proto__
属性,指向函数的原型对象4.每个对象都有一个指向它原型对象的链接。这个原型对象又有自己的原型,直到Object.prototype,它的的原型为 null 为止,组成这条链的最后一环,这种一级一级的链结构就称为原型链)。
5.当查找一个对象的属性时,会向上遍历原型链,直到找到给定名称的属性为止
先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,Function和Object和其它构造函数继承Function.prototype而产生。
详见博客:图解原型链
typeof 和 instanceof
typeof 操作符(和 instanceof 一起)或许是 JavaScript 中最大的设计缺陷, 因为几乎不可能从它们那里得到想要的结果。
typeof
大多数情况下都返回object
建议使用:
instanceof:
每个对象都有一个
__proto__
属性,指向创建该对象的函数的 prototype,即原型对象实例的
__proto__
链和构造函数的 prototype 是不是指向同一个原型对象示例:
JavaScript创建对象的几种方式?
1.对象字面量
2.工厂模式
缺点是无法知道对象的类型
3.构造函数模式
缺点是在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域名不副实
4.原型模式
5.组合使用方式
JavaScript如何实现继承?
许多OO语言支持接口继承和实现继承。
js只支持依靠原型链的实现继承。
原型继承->引用类型值被所有实例共享->构造函数继承->超类原型中定义的方法对子类不可见,也不能函数复用->组合继承
原型继承:
原型链继承的问题:
1.引用类型值被所有实例共享
2.创建子类型的实例时,不能在不影响所有实例的情况下向超类型的构造函数中传递参数。
为解决引用类型值被共享的问题,可使用构造函数继承,(在Sub上Super中的对象初始化代码)
组合继承:
超类型的原型中定义的方法对子类型不可见,也不能函数复用,因为每次 new 都会创建新的函数。所以采用组合继承。
Javascript作用链域?
JavaScript 是一个单线程语言,意味着同一时间只能执行一个任务, 它首先默认进入全局执行环境,执行上下文定义了变量或函数有权访问的其它数据
可以将每个执行上下文抽象为一个对象并有三个属性:
每次你试图访问函数执行上下文中的变量时,总是从自己的变量对象开始查找,如果没找到,将继续搜索作用域链,检查每一个执行上下文的变量对象,去寻找匹配的值
JavaScript中的作用域和执行上下文
谈谈this的理解。
1.在全局运行上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下。
2.直接调用函数,this的值会默认设置为全局对象,在严格模式下,this将会默认为undefined
3.当以对象里的方法的方式调用函数时,它们的 this 是调用该函数的对象.
当 o.f() 被调用时,函数内的this将绑定到o对象。
4.当一个函数被作为一个构造函数来使用(使用new关键字),它的this与即将被创建的新对象绑定。
5.call 和 apply 都是为了改变某个函数运行时的上下文
.call() 和 .apply() 的区别?
call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
bind()方法会创建一个新函数,、第一个参数作为 this,第二个以及以后的参数加上新函数调用时传入的参数按照顺序作为原函数的参数。
详见博客JavaScript call() , apply() , bind()方法
setTimeout
一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。当栈为空时,从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数。当栈再次为空的时候,也就意味着消息处理结束。
setTimeout 函数会在一个时间段过去后在队列中添加一个消息。如果有其它消息,setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少的时间 而非确切的时间。
同步和异步的区别,如何实现异步编程?
同步:如果在函数A返回的时候,调用者就能够得到预期结果(即拿到了预期的返回值或者看到了预期的效果),那么这个函数就是同步的。
异步:如果在函数A返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那么这个函数就是异步的。
回调函数
回调函数使用简单,容易理解,缺点就是存在耦合也容易造成 callback hell。
事件监听
事件监听模式中,任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
从本质上说,事件监听也是一种观察者模式。
观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
详见后文
Promise
详见后文
Async + Await
详见后文
RxJS
详见后文
详见博客:浅谈JavaScript中的异步编程
什么是闭包(closure),为什么要用它?
内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回了之后。换句话说,这些函数可以记忆它被创建时候的环境。
词法作用域关心的是函数在哪里声明的
应用:
1.每次触发自执行函数时,都相当于将当前循环的变量i存储了下来
2.管理私有变量和私有方法
3.将代码封装成一个闭包形式,合适的时候再使用,比如实现柯里化(是一种实现多参数函数的方法),createAssigner 返回了一个函数,这个返回的函数引用了外面的一个变量。
初识JavaScript闭包
eval是做什么的?
eval()函数执行表示为字符串形式的JavaScript代码。
避免在不必要的情况下使用eval eval() 是一个危险的函数, 你的代码可能被恶意方在使用方的机器上使用恶意代码。
LINK
什么是window对象? 什么是document对象?
BOM(浏览器对象模型)的核心对象是window,它既是通过js访问浏览器窗口的接口,又是ecmascript规定的global对象
document对象是HTMLDocument的一个实例,表示整个html页面,也是window对象的一个属性。
null,undefined 的区别?
使用var声明但未初始化时,变量值为undefined。
null表示一个空对象指针。
没有必要声明一个值为undefined,但是可以保存为null以体现null作为空指针的惯例。
http://bonsaiden.github.io/JavaScript-Garden/zh/#core.undefined
写一个通用的事件函数
事件是?IE与Netscape的事件机制有什么区别?
js和html之间的交互是通过事件实现的,就是文档和浏览器窗口中发生的一些交互瞬间。
IE的事件流为事件冒泡
Netscape的事件流为事件捕获(很少使用)
讲一讲事件委托机制
为解决事件处理程序过多问题,事件委托利用事件冒泡机制,指定一个事件处理程序,管理某一类型的所有事件。如:click会一直冒泡到document层次。
stopPropagation和preventDefault
stopPropagation()
有时我们希望事件在特定节点执行完之后不再传递,可以使用事件对象的
stopPropagation()
方法preventDefault()
阻止将要执行的浏览器默认动作
JavaScript 代码中的"use strict";是什么意思 ? 使用它区别是什么?
ECMAScript5 引入严格模式,
如何判断一个对象是否属于某个类?
var a = new A();a instance A
不一定返回true,见例子
new 操作符具体干了什么?
当代码 new Foo(...) 执行时:
1.一个新对象被创建。它继承自Foo.prototype.
foo.__proto__ === Foo.prototype
2.构造函数 Foo 被执行。执行的时候,相应的传参会被传入,同时this会被指定为这个新实例。
3.如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象,
JavaScript中哪一个函数,执行时对象查找时,永远不会去查找原型?
hasOwnProperty() 检测一个属性是存在于实例中,还是存在于原型中
JS延迟加载的方式有哪些?
defer和async、动态创建DOM方式(用得最多)、按需异步载入js
图片延迟加载
图片延迟加载
单页应用原理
谈一谈你对ECMAScript6的了解?
箭头函数
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
上面代码中,setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到100毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。
Class
Class 是基于原型继承的语法糖
类似于
Template Strings 模板字符串
http://babeljs.io/learn-es2015/
谈谈你对 ES6 新的声明变量的方式的一些看法
let
1.let声明的变量拥有块级作用域;ES5 只有全局作用域和函数作用域,没有块级作用域
2.var命令会发生”变量提升“现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错
const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const 声明的是常量,真的不能被改变吗?
你提到了 Set 类型,那你讲下对 Es6 里 Map 类型的看法。
Set
它类似于数组,但是成员的值都是唯一的,没有重复的值
Map
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
模块化编程怎么做,AMD、CMD规范区别?
1.简单的模块:函数 ->
2.闭包,IIFE 模式->
3.CommonJS 规范加载模块是同步的,只有加载完成,才能执行后面的操作。
4.AMD 规范则是非同步加载模块,允许指定回调函数, 推崇依赖前置,提前执行,在定义模块的时候就引入了其他模块,在模块当中已经是可用状态。
5.CMD提倡依赖就近,在需要使用到某个模块的时候,才进行引入。->
6.Webpack 是一个用于现代 JavaScript 应用的模块打包器(module bundler),它能够分析你的项目结构,找到 JavaScript 模块以及一些浏览器无法运行的语言(Scss,TypeScript等),并将其打包成合适的格式供浏览器使用。->
7.ES6 模块
模块化用于解决解决命名冲突与文件依赖
LINK
详见博客JavaScript的模块化编程
函数声明和函数表达式
JavaScript 中存在变量声明被**提升(hoisting)**的机制,变量(函数)的声明会被提升到作用域的最前面
documen.write和 innerHTML的区别
document.write 只能重绘整个页面
innerHTML 可以重绘页面的一部分
DOM操作?
内存泄漏?
IE 6, 7 使用引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄露。引用计数的含义是跟踪记录每个值被引用的次数,赋值时+1,引用这个值的变量又取得另一个变量引用次数-1
标记-清除算法给所有变量加上标记,然后去掉环境中的变量和变量引用的变量,此后销毁带标记的值。
从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。
polyfill 方案?
Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。MDN
indexOf() 方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。MDN
详见博客Underscore.js 源码学习笔记
设计模式
单例模式
一个类只能有一个实例化对象
简单工厂模式
工厂模式创建对象(视为工厂里的产品)时无需指定创建对象的具体类,可以把所有实例化的代码都集中在一个位置
观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者同时监听一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者
责任链模式
是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止
建造者模式可以将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
公钥加密和私钥加密。
公开密钥加密 也称为非对称加密,需要一对密钥,一个是私人密钥,另一个则是公开密钥。这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。
RSA是常见的公钥加密算法。
对称密钥加密 又称为私钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。实务上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通讯联系。与公开密钥加密相比,要求双方取得相同的密钥是对称密钥加密的主要缺点之一。
常见的对称加密算法有 DES、3DES、AES 等
creeperyang/blog#1
AJAX 是什么? 如何创建一个AJAX?
Asynchronous JavaScript + XML ,无需刷新页面就可以从服务器取得数据的技术。核心是XMLHttpRequest对象。
GET:
POST:
Ajax 解决浏览器缓存问题?
url加上随机数或者时间戳
LINK
200 memory from cache 和 304
200 memory from cache 是不向浏览器发送请求,直接使用本地缓存文件。
304,浏览器虽然发现了本地有该资源的缓存,但是不确定是否是最新的,于是想服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304。
http状态码有那些?分别代表是什么意思?
200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。
403 Forbidden 服务器已经理解请求,但是拒绝执行它。
404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。
500 Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。
请你说说 get 和 post的区别
GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源
GET 相对 POST 的优势是:
请求中的 URL 可以被手动输入;
请求中的 URL 可以被存在书签里,或者历史里;
请求中的 URL 可以被缓存;
详见博客理解HTTP协议
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
1.输入地址
2.浏览器查找域名的 IP 地址,这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...
3.浏览器向 web 服务器发送一个 HTTP 请求
4.服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
5.浏览器跟踪重定向地址
6.服务器处理请求
7.服务器返回一个 HTTP 响应
8.浏览器显示 HTML
9.浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
10.浏览器发送异步请求
如何解决跨域问题?
默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源(协议,端口和主机都相同)
CORS
简单请求
只使用 GET, HEAD 或者 POST 数据类型(Content-Type)是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain 中的一种
非简单请求(预请求)
请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。
不同于简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。
JSONP
JSONP利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 JavaScript
详见博客:CORS 跨域资源共享
CSRF 和 XSS
CSRF(跨站域请求伪造)是一种网络的攻击方式,其原理是攻击者构造接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。
防御CSRF
1.HTTP Referer 字段;
2.在请求地址中添加 token 并验证。CSRF 是因为攻击者可以完全伪造用户的请求,请求中的信息都是存在于 cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。而token可以不存在cookie中。
详见博客:CSRF 与 XSS 攻击
XSS
跨站脚本(XSS)是一种安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
Web 应用未对用户提交请求的数据做充分的检查过滤,允许用户在提交的数据中掺入 HTML 代码(最主要的是>、<),并将未经转义的恶意代码输出到第三方用户的浏览器解释执行,是导致XSS漏洞的产生原因。
防御 XSS 攻击最主要的方法是过滤特殊字符,进行 HTML 转义。
Socket 和 Websocket
1.HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
2.但是一个request只能有一个response。而且这个response是被动的,不能主动发起。
实现实时信息传递:
1.ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息
3.Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手
LazyMan
思路:使用一个队列来维护任务列表,通过返回 this 来实现链式调用,为了在任务队列中先 push 完所有任务然后再依次执行,添加上 setTimeout 函数
详见博客:如何实现一个LazyMan
数组去重
ES5:
ES6:
数组降维
多维数组
如何实现数组的随机排序?
详见博客:数组乱序
类数组转为数组
JS是按值传递还是按引用传递?
按值传递(call by value):函数的形参是被调用时所传实参的副本(内存副本)。修改形参的值并不会影响实参。
按引用传递(call by reference):函数的形参接收实参的隐式引用(内存指针),而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改,两者指向相同的值。
JS中的基本类型按值传递,对象类型按共享传递的(call by sharing)。调用函数传参时,函数接受对象实参引用的副本(引用的拷贝)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。
浅复制和深复制
首先深复制和浅复制只针对像Object,Array这样的复杂对象的。
浅复制:复制引用,所有引用对象指向同一数据,只复制一层对象的属性
深复制:递归复制了所有层级
详见博客:浅复制和深复制
函数式编程
函数即不依赖外部的状态也不修改外部的状态(没有副作用),函数调用的结果不依赖调用的时间和位置,只要给定输入参数,返回的结果必定相同(引用透明),这样写的代码容易进行推理,不容易出错
详见博客:浅谈函数式编程
尾调用
尾调用(Tail Call)是函数式编程里的一个重要概念,它是指某个函数的最后一步是调用另一个函数。
用尾递归的方式来优化斐波那契数列,可以避免栈溢出(stack overflow)
详见博客:JavaScript 中的尾调用
单元测试
单元测试关注的是验证一个模块或一段代码的执行效果是否和设计或预期一样。
mocha 摩卡
chai
Java和JavaScript对比
webpack和gulp对比
http://www.jianshu.com/p/42e11515c10f
Promise
为了解决callback hell,
所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
RxJS
RxJS 是用来解决异步和事件组合问题
Observable = 异步数组 = 数组 + 时间轴 = stream
Async + Await
async
函数是 Generator 函数的语法糖,返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句对比:
可以看出 RxJS 对于这类数据可以做一种类似流式的处理,也是非常优雅,而且 RxJS 强大之处在于你还可以对数据做取消、监听、节流等等的操作
Observable Object 中有
toPromise
方法,可以返回一个 Promise Object,同样可以结合await
使用。当然你也可以只使用 async/await 配合 underscore 或者其他库,也能实现很优雅的效果。总之,RxJS 与 async/await 不冲突。TypeScript
TypeScript 是 JavaScript 的强类型版本。然后在编译期去掉类型和特有语法,生成纯粹的 JavaScript 代码。TypeScript 并不依赖于浏览器的支持,也并不会带来兼容性问题。
TypeScript 是 JavaScript 的超集。
优点:
静态类型检查,编译器发现错误;
IDE智能提示;
可读性;
Vue2原理,Angular2原理 ?
Vue 中如果对象属性的添加或删除无法被检测到,那么你有什么解决方案?
受现代 JavaScript 的限制(以及废弃
Object.observe
),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行getter/setter
转化过程,所以属性必须在data
对象上存在才能让 Vue 转换它,这样才能让它是响应的。Vue.set(vm.someObject, 'b', 2)
Underscore和Zepto源码
1.Object.prototype.toString.call() 判断类型
2.函数去抖与函数节流
函数去抖就是对于一定时间内的连续的函数调用,只让其执行一次。核心思想是重复添加定时器。
函数节流是指一个函数在一定间隔内调用,目的是让一个函数不要执行得太频繁。
3.函数记忆
原理非常简单,就是把函数的每次执行结果都放入一个散列表中,在接下来的执行中,在散列表中查找,如果有,直接返回该值,没有才执行函数。
详见博客:Underscore.js 源码学习笔记
柯里化与偏函数
函数柯里化的本质是,可以在调用一个函数的时候传入更少的参数,而这个函数会返回另外一个函数并且能够接收其他参数。是一种实现多参数函数的方法。
偏函数应用到了 bind ,他解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值。
前端性能优化的方法(JS/CSS)?
1.减少/最小化 http 请求数
2.延迟加载组件
3.使用CDN
4.加Expires或者Cache-Control头部
5.传输时用gzip等压缩组件
6.把样式放在顶部
7.把脚本放到底部
8.压缩JS和CSS
Vue 和 Angular 区别 如何选择?
JavaScript有什么吸引你的地方?
1.单线程事件轮询是个很适合异步并发的模型,因为避免了在程序内部管理多个线程带来的各种问题。
2.函数作为一等公民存在(通过字面量创建,可以作为参数传递),闭包,函数式风格。
3.灵活。duck typing,动态指定函数的执行语境,动态修改原型,动态修改原型链,甚至修改原生对象的原型...
arguments不是Array类型,因此它没有slice方法,但是arguments对象满足了slice方法的一些条件:
因此,arguments可以应用于slice方法,于是我们也可以这样用:
JavaScript面向对象编程?
在JavaScript中,命名空间只是另一个包含方法,属性,对象的对象。
JavaScript是一种基于原型的语言,它没类的声明语句,比如C+ +或Java中用的。这有时会对习惯使用有类申明语句语言的程序员产生困扰。相反,JavaScript可用方法作类。定义一个类跟定义一个函数一样简单。在下面的例子中,我们定义了一个新类Person。
Event Loop
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop
不可变对象
number,string
项目中遇到的最大的问题,你是如何解决的?
你知道哪些知名的博客主?
The text was updated successfully, but these errors were encountered: