JavaScript笔记

es6中export和export default的作用、区别

作用:

export和export default实现的功能相同,即:可用于导出(暴露)常量、函数、文件、模块等,以便其他文件调用。

区别:

1、export导出多个对象,export default只能导出一个对象

2、export导出对象需要用{ },export default不需要{ },如:

  export {A,B,C};

  export default A;

3、在其他文件引用export default导出的对象时不一定使用导出时的名字。因为这种方式实际上是将该导出对象设置为默认导出对象,如:

假设文件A、B在同级目录,实现文件B引入文件A的导出对象deObject:

  文件A:export default deObject

  文件B:import deObject from './A'

  或者:

  import newDeObject from './A'

React和Vue对比

相同点

  • 都支持服务器端渲染
  • 都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponent规范
  • 数据驱动视图
  • 都有支持native的方案,React的React native,Vue的weex

不同点

  • React严格上只针对MVC的view层,Vue则是MVVM模式
  • virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
  • 组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即'all in js'; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
  • state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理

关于vue的数据双向绑定和单向数据流

Vue 的依赖追踪是【原理上不支持双向绑定,v-model 只是通过监听 DOM 事件实现的语法糖】

vue的依赖追踪是通过 Object.defineProperty 把data对象的属性全部转为 getter/setter来实现的;当改变数据的某个属性值时,会触发set函数,获取该属性值的时候会触发get函数,通过这个特性来实现改变数据时改变视图;也就是说只有当数据改变时才会触发视图的改变,反过来在操作视图时,只能通过DOM事件来改变数据,再由此来改变视图,以此来实现双向绑定

双向绑定是在同一个组件内,将数据和视图绑定起来,和父子组件之间的通信并无什么关联;

组件之间的通信采用单向数据流是为了组件间更好的解耦,在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以vue不推荐子组件修改父组件的数据,直接修改props会抛出警告

react没有数据双向绑定

react是单向数据流

react中通过将state(Model层)与View层数据进行双向绑定达数据的实时更新变化,具体来说就是在View层直接写JS代码Model层中的数据拿过来渲染,一旦像表单操作、触发事件、ajax请求等触发数据变化,则进行双同步。

前端笔试题1(预编译,typeof,函数,arguments)

1.求x,y,z值

2.打印出实参是1,2,3,4,5的函数是。

3.以下表达式的结果是

4.javascript语言typeof返回的结果
string number boolean object undefined function

5.看看下面alert的结果是什么

6.写出下列程序执行的结果

7.以下哪些表达式的结果为true

8.写出下列程序执行的结果

9.写出下列程序执行的结果

  1. 运行test() 和 new test()的结果分别是什么

11.写出下列程序执行的结果

12.写出下列程序执行的结果

13.写出下列程序执行的结果

14.写出下列程序执行的结果

15.写出下列程序执行的结果

高精度的基本四则运算npm包,用来弥补原生JS计算精度缺失的缺陷

面试问题:Vuejs如何实现双向绑定

最近出去面试,栽在这个问题上,提到vuejs,面试官一般会让你说vuejs的特点,一般就要回答virtual dom tree, dom tree diff, 以及数据双向绑定,然后面试官会追问你,vuejs是如何实现数据双向绑定的,前面的问题算基础的话,能答出这个就更上一个台阶,说明你的思考能力不停留在表层,遗憾的是我只能大概说出Object.defineProperty。
我回来搜了一下,发现其实vuejs的官网对这个原理是有详尽的阐释的,如果失败了只能怪自己准备不足。这篇文章我就整理一下分享给大家,如果有错误还请指出。

vuejs官网对这个问题的解释是 对响应式原理的解释,这里:https://cn.vuejs.org/v2/guide/reactivity.html

问题就是vuejs如何追踪对象的属性变化,答是利用es5的Object.defineProperty,参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty是一个无法被shim的属性,就是说它无法被降级使用,这也是vuejs不支持ie8以下的根本原因。

Object.defineProperty用来设置一个对象的某一个属性,这都不是最关键的,关键是在设置属性的同时,可以设置setter/getter,setter/getter设置两个函数,在这个属性被调用或者设置的时候自动执行,所以在setter的函数里,只要写了更新dom的方法,就可以在这个属性变化的时候执行,实现了属性变化的追踪。

实际上,vuejs的实现更加复杂,遵照这张流程图:

vuejs里每一个组件对应了一个watcher,Object.defineProperty是紫色的圆圈,当组件里某一个属性被get的时候,getter函数会通知Watcher,“说我这有一个属性被渲染了,你记一下”,然后当这个属性的setter被触发(也就是该属性数据被修改的时候),也会通知Watcher,说“我这有这样一个东西被改了,你看看在不在你的名单里。”Watcher此时去检查被改的属性在不在自己记录的名单里,如果在,就通知组件渲染程序,让它再去更新虚拟dom树。

需要注意的几个点:
1.getter/setter对用户是不可见的,是在vue内部实现的。
2.js里无法监听对象属性的增加或者删除,所以vue只能在开始data里添加响应式属性,所以当组件创建完毕,再给这个组件塞一个属性,这个属性是无法响应到dom的。
3.vue会在组件初始化的过程中进行getter/setter转换,所以也无法动态插入新属性,插入了也是非响应数据,但可以通过Vue.set(object, key, value)方法将属性加入到后台可响应的对象中。
4.官网还介绍了更新队列,上文说的Watcher中的更新会被推入到一个更新队列中,那么就是说数据更新后不会马上反映到dom上。
5.但是我们可以通过Vue.nextTick(callback)方法,将这次数据更新马上反映到dom上,这个方法的callback是dom更新完成的回调。

 ES6 带来的重大特性 – JavaScript 完全手册(2018版)

ES2015 最重要的变化包括:

  • Arrow functions(箭头函数)
  • Promises
  • Generators
  • let 和 const
  • Classes(类)
  • Modules(模块)
  • Multiline strings(多行字符串)
  • Template literals(模板字面量)
  • Default parameters(默认参数)
  • The spread operator(展开操作符)
  • Destructuring assignments(解构分配)
  • Enhanced object literals(增强的对象字面量)
  • for..of 循环
  • Map 和 Set

Arrow functions(箭头函数)

箭头函数改变了大多数 JavaScript 代码的外观(和工作方式)。 在视觉上,我们来看一下这种简单而受欢迎的变化:

变化为:

如果函数体内只有一行代码,只需:const foo = () => doSomething()

此外,如果您只有一个参数,您可以写:const foo = param => doSomething(param)

这不是一个破坏性的改变,因为常规函数可以继续像以前一样正常工作。

新的 this 作用域

箭头函数的 this 作用域继承自上下文。

对于常规函数,这总是指最近的函数,而使用箭头函数时,这个问题就不存在了,你不需要再次写 var that = this。

如果你还没很多好的理解箭头函数中的 this 作用域,可以查看: ES2015 中的箭头函数和词法 this 以了解更多

Promises

Promise 允许我们消除 “回调地狱” ,虽然它们引入了更多的复杂性( ES2017 已经带来了 async,用更高级别的概念解决了复杂性问题)。

在 ES2015 之前,JavaScript 开发人员已经使用了 Promise ,它有许多不同的库实现(例如,jQuery,q,deferred.js,vow …)。 该标准为这些差异创造了共同点。

通过使用 promises,您可以重写以下代码:

使用 promises 重写为:

更多关于 Promise 的信息,请查看 ES6 Promise 指南

Generator(生成器)函数

Generator(生成器)是一种特殊的函数,它能够暂停自身,并在稍后恢复,允许其他代码同时运行。

代码决定它必须等待,因此它允许其他代码“在队列中”运行,并保持 “当它正在等待的东西” 完成时恢复其操作的权利。

所有这些都是通过一个简单的关键字完成的:yield 。 当生成器包含该关键字时,将暂停执行。

生成器可以包含许多 yield 关键字,因此会多次自行停止,并且由 *function 关键字标识,不要与其他编程语言(如C,C ++或Go)中使用的指针解引用运算符混淆。

生成器在JavaScript中开启了全新的编程范例,允许:

Generator(生成器)运行时的双向通信
持久的while循环,不会冻结你的程序

这是一个生成器的例子,它解释了生成器是如何工作的。

我们用下面的代码初始化这个 Generator(生成器)函数const calc = calculator(10)

然后我们在我们的生成器上启动迭代器:calc.next()

第一次迭代启动迭代器。代码返回 this 对象:

会发生什么呢?代码运行函数,input = 10 传递给生成器构造函数。 它一直运行直到达到 yield,并返回 yield 的内容:input / 2 = 5。所以我们得到了一个值 5,并指示迭代没有完成(函数只是暂停)。

在第二次迭代中,我们传递值 7 :calc.next(7)

我们得到的结果是:

第二个 next 方法带有参数 7,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量 doubleThat 所在的表达式接收。

重要提示:您可能认为 input / 2 是参数,但这只是第一次迭代的返回值。我们现在跳过它,并使用新的输入值 7 ,并将其乘以 2。

然后我们达到第二个 yield ,然后返回 doubleThat ,因此返回值为 14 。

在下一个和最后一个迭代中,我们传入 100 calc.next(100)
我们得到的结果是:

当迭代完成时(没有找到更多的 yield 关键字),我们只返回(input doubleThat another),其数量为 10 14 100。

如果你还是没理解,可以看看 用最简单的方式理解 JavaScript 中的 Symbols,Iterators(迭代器),Generators(生成器),Async/Await(异步/等待) 和 Async Iterators(异步迭代器) 这篇文章了解更多详情

let 和 const

var 是传统上的函数作用域。

let 是一个新的变量声明方式,它是块作用域。

在 for 循环中、 if 中或普通块中声明 let 变量不会让该变量 “逃出” 该块,而 var 变量的作用域是函数定义中。

const 就像 let,但是他是一个固定不变的值。

在 JavaScript 向前发展中,你将很少,甚至不会看到 var 声明,只需要 let 和 const 。

特别是 const,也许令人惊讶的是,它现在被广泛使用,其中不可变性非常受欢迎。

更多信息请查看:ES6 中的块级作用域及变量声明 let

Classes(类)

传统上,JavaScript 是唯一一个基于原型继承的主流语言。 从基于类的语言切换到 JavaScript 的程序员,发现 JavaScript 很令人费解,但是 ES2015 引入了 Classes(类),这些类只是 JavaScript 内部工作的语法糖,但改变了我们构建 JavaScript 程序的方式。

现在,继承非常简单,类似于其他面向对象的编程语言:

以上代码将打印 : “Hello, I am Tom Cruise. I am an actor.”

Classes(类) 没有显式的类变量声明,但必须在 构造函数(constructor) 中初始化所有变量。

构造函数(constructor)

Classes(类) 有一个叫做 constructor 的特殊方法,当通过 new 初始化一个 class(类) 时会调用它。

超类(super)

可以使用 super() 引用父类。

getters 和 setters

可以将属性的 getter 声明为

setter 以相同的方式编写:

关于 ES6 Classes(类) 的更多信息请查看 面向对象的 JavaScript – 深入了解 ES6 类

Template Literals(模板字面量)

Template Literals(模板字面量)是创建字符串的新语法:const aString = 'A string'

它提供了一种将表达式嵌入到字符串中的方法,通过使用 ${a_variable} 语法有效地进行插值:

您还可以执行更复杂的表达式:

并且字符串可以跨越多行:

比较一下,我们在 ES2015 之前 实现多行字符串的方式:

Default parameters(默认参数)

函数现在支持默认参数:

了解更多关于默认参数的信息,请查看 JavaScript 函数中默认参数

spread operator(展开操作符)

您可以使用展开操作符 ... 展开数组,对象或字符串。

让我们从一个数组示例开始。查看以下内容:const a = [1, 2, 3]

您可以使用创建一个新数组const b = [...a, 4, 5, 6]

您还可以使用展开操作符创建一个数组的副本const c = [...a]

spread operator(展开操作符)也适用于对象。用以下方法克隆对象:const newObj = { ...oldObj }

使用字符串,spread operator(展开操作符)创建一个数组,其中包含字符串中的每个字符:

这个运算符有一些非常有用的应用。最重要的是能够以非常简单的方式使用数组作为函数参数:

在过去,你可以使用 f.apply(null, a)来做到这一点,但可读性不是很好。

spread operator(展开操作符)对于函数参数的应用还有另一种叫法:Rest Parameters(剩余形参),你可以查看 JavaScript 函数中的参数:Parameters(形参) 和 Arguments(实参) 了解更多的说明。

Destructuring assignments(解构分配,解构赋值)

给定一个对象,您可以只提取一些值并将它们放入命名变量中:

name 和 age 包含了所需的值。

语法也适用于数组:

Enhanced object literals(增强的对象字面量)

在 ES2015 中,对象字面量获得了增强。

包含变量的更简单的语法

你不再需要这么做:

你只需:

Prototype(原型)

可以使用指定原型

super()

动态属性

for..of 循环

ES5 早在 2009 年就推出了 forEach() 循环。虽然很好,但它们没有办法中断循环(比如使用 break 语句或使用 return 语句),就像 for 循环一样。

ES2015 引入了 for..of 循环,它结合了 forEach 的简洁性和中断循环的能力:

了解 JavaScript 中循环方法的比较,请查看 JavaScript里的循环方法:forEach,for…in,for…of 。关于 for..of 循环的更多解释和应用,请查看 理解 JavaScript 中的 for…of 循环

ES2016(ES7) 的改进 – JavaScript 完全手册(2018版)

ES7,正式名称为 ECMAScript 2016 ,于2016年6月完成。

与ES6相比,ES7 是 JavaScript 的一个小版本,仅包含两个功能:

  • Array.prototype.includes
  • 求幂运算符

Array.prototype.includes()

此功能引入了更易读的语法,用于检查数组是否包含元素。

使用 ES6 和更低版本,要检查数组是否包含某个元素项,您必须使用 indexOf ,它检查数组中的索引,如果元素不存在则返回 -1 。

由于 -1 被求值为真值,因此您不能这样做:

借助 ES7 中引入的这一新功能,我们可以这样做:

关于这个特性请阅读 ES2016 新特性:Array.prototype.includes 了解更多信息。

求幂运算符(**)

求幂运算符 ** 等价于 Math.pow(),但是它被引入语言本身,而不是库函数。

Math.pow(4,2)== 4 ** 2

这个特性对于数学密集型的 JavaScript 应用程序来说是一个很好的补充。

** 运算符在许多语言中都是标准化的,包括Python,Ruby,MATLAB,Lua,Perl等等。

关于这个特性请阅读 ES2016 新特性:求幂运算符(**) 了解更多信息。

ES2017(ES8)带来的重大新特性 – JavaScript 完全手册(2018版)

ECMAScript 2017,ECMA-262 标准版本的第8版(通常称为ES2017或ES8),于 2017 年 6 月完成。

与 ES6 相比,ES8 是 JavaScript 的一个小版本,但它仍然引入了非常有用的功能:

  • 字符串填充(padStart 和 padEnd)
  • Object.values
  • Object.entries
  • Object.getOwnPropertyDescriptors()
  • 函数参数列表和调用中的尾随逗号
  • Async Functions (异步函数)
  • 共享内存 和 Atomics

字符串填充(padStart 和 padEnd)

字符串填充的目的是 向字符串添加字符,使字符串达到指定的长度。

ES2017引入了两个 String 方法:padStart() 和 padEnd() 。

简单的使用:

关于这个特性请阅读 ES2017 中新的字符串方法:padStart 和 padEnd 了解更多信息和用例。

Object.values()

这个方法返回一个包含所有对象自身属性值的数组

使用:

Object.values() 也适用于数组:

关于 Object.values() 特性请阅读 ES2017 中 Object.entries() 和 Object.values() 了解更多信息和用例。

Object.entries()

这个方法返回一个包含所有对象自身属性的数组,作为 [key,value] 对的数组。

使用:

Object.entries() 也适用于数组:

关于 Object.entries() 特性请阅读 ES2017 中 Object.entries() 和 Object.values() 了解更多信息和用例。

Object.getOwnPropertyDescriptors()

此方法返回对象的所有自有(非继承的)属性描述符。

JavaScript 中的任何对象都有一组属性,每个属性都有一个描述符。

描述符是属性(property) 的一组特性(attributes),它由以下的子集组成:

  • value:属性的值
  • writable:true 表示改属性可以被修改
  • get:属性的 getter 函数,在读取属性时调用
  • set:属性的 setter 函数,在属性设置值时调用
  • configurable:如果为 false ,则不能删除属性,也不能更改任何属性,但值除外
  • enumerable:如果属性是可枚举的,则为 true

Object.getOwnPropertyDescriptors(obj) 接受一个对象,并返回一个带有描述符集的对象。

这个方法有什么用?
ES2015 给我们带来了 Object.assign() 方法,它从一个或多个对象复制所有可枚举的属性,并返回一个新对象。

但是存在问题,它无法正确复制具有非默认特性(attribute) 的属性 (property)(getter,setter,不可写属性,等)。

如果一个对象只有一个 setter ,则无法使用 Object.assign() 正确地复制到一个新对象。

例如:

以下代码将不起作用:

但下面的代码就会奏效:

您可以通过简单的控制台测试,将会看到:

person2 丢失了 setter ,因为它没有复制过来。

使用 Object.create() 对浅拷贝对象也有同样的限制。

想了解关于 浅拷贝对象,深拷贝对象及更多更可靠的对象拷贝方法,请阅读 JavaScript 中的对象拷贝

想了解关于 Object.getOwnPropertyDescriptors() 特性的更多信息和相关用例,请阅读 ES2017 中的 Object.getOwnPropertyDescriptors()

函数参数列表和调用中的尾随逗号

此功能允许在函数声明和函数调用中使用尾随逗号:

这一变化将鼓励开发人员停止丑陋的“行以逗号开头”的习惯。

这个功能同样支持对象字面量和数组字面量后面跟的逗号,更多说明和限制请查看 ES2017 函数参数列表和调用后面的逗号

Async Functions (异步函数)

ES2017 引入了 Async Functions (异步函数) 的概念,这是 ECMAScript 版本中引入的最重要的变化。

Async Functions (异步函数) 是 promises 和 generators(生成器) 的组合,以简化 promises 调用,提过代码的可读性,但是不打破 promises 链式调用的限制。

为什么有用
这是对 promises 更高层次的抽象。

当 Promise 在 ES2015 中引入时,它们的目的是解决异步代码的问题,并且他们做到了。但在 ES2015 和 ES2017 相间隔的两年时间里,很明显, Promise 并不是最终的解决方案。

引入 Promise 是为了解决著名的 回调地狱 问题,但它们引入了自己的复杂性和语法复杂性。它们是良好的原语,可以向开发人员公开更好的语法:那就是Async Functions (异步函数)。

一个简单的例子
使用异步函数的代码可以写成:

上面的代码将在浏览器控制台中打印以下内容:

链式调用多个异步函数

异步函数可以非常容易地链式调用,并且语法比简单的 Promise 更具可读性:

后面的章节我们还会有更多的介绍。如果你有兴趣可以先阅读 ES2017 新特性:Async Functions (异步函数)使用 ES2017 中的 Async(异步) 函数 和 Await(等待) 这两篇文章详细了解。

共享内存 和 Atomics

WebWorkers 用于在浏览器中创建多线程程序。

他们通过事件提供消息传递协议。 从ES2017开始,您可以使用 SharedArrayBuffer 在 Web worker 及其创建者之间创建共享内存数组。

由于我们不知道向共享内存部分写入要花费多少时间来传播,因此 Atomics 是一种在读取值时执行该操作的方法,并且完成了任何类型的写入操作。

关于此的更多细节可以在 规范提案中找到 ,该提案已经实施。

或者阅读 ES2017 新特性:共享内存 和 Atomics (中文)详细了解该特性。

更加详细的 ES2016 与 ES2017 介绍

关于 ES2016 与 ES2017 的新特性也可以阅读 JavaScript 新书:探索 ES2016 与 ES2017

ES2018(ES9) 带来的重大新特性 – JavaScript 完全手册(2018版)

ES2018 是 ECMAScript 标准的最新版本。

它引入了哪些新东西呢?

Rest(剩余)/Spread(展开) 属性

ES6 在处理数组解构时,引入了 rest(剩余)元素的概念,例如:

还有展开元素时:

ES2018 为对象引入了类似的功能。

rest(剩余) 属性

spread(展开) 属性 允许通过组合展开运算符 ... 之后传递的对象属性来创建新对象:

Asynchronous iteration (异步迭代)

新的 for-await-of 构造允许您使用异步可迭代对象作为循环迭代:

由于这使用 await ,你只能在异步函数中使用它,就像普通的 await 一样(参见 async / await 章节)

Promise.prototype.finally()

当一个 promise 得到满足(fulfilled)时,它会一个接一个地调用 then() 方法。

如果在此期间发生错误,则跳过 then() 方法并执行 catch()方法。

finally() 允许您运行一些代码,无论 promise 的执行成功或失败:

正则表达式改进

先行断言(lookahead) 和 后行断言(lookbehind)
正则表达式后行断言(lookbehind):根据前面的内容匹配字符串。

下面是一个先行断言(lookahead):您可以使用 ?= 匹配一个字符串,该字符串后面跟着一个特定的子字符串:

?! 执行逆操作,匹配一个字符串,该字符串后面没有一个特定的子字符串:

先行断言(lookahead)使用 ?= 符号。它们已经可用了。

后行断言(lookbehind),是一个新功能,使用 ?< =。

后行断言(lookbehind) 逆操作,使用 ?< !。

Unicode 属性转义 \p{…} 和 \P{…}

在正则表达式模式中,您可以使用 \d 匹配任何数字,\s 匹配任何不为空格的字符,\w 匹配任何字母数字字符,依此类推。

这个新功能将扩展此概念到引入 \p{} 匹配所有 Unicode 字符,否定为 \P{} 。

任何 unicode 字符都有一组属性。 例如,Script 确定语言系列,ASCII 是一个布尔值, 对于 ASCII 字符,值为 true,依此类推。 您可以将此属性放在花括号中,正则表达式将检查是否为真:

ASCII_Hex_Digit 是另一个布尔属性,用于检查字符串是否仅包含有效的十六进制数字:

还有许多其他布尔属性,您只需通过在花括号中添加它们的名称来检查它们,包括 Uppercase, Lowercase, White_Space, Alphabetic, Emoji 等:

除了这些二进制属性之外,您还可以检查任何 unicode 字符属性以匹配特定值。在这个例子中,我检查字符串是用希腊语还是拉丁字母写的:

您可以直接在提案上阅读可使用的 所有属性

命名捕获组(Named capturing groups)

在 ES2018 中,可以为捕获组分配一个名称,而不是仅在结果数组中分配一个 slot(插槽):

正则表达式的 ‘s’ 标志

s 标志是 ‘single line'(单行)的缩写,它使 . 匹配新的行字符。如果没有它,点将匹配普通字符,而不是新行:

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复