H5跳转小程序按钮不显示(使用wx-open-launch-weapp的血泪史)

被wx-open-launch-weapp折磨累了,也就不废话了,直接上关键点:

ps:其他细节不赘述,自行百度,有很多案例

  1. 引入jweixin.js,需要1.6.0版本

http://res2.wx.qq.com/open/js/jweixin-1.6.0.js

  1. 设置wx.config

设置:openTagList:['wx-open-launch-weapp'](必须有,跳转小程序)

设置:jsApiList:['chooseImage', 'previewImage'](必须有,不然安卓不显示)

  1. vue中忽略wx-open-launch-weapp标签检测

在main.js中添加:Vue.config.ignoredElements = ['wx-open-launch-weapp']

  1. 在vue页面中添加wx-open-launch-weapp标签

在vue的视图页:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<wx-open-launch-weapp
id="launch-btn"
username="gh_xxxxxxx"
path="pages/order-tab/order-tab.html"
@launch="sucFun"
@error="errFun"
>
<script type="text/wxtag-template">
<style>.guideBtn{width: 347px;
height: 50px;
background-color: #ff6611;
border-radius: 2px;
color: #fff;
font-size: 16px;
line-height: 50px;
text-align: center;}</style>
<div class="guideBtn">去注册</div>
</script>
</wx-open-launch-weapp>

在vue的methods中:

1
2
sucFun(msg) { console.log(msg) },
errFun(msg) { console.log(msg) }

另外,在vue中也可以使用v-html去绑定,例如:

在vue视图中:

1
<div id="wxLaunchBox" v-html="weappDom"></div>

在vue的script中(可放在created中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
this.weappDom = `
<wx-open-launch-weapp
id="launch-btn"
username="gh_xxxxxx"
path="pages/order-tab/order-tab.html"
@launch="sucFun"
@error="errFun"
>
<script type="text/wxtag-template">
<style>.guideBtn{width: 347px;
height: 50px;
background-color: #ff6611;
border-radius: 2px;
color: #fff;
font-size: 16px;
line-height: 50px;
text-align: center;}</style>
<div class="guideBtn">去注册</div>
</script>
</wx-open-launch-weapp>
`

注意:
vue页面中,可以使用<script type="text/wxtag-template"></script>进行包裹标签
普通html页面中,使用<template></template>进行包裹
样式中不可添加position:fixed,position:absoulte样式,不然按钮不展示

  1. 环境

微信开发工具和真机测试结果可能不一样,一定要用真机测试
安卓和ios测试结果也可能不同,都要测试
6. 小程序的web-view不支持wx-open-launch-weapp

所以在h5页面中使用wx-open-launch-weapp跳转A小程序,如果将此h5通过webview的方式嵌入B小程序,这个功能将失效,按钮也不会展示


此情况还是采用长按识别小程序码吧!(直接放上小程序码图片<img src="xxx" alt="小程序码" />就可以,系统自带长按识别功能)——官方的规格还没有明确说支持这个功能,但是可以使用。


如果直接使用img放小程序码页不识别,那就再退而求其次吧,可以使用官方文档提供的图片预览的功能:

1
2
3
4
wx.previewImage({
current: '', // 当前显示图片的http链接(注意:是在线链接,不是本地)
urls: [] // 需要预览的图片http链接列表(注意:是在线链接,不是本地)
>});

点击之后,出现预览的小程序码或二维码界面,然后长按识别


如果还是不可以,那就更换需求或交互方式。总之,大家自己想办法吧🤪

ps: 尽自己的绵薄之力让大家少走点坑,其他的坑大家慢慢踩吧🐷。
说实话,微信相关开发是真的坑,及其不友好😭😭😭(痛苦三连~~~)

  

设计模式

单例模式

单例模式保证类只有一个实例,并提供一个访问她的全局访问点

1
2
3
4
5
6
function getSingle(fn){
let result
return function (){
return result || (result=fn.apply(this,arguments))
}
}

策略模式

解决一个问题的多个方法,将每种方法独立封装起来,相互可以转换

一个基于策略模式的程序至少由两部分组成,一个是一组策略类,策略类封装了具体的算法,并负责具体的计算过程,一个是环境类,环境类接受客户的请求,随后把请求委托给某个策略类
策略模式的一个使用场景:表单验证,将不同验证规则封装成一组策略,避免了多重条件判断语句
一句经典的话: 在函数作为一等对象的语言中,策略模式是隐性的,策略就是值为函数的变量
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
const S = (salary)=>{
return salary * 4
}
const A = (salary)=>{
return salary * 3
}
const B = (salary)=>{
return salary * 2
}
const calculate = (fun,salary)=>{
return fun(salary)
}
calculate(S,1000)

代理模式

代理模式为一个对象提供一个代用品或占位符,以便控制对它的访问

不直接和本体进行交互,而是在中间加入一层代理,代理来处理一些不需要本体做的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var myImage=function(){
var imgNode=document.createElement('img')
document.body.appendChild(imgNode)
return {
setImg(src){
imgNode.src=src
}
}
}
var proxyImg=function(){
var img =new Image()
img.onload=function(){
myImage.setSrc(this.src)
}
return {
setImg(src){
myImage.setSrc(‘loading.png’)
img.src=src
}
}
}

代理的意义
对单一职责原则的一种表现,单一职责原则指的是,一个函数或类应该只负责一件事,如何一个函数职责太多,等于把这些职责耦合在了一起,当一部分需要改动时,很有可能就影响到了函数的其他部分

观察者和发布订阅模式

观察者和发布、订阅模式使程序的两部分不必紧密耦合在一起,而是通过通知的方式来通信

  1. 观察者模式

    一个对象维持一系列依赖于它的对象,当对象状态发生改变时主动通知这些依赖对象

这里注意是对象直接管理着依赖列表,这点也是观察者模式和发布、订阅模式的主要区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Subject{
constructor(){
this.observers=[]
}
add(observer){
this.observers.push(observer)
}
notify(data){
for(let observer of this.observers){
observer.update(data)
}
}
}
class Observer{
update(){
}
}
  1. 发布订阅模式
    该模式在主题和观察者之间加入一层管道,使得主题和观察者不直接交互,发布者将内容发布到管道,订阅者订阅管道里的内容,目的是避免订阅者和发布者之间产生依赖关系
    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
    class Pubsub{
    constuctor(){
    this.pubsub={}
    this.subId=-1
    }
    publish(topic,data){
    if(!this.pubsub[topic]) return
    const subs=this.pubsub[topic]
    const len=subs.length
    while(len--){
    subs[len].update(topic,data)
    }
    }
    /**
    * topic {string}
    * update {function}
    */
    subscribe(topic,update){
    !this.pubsub[topic] && (this.pubsub[topic]=[])
    this.subId++
    this.pubsub[topic].push({
    token:this.subId,
    update
    })
    }
    unsubscribe(token){
    for(let topic in this.pubsub){
    if(this.pubsub.hasOwnProperty(topic)){
    const current=this.pubsub[topic]
    for(let i=0,j=current.length;i<j;i++){
    if(current[i].token==token){
    current.splice(i,1)
    return token
    }
    }
    }
    }
    return this
    }
    }

    命令模式

    命令模式的命令指的是一个执行某些特定事情的指令

命令模式最常见的使用场景是:有时候需要向某些对象发送请求,但是不知道请求的接受者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,是使得请求发送者和接受者消除彼此之间的耦合关系
命令模式的由来,其实是回调函数的一个面向对象的替代品
一句话来说,命令模式就是用一个函数来包裹一个具体的实现,这个函数统一定义了一个 execute 方法来调用具体的实现方法,而请求者只要和这个命令函数交流就行

享元模式

享元模式顾名思义,共享一些单元,用于优化重复、缓慢及数据共享效率较低的代码

应用:一是用于数据层,处理内存中保存的大量相似对象的共享数据,二是用于 DOM 层,事件代理
在享元模式中,有个有关两个状态的概念 - 内部和外部
内部状态存储于对象内部,可以被一些对象共享,独立于具体的场景,通常不会变
外部状态根据场景而变化
剥离了外部状态的对象成为共享对象,外部状态在必要时被传入共享对象来组成一个完整的对象
使用享元模式的几个步骤:
以书中文件上传的例子描述
1.剥离外部状态

1
2
3
4
5
6
7
8
9
10
11
12
13
class Upload {
constructor(type) {
this.uploadType = type
}
delFile(id) {
uploadManager.setExternalState(id, this) //这里就是组装外部状态来使共享对象变成一个具体的对象
if (this.fileSize < 3000) {
//直接删除
return
}
//弹窗询问确认删除?
}
}

2.使用工厂进行对象实例化

1
2
3
4
5
6
7
8
9
10
11
var UploadFactory = (function() {
const flyWeightObjs = {}
return {
create(uploadType) {
if (flyWeightObjs[uploadType]) {
return flyWeightObjs[uploadType]
}
return flyWeightObjs[uploadType] = new Upload(uoloadType)
}
}
})()

3.使用管理器封装外部状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var uploadManager = (function() {
var uploadDatabase = {}
return {
add(id, uploadType, fileSize, fileName) {
var flyWeightObj = UploadFactory.create(uploadType) //那个被共享的对象
//创建结点...
//删除操作
dom.onclick = function() {
flyWeightObj.delFile(id) //这个共享在步骤1中会被组合,可以看到,只有在删除操作的时候,我们才需要那些外部状态
}
uploadDatabase[id] = {
fileName,
fileSize,
dom
}
return flyWeightObj
},
setExternalState(id, flyWeight) {
var externalState = uploadDatabase[id]
Object.assign(flyWeight, externalState)
}
}
})()

责任链模式

将一个请求以此传递给多个函数,若请求符合当前函数要求,则当前函数处理,否则,传给下一个

很好很强大
责任链模式可以很好的避免大量的 if,else if,else

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
if (Function.prototype.chainAfter) {
throw new Error('the chainAfter method already exist')
} else {
Function.prototype.chainAfter = function(fn) {
return (...args) => {
const ret = this.apply(this, [...args, () => {
return fn && fn.apply(this, args)
}])
if (ret === 'NEXT') {
return fn && fn.apply(this, args)
}
return ret
}
}
}
/*
* example
* class Test{
*
* test(...args){
* alert('test')
* return 'NEXT'
* }
*
* test1(...args){
*
* setTimeout(()=>{
* alert('test1')
* args.pop()()
* })
* }
*
* test2(...args){
* alert('test2')
* }
*
* $onInit(){
* const chain = this.test.bind(this)
* .chainAfter(this.test1.bind(this))
* .chainAfter(this.test2.bind(this))
* chain(1,2,3)
* }
* }
*
*/

装饰者模式

在不改变原有函数或对象功能的基础上,给它们新加功能

用 AOP 装饰函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (Function.prototype.before) {
throw new Error('the before method already exist')
} else {
Function.prototype.before = function(beforefn) {
return () => {
if (beforefn.apply(this, arguments)) {
this.apply(this, arguments)
}
}
}
}
if (Function.prototype.after) {
throw new Error('the after method already exist')
} else {
Function.prototype.after = function(afterfn) {
return () => {
this.apply(this, arguments)
afterfn.apply(this, arguments)
}
}
}

状态模式

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

要点:将状态封装成独立的函数,并将请求委托给 当前的状态对象,当对象的内部状态改变时,会带来不同的行为变化
电灯的例子:
一个按钮控制电灯的开关,按一下是开,再按一下是关
初始实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Light {
constructor() {
this.state = 'off',
this.button = null
}
init() {
//创建按钮结点
.....
this.button.onClick = () => {
this.btnPressed()
}
}
btnPressed() {
if (this.state == 'off') {
this.state = 'on'
} else {
this.state = 'off'
}
}
}

这段代码的缺点就是不易扩展,当要加入一种闪动的状态时,就要修改 btnPressed 中的代码

使用状态模式改写

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
class Light {
constructor() {
this.state = FSM.off,
this.button = null
}
init() {
//创建按钮结点
.....
this.button.onClick = () => {
this.state.btnPressed.call(this)
}
}
}
const FSM = {
on: {
btnPressed() {
//处理
this.state = FMS.on
}
},
off: {
btnPressed() {
//处理
this.state = FMS.off
}
}
}

点击查看原文

原生JS

工作线程(webWorker)

简介:web worker是HTML5引入的一个工作线程的概念,是运行在后台的JavaScript,独立于其他脚本。允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的响应。

简而言之,就是允许JavaScript创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
从而,可以用webWorker来处理一些比较耗时的计算。

 web js
  

GULP

简介

1、Gulp是一个开源的JavaScript开源自动化工具
2、Gulp应用于前后端代码管理的一种工具
3、Gulp是基于Node.js和NPM应用的构建工具
4、Gulp主要用于处理耗时及重复的任务
5、Gulp可以解决上百种的任务 例如:压缩代码 合并代码等

gulp作用

1、压缩代码
2、合并代码
3、压缩图片
4、Sass、Less转换
5、……

原理

1、基于Node.js中的数据流
2、Gulp主要使用pipe事件输入及输出
3、插件独立使用

安装步骤

1、安装Node环境
2、通过 npm install -g gulp 安装全局
3、初始化package.json
4、在项目文件中安装gulp

VUE

==
vue.js 轻量级的MVVM框架
数据驱动+组件化的开发
==

基本指令

1

v-if是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下:
v-if=”expression”

2

v-show根据表达式的真假来删除和插入元素
v-if=”expression”

3

可以用v-else指令为v-if或v-show添加一个“else块”。
v-else元素必须立即跟在v-if或v-show元素的后面——否则它不能被识别。
v-if和v-else连用时,不执行else时,else里面的HTML不渲染
v-if和v-show连用时,不执行else时,else里面的HTML渲染,只是display:none隐藏了

4

v-for=”item in items” items是一个数组,item是当前被遍历的数组元素。
总是key配合v-for使用

1
2
3
4
5
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>

5

v-bind 指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的
特性(attribute–专门用来绑定属性),例如:v-bind:width=""
v-bind:argument="expression"
简写形式如下:
:argument="expression"

另外可以绑定类名
用法1:
:class="[className1,className2,className3]" 其中,className1、2、3是数据 放在data中的
用法2:
:class="{className1:true,className2:false}" 其中,className1、2是真正的类名
用法3:
:class="json" json是data里面的json
可以绑定style
:style="[c]" c是json形式的数据
:style="[c,d]" c和d都是json形式的数据,多个样式的写法
:style="json" json是data中的数据

6

v-on指令用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听<a>元素的点击事件:
<a v-on:click="doSomething">
v-on 有简写形式,如下:
<a @click="doSomething">

7.模板

数据更新模板变化-->v-text="msg" 后面的方法可以防止闪烁
1
{{*msg}}

数据只绑定一次

1
{{{msg}}}

将HTML转译输出–>v-html=”msg” 后面的方法可以防止闪烁,前面的方法v2.0已经删掉了

8.过滤器

过滤模板数据 系统提供一些过滤器:

1
2
{{msg| filterA}}
{{msg| filterA | filterB}}
 web vue
  

es6

ES6项目构建

let和const命令

let命令

let声明

1
2
3
4
5
6
{
let a=10;//let声明的变量只在它所在的代码块有效
var b=1;
}
console.log(b);
// console.log(a);//报错

let应用

1
2
3
4
5
6
7
8
9
10
11
for(let i=0;i<10;i++){}
//console.log(i);//i不能在外面引用
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
//如果是var声明,则会输出10;如果是let声明,则会输出6
//let声明中,每次循环的i其实都是一个新的变量

let不支持变量提升

只要块级作用域内存在let命令,它所声明的变量就“绑定”了这块区域,不再受外部的影响

1
2
3
4
5
6
7
8
9
10
11
var temp=123;
if(true){
temp='abc';//会报错,因为下面的let声明了temp,所以这里的temp和外面的就没有关系了,
//但是此处的赋值在声明之前,还没有声明就赋值会报错
let temp;
/*ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。*/
//称为暂时性死区
}
typeof x; // 报错
let x;
//let不予许重复声明

块级作用域

外层作用域无法读取内层作用域的变量

1
2
3
4
{{{{
{let insane = 'Hello World'}
console.log(insane); // 报错
}}}};

内层作用域可以定义外层作用域的同名变量

1
2
3
4
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};

作用:使的获得广泛应用的立即执行函数表达式(IIFE)不再必要了

1
2
3
4
5
6
7
8
9
10
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}

do 表达式

块级作用域本质上是语句,没有返回值,所以在外部没法或许执行结果

可以通过do表达式获取块级作用于中的最后执行的表达式的值。

1
2
3
4
let x = do{
let t = f();
t * t + 1;
}

const 命令

const 声明一个只读的常量。一旦声明,常量的值就不能改变。—所以常量一旦声明就必须立即初始化,不能留到以后赋值
const 的作用域与let命令相同:只在声明所在的块级作用域内有效
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

const实际保证的,并不是变量的值不得改动,而是变量指向的哪个地址不得改动
如:const foo={};
foo存的是地址,这个地址指向一个对象,这个对象本身是可变的,故可添加属性foo.prop=123;
但是不可把foo指向另一个地址:foo = {}//错误

————-让对象冻结的方法(不可改变属性)—————

1
2
const foo=Object freeze({});
foo.prop=123;//常规模式下,此行代码不起作用。 严格模式下会报错

————-让对象彻底冻结的方法————————-
注:对象的属性有可能还是对象,那么对象的属性就有可能有自己的属性,那么对象的属性也要被冻结

***使用回调函数

1
2
3
4
5
6
7
8
var constantize = (obj)=>{
Object freeze(obj);
Object keys(obj).forEach((key,i)=>{
if(typeof obj[key]==='object'){
constantize(obj[key]);
}
});
}

es6声明变量的6种方法

var function let const import class es5只有前两种

顶层对象的属性

顶层对象:window(浏览器环境),global(Node环境)

window.a=1; 和 a=1; 是一样的,即顶层对象属性和全局变量是一样的

这是JavaScript设计的败笔之一,ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。

1
2
3
4
5
6
var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1
let b = 1;
window.b // undefined

global对象

有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象

垫片库(system.global)模拟了这个提案,可以在所有环境中拿到global

1
2
import getGlobal from 'system.global';
const global = getGlobal();

变量的解构赋值

数组的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

如果解构不成功,变量的值就等于undefined。

1
2
let [foo] = [];
let [bar, foo] = [1];

以上两种情况都属于解构不成功,foo的值都会等于undefined。

不完全解构:

1
2
let [x, y] = [1, 2, 3];// x 为1, y为2
let [a, [b], d] = [1, [2, 3], 4];//a 为 1,b为 2,d为4

//下面情况将会报错,右边必须为数组(可遍历的结构——Iterator 接口)形式

1
2
3
let [foo] = 1;
let [foo] = undefined;
let [foo] = {};

对于 Set 结构,也可以使用数组的解构赋值。

1
2
let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

1
2
3
4
5
6
7
8
9
10
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5

默认值

解构赋值允许指定默认值

1
2
3
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

1
2
3
4
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null

如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
==惰性求值==:即只有在用到的时候才会求值
默认值可以引用解构赋值的其他变量,但该变量必须已经声明

1
2
3
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError

对象的解构赋值

数组的解构赋值是有顺序的,但是对象的解构赋值是无需的,变量名和属性同名才能获取到正确的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let { bar: bar, foo: foo } = { foo: "aaa", bar: "bbb"};
// 可以简写为
let { bar, foo } = { foo: "aaa", bar: "bbb"};
foo // "aaa"
bar // "bbb"
let {foo: xiao , baz } = { foo: "aaa", bar: "bbb"};
baz // undefined
xiao // "aaa"
//真正被赋值的是后者
foo // error : foo is not defined

let obj = { first: 'hello', last: 'world' };
let { first: f, last: 1 } = obj;
f // 'hello'
l // 'world'

与数组一样,结构也可以用于嵌套结构的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//如果写法如下:那么p既是模式又是变量
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

一个嵌套的例子:

1
2
3
4
5
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true});// 此处必须加小括号,否则会报错
obj // {prop:123}
arr // [true]

对象的结构也可以设置默认值,默认值生效的条件是严格等于undefined

如果结构失败,变量的值等于undefined

1
2
3
var { x = 1, y = 2 } = { x: undefined, y: null };
x // 1
y // null

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量

1
2
3
let {sin, cos, tan} = Math;
Math.sin // 一个sin function
sin // 一个sin function 直接将Math中的方法给了sin

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象

1
2
3
4
5
6
7
const [a, b, c, d, e] = 'hello';
a // "h"
e // "o"

//类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5

数值和布尔值得解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象,无法转化成对象,将会报错

1
2
3
4
5
6
7
8
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

函数参数的解构赋值

1
2
3
4
5
6
7
function add([x, y]){
return x + y;
}
add([1, 2]); // 3

[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

undefined就会触发函数参数的默认值。

1
2
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]

圆括号问题

建议只要有可能,就不要在模式中放置圆括号

不能使用圆括号的情况

1.变量声明语句

1
2
3
4
5
6
7
//全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };

2.函数参数

1
2
3
4
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

3.赋值语句模式

1
2
3
4
5
6
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];

// 报错
[({ p: a }), { x: c }] = [{}, {}];

可以使用圆括号的情况

只有一种:赋值语句的非模式部分,可以使用圆括号

1
2
3
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

用途

1.交换变量的值

1
2
3
let x = 1;
let y =2;
[x, y] = [y, x];

2.从函数返回多个值
直接取值就可以

1
2
3
4
5
6
7
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();

3.函数参数的定义
4.提取JSON数据

1
2
3
4
5
6
7
8
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

5.函数参数的默认值

1
2
3
4
5
6
7
8
9
10
11
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句
6.遍历Map结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world

//如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}

7.输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

1
const { SourceMapConsumer, SourceNode } = require("source-map");

字符串的扩展

字符的Unicode表示法

codePointAt()

String.fromCodePoint()

字符串的遍历器接口

es6为字符串添加了遍历器接口,而且增加的for…of循环识别码点

1
2
3
4
5
6
7
8
9
10
11
let text = String.fromCodePoint(0x20BB7);
for (let i of text) {
console.log(i);
}
// "𠮷"

for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "

at()

es5中的charAt方法可以返回字符串指定位置的字符,但是不识别码点大于0xFFFF的字符。es6提供了at()方法,可以实现这一要求

6
1
2
3
4
'abc'.charAt(0) //"a"
'𠮷'.charAt(0) // "\uD842"
'abc'.at(0) // "a"
'𠮷'.at(0) // "𠮷"

normalize()

includes()、startWith()、endsWith

includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

6
1
2
3
4
5
6
7
8
9
10
let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

//这三个方法都支持第二个参数,表示开始搜索的位置。
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

6
1
'hello'.repeat(2) // "hellohello"

padStart(),padEnd()

字符串补全长度的功能9

 web js
  

:D 一言句子获取中...