搜索文章
类目归类
第十八章 ECMAScript 6 Class
Class基本语法JavaScript语言的传统方法是通过构造函数,定义并生成新对象。下面是一个例子。function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2);上面这种写法跟传统的面向对象语言(比如C++和Java)差异很大,很容易让新学习这门语言的程序员感到困惑。ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用ES6的“类”改写,就是下面这样。//定义类 class Point { constructor(x, y) { this.x = x; t...第十七章 ECMAScript 6 异步操作和Async函数
异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。ES6诞生以前,异步编程的方法,大概有下面四种。回调函数事件监听发布/订阅Promise 对象ES6将JavaScript异步编程带入了一个全新的阶段,ES7的Async函数更是提出了异步编程的终极解决方案。基本概念异步所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。回调函数JavaScript语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。它的英语名字callback,直译过来就是"重新...第十六章 ECMAScript 6 Promise对象
Promise的含义Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。Promise对象有以下两个特点。(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rej...第十五章 ECMAScript 6 Generator 函数
简介Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍Generator函数的语法和API,它的异步编程应用请看《异步操作》一章。Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态。执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。形式上,Generator函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield语句,定义不同的内部状态(yield语句在英语里的意思就是“产出”)。function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();上面代码定义了一个Generator函数hel...第十四章 ECMAScript 6 Iterator和for...of循环
Iterator(遍历器)的概念JavaScript原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。Iterator的遍历过程是这样的。(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。(3)第二次调用指针对象的next方...第十三章 ECMAScript 6 Set和Map数据结构
SetES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。var s = new Set(); [2, 3, 5, 4, 5, 2, 2].map(x => s.add(x)); for (let i of s) { console.log(i); } // 2 3 5 4上面代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。// 例一 var set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4] // 例二 var items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.size // 5 // 例三 function divs () { return [...document.querySelectorAll('div')]; } var set = new Set(divs()...新版chrome浏览器设置允许跨域
前言目前前端解决跨域,主要是通过webpack的devServer来配置。但是有时候开发环境中没有配置devServer,后端又没有设置跨域。前后端分离项目,本地调试代码的时候,经常会遇到跨域问题。本文主要是对之前文章浏览器跨域访问解决方案,做一个补充吧,因为这篇文章最后对chrome设置方式,目前设置不起作用了,更新文章,修正一下。解决--disable-web-security 不起作用的方案之前文章,提供了windows,mac,linux等设置--disable-web-security的方式,但是chrome新版本安全策略升级,这种打开方式或者之前的设置方式是无效的。那么如何解决呢?一、设置跨域,在chrome快捷方式右键‘属性’,‘快捷方式’,‘目标’ 路径最后边按一下空格,再添加以下代码:--args --disable-web-security --user-data-dir=D:\HaoroomsChromeUserData或者--disable-web-security --user-data-dir=D:\HaoroomsChromeUserDataD:Ha...第十二章 ECMAScript 6 二进制数组
二进制数组(ArrayBuffer对象、TypedArray视图和DataView视图)是JavaScript操作二进制数据的一个接口。这些对象早就存在,属于独立的规格(2011年2月发布),ES6将它们纳入了ECMAScript规格,并且增加了新的方法。这个接口的原始设计目的,与WebGL项目有关。所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的JavaScript脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像C语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。二进制数组就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了JavaScript处理二进制数据的能力,使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信。二进制数组由三类对象组成。ArrayBuffer对象:代表内存之中的一...第十一章 ECMAScript 6 Proxy和Reflect
Proxy概述Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。var obj = new Proxy({}, { get: function (target, key, receiver) { console.log(`getting ${key}!`); return Reflect.get(target, key, receiver); }, set: function (target, key, value, receiver) { console.log(`setting ${key}!`); return Reflect.set(target, key, value, receiver); } }...第十章 ECMAScript 6 Symbol
概述ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。let s = Symbol(); typeof s // "symbol"上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是Symbol数据类型,而不是字符串之类的其他类...第九章 ECMAScript 6 对象的扩展
属性的简洁表示法ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。var foo = 'bar'; var baz = {foo}; baz // {foo: "bar"} // 等同于 var baz = {foo: foo};上面代码表明,ES6允许在对象之中,只写属性名,不写属性值。这时,属性值等于属性名所代表的变量。下面是另一个例子。function f(x, y) { return {x, y}; } // 等同于 function f(x, y) { return {x: x, y: y}; } f(1, 2) // Object {x: 1, y: 2}除了属性简写,方法也可以简写。var o = { method() { return "Hello!"; } }; // 等同于 var o = { method: function() { return "Hello!"; } };下面是一个实际的例子。var birth = '20...JavaScript的内存管理
大多数情况下,作为JavaScript开发者,你可能可以在不需要知道任何有关内存管理的情况下就做得很好。毕竟JS引擎帮你把这事都干了。但另一方面,你也会碰到一些只有知道内存分配运作原理才能解决的问题,比如内存泄漏。在这篇文章中,我会介绍内存分配和垃圾回收机制,以及如何避免一些常见的内存泄漏。JavaScript在浏览器是如何运作的?本文是我的系列文章(解释JavaScript在浏览器是如何工作的)的第二部分。为了能在邮箱获取我最新的文字,请订阅我的简讯。Part 1: JavaScript Event Loop And Call Stack ExplainedPart 2: JavaScript's Memory Management: Heap And Garbage Collection Explained内存生命周期在JavaScript中,当我们创建变量、函数或者任何你能想到的,JS引擎都会为它分配内存,当它不会再被用到的时候就会被释放掉。在内存中,分配内存是保留空间的过程,而释放内存则是释放空间,释放出来的空间准备用于其他目的。我们每次声明一个变量或创造一个函数,该变量...CSS之栅格化布局
栅格化布局帮助你更容易构建复杂的网页设计。它会将HTML元素转换为网格的容器(有行有列)。你可以在网格里面添加你想要的子元素。grid 初始化元素为栅格化将一个HTML元素转换为网格的容器,只需要对其设置display: grid即可。display: grid告诉我们,可以使用CSS Grid的相关属性了。<dl class="container"> <dd class="item1">item1</dd> <dd class="item2">item2</dd> <dd class="item3">item3</dd> <dd class="item4">item4</dd> <dd class="item5">item5</dd> <dd class="item6">it...javaScript几个例子理解不同数据类型的堆栈内存处理
js代码的运行环境简介浏览器 内核(引擎)nodewebview(hybrid,嵌入到手机app里面,在app里面运行)...下面通过几个例子理解不同数据类型的堆栈内存处理js如何运行(示例1)var a = 12; var b = a; b = 13; console.log(a);浏览器能够运行js代码,是因为浏览器会在计算机内存中分配出一块内存,用来供代码执行,这块内存叫栈内存,也叫Stack,或者ECStack(Execution Context Stack)执行环境栈。为了区分是哪个区域(全局或者函数等)下的代码执行,会产生一个执行上下文(EC : Execution Context)。所谓执行上下文,其实是一个抽象的概念,简单来理解就是代码执行区域的划分。在全局环境下会产生 EC(G) :Execution Context (golbal) 全局执行上下文,其中VO(G)全局变量对象(Varibale Object)存储全局执行上下文声明的变量,然后进入栈内存执行。声明变量的步骤接着开始执行,先声明变量,声明变量有三步var [变量] = [值]先创建值(执行等号右边...解析call、apply、bind三者区别及实现原理
前言不管在写插件,还是写框架,又或者其它业务开发中。我们都会遇到在执行函数的时候,如果需要保证函数内部this不被污染或者说需要使函数内部this指向到指定对象的时候,都会按情况分别使用到call、apply、bind方法来实现需求。那么,你知道它们三者之间的区别吗?又分别如何实现的呢?接下来,请准我一一道来并分别实现它们吧~call、apply、bind的区别bindbind与call或apply最大的区别就是bind不会被立即调用,而是返回一个函数,函数内部的this指向与bind执行时的第一个参数,而传入bind的第二个及以后的参数作为原函数的参数来调用原函数。用一个例子来理解一下吧let obj = { name: 'wujia', fn: function (a, b, c) { console.log(this.name, a, b, c) } } window.name = '吴佳' let nFn = obj.fn.bind(window, '第一个参数') nFn('第二个参数', '第三个参数') // 最后输出:吴佳,第一个参数,第二个...Vue项目接口代理需要注意的几点
在做项目中,我们可能会遇到接口地址跨域的问题,有时候不想找后端去处理这个时候我们要怎么做呢,其实有个叫代理的东西可以帮我们快速的解决这个问题,第一步项目中创建一个vue.config.js的文件,在里面添加如下代码:module.exports = { publicPath: "./", devServer: { proxy: { '/api': { target: 'https://aijiumai.cn/api/', //对应服务器地址 changeOrigin: true, //允许跨域 ws: true, pathRewrite: { '^/api': '' } } } } };我们添加了之后就可以使用/api直接代替接口地址,只要axios请求地址有...transform 导致字体模糊的解决方案
很多人在日常开发中会使用transform: translate(-50%, 50%)来居中弹出层,那么相信大家也会碰到与我相同的情况:有时候弹出层的内容变得模糊不清晰。原因很简单,是因为css动画在渲染非整数的px时会出现字体模糊。上面transform内的50%是相对于自身的宽高的,所以我们就需要确保自身的宽高都为偶数。解决办法:设置元素宽高皆为偶数(需要知道元素高度)使用margin代替transform(需要知道元素宽高)增加一个父级元素,将定位给父级,并使用flex布局使原本元素居中(不需要知道元素高度).father { position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; }关于 Promise 内存泄漏的问题
PromisePromise 是 ES6 的新特性,在 ES6 之前各大浏览器、各种 polyfill 和各种 js 执行环境都针对 Promise 进行了自己的实现,不过实现上大同小异。V8 Promise 内存泄漏不过 V8 对 Promise 的实现存在内存泄漏问题,当一个 promise 无法 resolve 也无法 reject 的时候,就会发生内存泄漏。一个很容易造成 Promise 内存泄漏的场景便是递归 Promise 或者嵌套 Promise。为方便观察内存使用情况,下面是一段在 Nodejs 里面运行的代码(function() { // 记录Promise链的长度 var i = 0; function run() { return new Promise(function(resolve) { // 每增加10000个Promise打印一次内存使用情况 if (i % 10000 === 0) console.log(i); i++; ...JavaScript 定时器与执行机制解析
从 JS 执行机制说起浏览器(或者说 JS 引擎)执行 JS 的机制是基于事件循环。由于 JS 是单线程,所以同一时间只能执行一个任务,其他任务就得排队,后续任务必须等到前一个任务结束才能开始执行。为了避免因为某些长时间任务造成的无意义等待,JS 引入了异步的概念,用另一个线程来管理异步任务。同步任务直接在主线程队列中顺序执行,而异步任务会进入另一个任务队列,不会阻塞主线程。等到主线程队列空了(执行完了)的时候,就会去异步队列查询是否有可执行的异步任务了(异步任务通常进入异步队列之后还要等一些条件才能执行,如 ajax 请求、文件读写),如果某个异步任务可以执行了便加入主线程队列,以此循环。JS 定时器JS 的定时器目前有三个:setTimeout、setInterval 和 setImmediate。定时器也是一种异步任务,通常浏览器都有一个独立的定时器模块,定时器的延迟时间就由定时器模块来管理,当某个定时器到了可执行状态,就会被加入主线程队列。JS 定时器非常实用,做动画的肯定都用到过,也是最常用的异步模型之一。有时候一些奇奇怪怪的问题,加一个 setTimeout(fn, ...移动端输入框填坑系列
输入框来来来,我们来想一下我们一天中使用频率最高的 App——微信,英文名是 WeChat,它的聊天界面长啥样子,输入框在最底部(不知道你什么反应,我反正当场就打开了 weibo,facebook, twitter 等等等的 mobile 端,就没有一个是把输入框放在最底部的,好的,我当场就对产品发动了强烈的反抗,当然依旧没有成功),输入框默认单行展示,随着用户输入,输入框中的内容自动换行,最多显示 3 行,超出部分可以滚动,要求可以输入超链接,输入框左边有个插入表情按钮,右边是发送按钮,输入框下面有个 checkbox,,,,,产品:这个需求很简单,怎么实现我不管,反正下个月要上线。技术方案虽然我很绝望,但是需求还是要做,,,,输入框技术选型来,我们来具体看需求,“输入框内容要自动换行”,排除 input;“输入框中可以输入超链接”,排除 textarea;还有啥,只有 contentEditable 为 true 的 div 了。插入表情我们知道,如果想做各端样式统一的表情的话,必然是用图片展示表情,这样的话,我们的成本就会增加很多,所幸在这一点上说服了产品,可以直接使用 e...