本文目录:
共同点
js的任务分为同步任务和异步任务,js是单线程语言,所以直接进行主线程执行的任务是同步任务,被挂起到任务队列等待执行的是异步任务,常见的异步任务有绑定事件、定时器以及多数情况下的ajax请求和promise.then,需要特别注意的一点是:promise.then的执行顺序高于其他几种常见的异步任务(微任务高于宏任务)。
异步任务可以分为宏任务和微任务
宏任务主要有setTimeout、setInterval、setImmediate、I/O、UI rendering,微任务主要有promise.then、process.nextTick
执行顺序
在 JS 中,存在着 7 种原始值,分别是:
引用数据类型: 对象Object(包含普通对象-Object,数组对象-Array,正则对象-RegExp,日期对象-Date,数学函数-Math,函数对象-Function)
JavaScript不支持任何创建自定义类型的机制,而所有值最终都将是上述 8 种数据类型之一。
原始数据类型:直接存储在栈(stack)中,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。
引用数据类型:同时存储在栈(stack)和堆(heap)中,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
两者都可以对字符串进行解析,JSON.parse要解析的字符串必须完全符合JSON格式,否则会报错,而eval()则看上去强大的多,可解析不规范的JSON字符串,但是也会对字符串进行计算和执行,尤其是对于未知数据,你根本不知道eval()之后会干什么。所以在实际开发中,我们很少用到eval()。
强制类型转换:
Number()带有其他任何字符,结果都会变成NaN
String()
parseInt()保留整数,parseFloat转换成小数
Boolean(),数字零和空字符串和null和undefined会被转换成false,其他会转换成true,注意空格会被转换成true
自动类型转换(隐式转换)
隐式转换体现了js这门语言的宽容性,但是也是js的一个大坑,比较常见的就是运算符的隐式转换,加号会优先进行字符串拼接,而减号乘号除号会优先进行数字运算,如:
3+‘2’,结果是‘32’,加法会优先进行字符串转换,并进行拼接
3-‘2’,结果是1,减法会优先自动转换成数字,并进行计算,另外乘法和除法也都会自动进行数字转换。
3‘2’,结果是6
3/‘2’,结果是1.5
8null,结果是0
==更是有数之不尽的坑,如null == undefined 结果为true,NaN !== NaN,[] == false ,0 == false,我们在编程中应该注重变量的类型定义,避免不同类型的数据进行比较和运算,用===去代替==。
当代码运行时,会产生一个对应的执行环境,代码从上往下开始执行,就叫做执行上下文。特点:
作用域
在 Javascript 中,作用域分为 全局作用域 和 函数作用域。拥有全局作用于的代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。函数作用域在固定的代码中才能被访问。
作用域有上下级关系,上下级关系的确定就看函数是在哪个作用域下创建的。如在fn作用域下创建了bar函数,那么“fn作用域”就是“bar作用域”的上级。作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
作用域链
一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值,但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
函数式编程(经常缩写为FP)是通过组合纯函数,避免共享状态、可变数据、和副作用来构建软件的过程。函数式编程是声明性的而不是命令式的,应用状态流经纯函数中。相比于面向对象编程,其中的应用状态经常是共享的,并且和方法一起定义在一些对象中。
函数式编程是一种编程模式。意味着它是一种基于一些基本原理和定义原则来思考软件构造的方式。其它的编程模式还包括面向对象编程和过程式编程。
相比于命令式的和面向对象式的代码,函数式的代码趋向于更简洁、更加可预言的、更容易测试。
相同点:
async和defer都是script标签的属性,都代表异步加载script引入的js文件,使用方法是直接加在标签中就可以了
<script type="text/javascript" src="js/1.js" defer></script>
<script type="text/javascript" src="js/1.js" async></script>
不同点:
defer
文档解析时,遇到设置了defer的脚本,就会在后台进行下载,但是并不会阻止文档的渲染,当页面解析&渲染完毕后。会等到所有的defer脚本加载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded事件。如果你的脚本代码依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖,请使用defer
async
async脚本会在加载完毕后立即执行,会根据加载完毕的时间打破正常的执行顺序,如果你的脚本并不关心页面中的DOM元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据,请使用async,如果不太确定各个JS文件的用途,慎用async。
原型是一个对象,也称为原型对象。原型的作用,就是共享方法。我们通过在原型上添加可共享方法,实例化对象的时候,就不会反复开辟空间存储方法。原型中this的指向是实例。
原型与原型层层相链接的过程即为原型链。对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有proto原型的存在。
ES6之前并没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承。
继承属性,利用call改变this指向。但该方法只可以继承属性,实例不可以使用父类的方法。继承父类方法的方式有很多,当前最成熟的方式是寄生方式。
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的最常见的方式,就是在一个函数内部创建另一个函数。闭包这个概念涉及到作用域链、执行上下文和垃圾回收机制,需通过全面的分析才能有更好的理解。
闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,
只有函数内部的子函数才能读取局部变量,
因此可以把闭包简单理解成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
使用闭包的注意点:
· 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
· 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
本质上都是函数,class只是构造函数的另一种写法,让对象原型的写法更加清晰(语法糖)。构造函数和class创建的实例,里面都有proto指向prototype原型对象。
// ES5 Function Constructor
function Person(name) {
this.name = name;
}
// ES6 Class
class Person {
constructor(name) {
this.name = name;
}
}
区别:
ES6的类和构造函数的主要区别在于继承。如果咱们创建一个继承Person类的Student子类并添加一个studentId字段,以下是两种方式的使用:
function Student(name, studentID) {
// 调用你类的构造函数以初始化你类派生的成员。
Person.call(this, name)
// 初始化子类的成员。
this.studentID= studentID
}
Student.prototype = Object.create(Person.prototype)
Student.prototype.constructor = Student
// ES6 Class
class Student extends Person {
constructor(name, studentId) {
super(name)
this.studentId = studentId
}
}
主要区别说明:
element.addEventListener(event, function, useCapture)
第一个参数:event,必须,字符串,指定事件名
第二个参数,必须,指定要事件触发时执行的函数
第三个参数,可选,布尔值,true - 事件句柄在捕获阶段执行,false- 默认值,事件句柄在冒泡阶段执行
setTimeout方法包含两个参数,第一个参数为一个函数或者一个会作为eval()方法参数的js代码字符串,第二个参数为以毫秒为单位的时间。该方法的实际作用即:在一定时间之后,把一个函数加入消息队列末尾。如果这个时间点消息队列中还存在其他消息,那么该函数会在排在他之前的消息都执行完之后再开始执行。
如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。
如果拷贝的对象里的元素包含引用(像一个列表里储存着另一个列表,存的就是另一个列表的引用),那浅拷贝和深拷贝是不同的,浅拷贝虽然将原有对象复制一份,但是依然保存的是引用,所以对新对象里的引用里的值进行修改,依然会改变原对象里的列表的值,新对象和原对象并没有完全分离开。而深拷贝则不同,它会将原对象里的引用也新创建一个,即新建一个列表,然后放的是新列表的引用,这样就可以将新对象和原对象完全分离开。
联系:typeof和instanceof的目的都是检测变量的类型,两个区别在于typeof只能用于检测基本数据类型,instanceof可以检测基本数据类型,也可以检测某些引用数据类型,但是instanceof只能通过true或者false来判断,不能直接看出来是什么类型。
由此可见,无论是typeof还是instanceof都不能准确判断出正确的类型。所以需要另外的更直观的方法:
通过Object.prototype.toString方法,判断某个对象之属于哪种内置类型。
箭头函数生成一个JavaScript函数对象,其this上下文绑定到与this创建它们的位置相同的值。
显然,在一般意义上,Function.prototype.bind它比箭头函数更灵活:它可以将函数中的this绑定到本地以外值,并且它可以让this在任何时间绑定指定的对象。
事件委托 本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到 目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
使用事件代理我们可以不必要为每一个子元素都绑定一个监听事件,这样减少了内存上的消耗。并且使用事件代理我们还可以实现事件的动态绑定,比如说新增了一个子节点,我们并不需要单独地为它添加一个监听事件,它所发生的事件会交给父元素中的监听函数来处理。
IIFE是一个立即调用的函数表达式,它在创建后立即执行
(function IIFE(){
console.log( "Hello!" );
})();
// "Hello!"
常常使用此模式来避免污染全局命名空间,因为在IIFE中使用的所有变量(与任何其他普通函数一样)在其作用域之外都是不可见的。
ECMAScript 5 (ES5):ECMAScript 的第五版,于2009年标准化,该标准已在所有现代浏览器中完全支持。
ECMAScript 6 (ES6)/ ECMAScript 2015 (ES2015):ECMAscript 第 6 版,2015 年标准化。这个标准已经在大多数现代浏览器中部分实现。
1.箭头函数和字符串插值
const greetings = (name) => {
return `hello ${name}`;
}
也可以这样写:
const greetings = name => `hello ${name}`;
2.const
const 表示无法修改变量的原始值。
3.块作用域
ES6 中 let, const 会创建块级作用域,不会像 var 声明变量一样会被提升。
4.默认参数
默认参数使咱们可以使用默认值初始化函数。当参数省略或 undefined 时使用默认参数值。
function multiply (a, b = 2) {
return a * b;
}
multiply(5); // 10
5.类定义与继承
ES6 引入了对类(class关键字)、构造函数(constructor关键字)和 extend 关键字(用于继承)的语言支持。
6.for-of 运算符
for...of 语句创建一个遍历可迭代对象的循环。
7.展开操作符
const obj1 = { a: 1, b: 2 }
const obj2 = { a: 2, c: 3, d: 4}
const obj3 = {...obj1, ...obj2}
8.Promise
Promise 提供了一种机制来处理异步操作的结果和错误。可以使用回调来完成相同的事情,但是Promises 通过方法链接和简洁的错误处理来提高可读性。
const isGreater = (a, b) => {
return new Promise ((resolve, reject) => {
if(a > b) {
resolve(true)
} else {
reject(false)
}
})
}
isGreater(1, 2)
.then(result => {
console.log('greater')
})
.catch(result => {
console.log('smaller')
})
**9.模块导出和导入
const myModule = { x: 1, y: () => { console.log('This is ES5') }}
export default myModule;
import myModule from './myModule';
避免使用箭头函数的情况:
1.当想要函数被提升时(箭头函数是匿名的)
2.要在函数中使用this/arguments时,由于箭头函数本身不具有this/arguments,因此它们取决于外部上下文
3.使用命名函数(箭头函数是匿名的)
4.使用函数作为构造函数时(箭头函数没有构造函数)
5.当想在对象字面是以将函数作为属性添加并在其中使用对象时,因为咱们无法访问 this 即对象本身。
为啥大多数情况都建议使用箭头函数?
1.作用域安全性:当箭头函数被一致使用时,所有东西都保证使用与根对象相同的thisObject。如果一个标准函数回调与一堆箭头函数混合在一起,那么作用域就有可能变得混乱。
2.紧凑性:箭头函数更容易读写。
3.清晰度:使用箭头函数可明确知道当前 this 指向。
ES6 的展开语法在以函数形式进行编码时非常有用,因为咱们可以轻松地创建数组或对象的副本,而无需求助于Object.create,slice或库函数。Redux 和rx.js项目中经常使用此特性。
function putDookieInAnyArray(arr) {
return [...arr, 'dookie'];
}
const result = putDookieInAnyArray(['I', 'really', "don't", 'like']);
// ["I", "really", "don't", "like", "dookie"]
const person = {
name: 'Todd',
age: 29,
};
const copyOfTodd = { ...person };
ES6 的 rest 语法提供了一种捷径,其中包括要传递给函数的任意数量的参数。
就像展开语法的逆过程一样,它将数据放入并填充到数组中而不是展开数组,并且它在函数变量以及数组和对象解构分中也经常用到。
function addFiveToABunchOfNumbers(...numbers) {
return numbers.map(x => x + 5);
}
const result = addFiveToABunchOfNumbers(4, 5, 6, 7, 8, 9, 10);
// [9, 10, 11, 12, 13, 14, 15]
const [a, b, ...rest] = [1, 2, 3, 4]; // a: 1, b: 2, rest: [3, 4]
const { e, f, ...others } = {
e: 1,
f: 2,
g: 3,
h: 4,
};
// e: 1, f: 2, others: { g: 3, h: 4 }
对于三个点号,三点放在形参或者等号左边为rest运算符; 放在实参或者等号右边为spread运算符,或者说,放在被赋值一方为rest运算符,放在赋值一方为扩展运算符。
如果是做为rest运算符的时候,...不能出现了中间,spread运算符则位置随意。
const和Object.freeze是两个完全不同的概念。
const 声明一个只读的变量,一旦声明,常量的值就不可改变:
const person = {
name: "Leonardo"
};
let animal = {
species: "snake"
};
person = animal; // ERROR "person" is read-only
Object.freeze适用于值,更具体地说,适用于对象值,它使对象不可变,即不能更改其属性。
let person = {
name: "Leonardo"
};
let animal = {
species: "snake"
};
Object.freeze(person);
person.name = "Lima"; //TypeError: Cannot assign to read only property 'name' of object
console.log(person);
要将一个类数组对象转换为一个真正的数组,必须具备以下条件:
我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1
rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
在我的mac上安装几个东西时遇到这个问题,我认为这个问题来自将我的豹子升级到雪豹。我认为这个问题也与macports有关。/usr/local/lib/libz.1.dylib,filewasbuiltfori386whichisnotthearchitecturebeinglinked(x86_64)有什么想法吗?更新更具体地说,这发生在安装nokogirigem时日志看起来像:xslt_stylesheet.c:127:warning:passingargument1of‘Nokogiri_wrap_xml_document’withdifferentwidthduetoproto
我有一个包含多个组件的存储库,其中大部分是用JavaScript(Node.js)编写的,一个是用Ruby(RubyonRails)编写的。我想要一个.travis.yml文件来触发一个运行每个组件的所有测试的构建。根据thisTravisCIGoogleGroupthread,目前还没有官方支持。我的目录结构是这样的:.├──构建服务器├──核心├──扩展├──网络应用├──流浪文件├──package.json├──.travis.yml└──生成文件我希望能够运行特定版本的Ruby(2.2.2)和Node.js(0.12.2)。我已经有了一个make目标,所以maketest在每
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易
在Rails3.x应用程序中,我正在使用net::ssh并向远程pc运行一些命令。我想向用户的浏览器显示实时日志。比如,如果两个命令在net中运行::ssh执行即echo"Hello",echo"Bye"被传递然后"Hello"应该在执行后立即显示在浏览器中。这是代码我在rubyonrails应用程序中使用ssh连接和运行命令Net::SSH.start(@servers['local'],@machine_name,:password=>@machine_pwd,:timeout=>30)do|ssh|ssh.open_channeldo|channel|channel.requ
我正在为Jekyll编写一个转换器插件,需要访问一些页眉(YAML前端)属性。只有内容被传递给主要的转换器方法,似乎无法访问上下文。例子:moduleJekyllclassUpcaseConverter关于如何在转换器插件中访问页眉数据有什么想法吗? 最佳答案 基于Jekyll源代码,无法在转换器中检索YAML前端内容。根据您的情况,我看到了两种可行的解决方案。您的文件扩展名可以具有足够的描述性,以提供您本应包含在前言中的信息。看起来Converter插件的设计就是这么基本的。如果修改Jekyll是一个选项,您可以更改Convert
我需要一些指导来了解如何将Angular整合到rails中。选择Rails的原因:我喜欢他们偏执的做事方式。还有迁移,gem真的很酷。使用angular的原因:我正在研究和寻找最适合SPA的框架。Backbone似乎太抽象了。我不得不在Angular和Ember之间做出选择。我首先开始阅读Angular,它对我来说很有意义。所以我从来没有去读过关于ember的文章。使用Angular和Rails的原因:我研究并尝试使用小型框架,例如grape、slim(是的,我也使用php)。但我觉得需要坚持项目的长期范围。我个人喜欢用Rails的方式做事。这就是我需要帮助的地方,我在Rails4中有
目标:我想从动画GIF中抓取最佳帧并将其用作静态预览图像。我相信最好的帧是显示最多内容的帧-不一定是第一帧或最后一帧。以这张动图为例:--这是第一帧:--这是第28帧:很明显,第28帧很好地代表了整个GIF。我如何以编程方式确定一帧是否比另一帧具有更多像素/内容?如果您能向我指出任何想法、想法、包/模块或文章,我们将不胜感激。 最佳答案 实现此目的的一种直接方法是估计entropy每个图像的帧,并选择具有最大熵的帧。在信息论中,熵可以被认为是图像的“随机性”。单一颜色的图像是非常可预测的,分布越平坦,越随机。这与Arthur-R描述