JavaScript中的Proxy模块化过滤

2019-11-9 张宇童 学习日志

let source = {
    name: '小李',
    price: 100,
}

function validate(target, key, value) {
    if (Reflect.has(target, key)) {
        if (key == 'price') {
            if (value < 300) {
                return target[key] = value
            }
        }
    }
    return false
    
}

let p = new Proxy(source, {
    get (target, key) {
        if (key == 'price')
        return target[key] || '';
        return '您没有权限'
    },
    set: validate
})
p.price = 200
console.log(p.price, p.name)

标签: javascript ES6

评论(0) 浏览(397)

JavaScript简单使用

2019-11-9 张宇童 学习日志

let a = {
    x: '小花',
    price: 190
}

let p = new Proxy(a, {
    get(target, key) {
        if (key == 'price') {
            return target[key] + 20
        }else {
            return target[key]
        }
    }
})
console.log(a.price)

标签: javascript ES6

评论(0) 浏览(416)

JavaScript中的Reflect

2019-11-9 张宇童 学习日志

let obj = {x: '312', y: '666'}
let arr = ['1','2','3']

// Object.freeze(obj)
let d = new Date()
console.log(Reflect.apply(Math.floor, null, [3.99])) // 3 Reflect.apply 反射
console.log(Reflect.construct(Date, []).getTime()) // 1573292254566 实例化
console.log(Reflect.getPrototypeOf(d))// 打印原型方法 1
console.log(Reflect.has(d, 'constructdor')) // 判断原型链上有没有属性或元素 2
console.log(Reflect.isExtensible(d)) // 判断对象是否可以扩展3
Object.freeze(d) // 冻结对象 使对象不可扩展
console.log(Reflect.isExtensible(d)) // 变成了false
console.log(Reflect.ownKeys(d)) // 查看对象自己的属性 不包含原型链上的属性4
console.log(Reflect.isExtensible(obj)) // true
Reflect.preventExtensions(obj) // 冻结对象5
console.log(Reflect.isExtensible(obj)) // 变成了false
console.log(Reflect.getPrototypeOf(arr))
Reflect.setPrototypeOf(arr, String.prototype) // 修改arr的原型对象

标签: javascript ES6

评论(0) 浏览(416)

关于Promise对象

2019-11-9 张宇童 学习日志

Promise对象是解决ES5中回调地狱的问题

使用Promise 可以使代码的可读性增强。

使用new Promise的时候需要注意 new Promise后里面的代码将被直接执行。New的时候就会被执行

Promise对象有两个参数resolve和reject

resolve是将Promise的状态改为成功

而reject是将Promise的状态改为失败

如何声明一个Promise对象函数?

function loadScript(src) {
    return new Promise((resolve, reject) => {
        let script = document.createElement('script')
        script.src = src
        script.onload = () => resolve(src)
        script.onerror = err => reject(err)
        document.head.append(script)
    })
}
Promise中的整合

可能读者没有理解什么是整合的意思。

就好像我需要从A接口取一些数据 然后从B接口取一些数据,最后将A和B的数据整合成一个数组。

我们可以使用串联的方式解决该问题

但是Promise给我提供了一个很好的方法。这个是Promise的原型方法

大家只需要这样就可以了

Promise.all([promise接口1,promise接口2]).then(values => {
    console.log(values) // 在这里会输出一个数组。它就是promise接口1和promis接口2 的集合
})
写到这里很多工作过的同学一定用过CDN,在使用CDN的时候考虑到CDN的不可靠性会准备备用的CDN

这个时候的需求时如果主CDN无法使用 就使用备用CDN

同样可以使用串联的思路

但是Promise在这里也给我们提供了一个很好的方法

CDN1和CDN2哪一个接口请求速度快就使用哪一个。

Promise.race([promise接口1,Promise接口2]).then(value => {
    console.log(vlaue) // 这里会返回最先请求到的数据,也就是最先改变状态的Promise而不会再去管后请求到的数据
})

标签: javascript ES6

评论(0) 浏览(477)

JavaScript中的map

2019-11-8 张宇童 学习日志

以下是我个人对map对象的一些理解,如有不足之处请多批评指正:

1、map可以传入一个可遍历的对象
2、map传入的数组必须是一个可遍历的对象,不能是任意值。
3、map必须传入key、value的形式 example:[[k,v],[k,v]
4、map的key可以是任意值 函数、对象...
5、map添加数据不是用add而是用set
6、map的set方法可以用作修改
7、使用删除或查找等方法都是使用map的索引,而不是值
8、使用forEach遍历时,第一个参数是value,第二个是key

let map = new Map([['hello', 'world'],['name', 'Joky']])
console.log(map) // Map(2) {"hello" => "world", "name" => "Joky"}
// 添加
map.set('age', 18)
console.log(map) // Map(3) {"hello" => "world", "name" => "Joky", "age" => 18}
// 修改
map.set('age', 12)
console.log(map) // Map(3) {"hello" => "world", "name" => "Joky", "age" => 12}
// 删除
map.delete('age')
console.log(map) // Map(2) {"hello" => "world", "name" => "Joky"}
// 全部清空
map.clear()
console.log(map) // Map(0) {}
map.set('hello', 'world').set('name', 'Joky').set('age', 18)
// 获取map的键值对个数
console.log(map.size) // 3
// 判断某个值是否存在
console.log(map.has('hello')) // true
// 给定键获取值 
console.log(map.get('hello')) // world
// 获取map的所有键
console.log(map.keys()) // MapIterator {"hello", "name", "age"}
// 获取map的所有值
console.log(map.values()) // MapIterator {"world", "Joky", 18}
// 获取map的键值对
console.log(map.entries()) // MapIterator {"hello" => "world", "name" => "Joky", "age" => 18}
// map的遍历
map.forEach((v, k) => {
    console.log(v, k)
    // world hello
    // Joky name
    // 18 "age"
})
for (let [k, v] of map) {
    console.log(k, v)
    // hello world
    // name Joky
    // age 18
}
// 函数键的演示
function o () {}
map.set(o, '我是一个函数')
console.log(map) // Map(4) {"hello" => "world", "name" => "Joky", "age" => 18, ƒ => "我是一个函数"}

标签: javascript ES6

评论(0) 浏览(429)

JavaScript中的set数据结构

2019-11-8 张宇童 学习日志

我个人关于set的一些理解

1、set 接受的参数是一个可遍历的对象而不一定是一个数组
2、set加入新的数据使用add('hello')
3、set加入数据的时候可以链式操作
4、set如果存入了重复的数据将会自动过滤
5、set还是一个键值对
6、set很难改

// 删除元素
set.delete('goodbay')
console.log(set) // Set(1) {"hello"}
// 清空元素
set.clear()
console.log(set) // Set(0) {}
// 添加元素
set.add('hello').add('goodbay')
console.log(set) // Set(2) {"hello", "goodbay"}
// 检查元素是否存在
console.log(set.has('hello')) // true
// 检查数据元素个数
console.log(set.size) // 2
// 取set所有的键
console.log(set.keys()) // SetIterator {"hello", "goodbay"}
// 取set所有的值
console.log(set.values()) // SetIterator {"hello", "goodbay"}
// 取set的键值对
console.log(set.entries()) // SetIterator {"hello" => "hello", "goodbay" => "goodbay"}
// 可以使用forEach遍历
set.forEach(x => {
    console.log(x) 
    // hello
    // goodbay
})
// 可以使用for...of...进行遍历
for (i of set) {
    console.log(i)
    // hello
    // goodbay
}

标签: javascript ES6

评论(0) 浏览(467)

JavaScript中的结构赋值

2019-11-8 张宇童 学习日志

在ES5中如果有一个数组有很多的元素。我们可能需要使用数组的索引一个一个的取出来。

这个明显是比较麻烦的。

在ES6中就有了新的取数组中的元素方式

let arr = ['hello', 'world']

let [firstName, lastName] = arr

console.log(firstName, lastName)
 如果有多个元素的话我只想取指定的第几个,而不取前面的值呢?

let arr = ['one', 'two', 'three', 'four', 'five']
// 如果这个时候我只要最后一个呢?怎么办呢?
let [,,,,lastName] = arr 
console.log(lastName)

标签: javascript ES6

评论(0) 浏览(542)

JavaScript中的字符串模版

2019-11-8 张宇童 学习日志

我个人认为这个功能并不是那么简单。

可能有更多实用的功能我只是没有发现。

如果只是那么简单这个功能有点...

let user_type = 'ordinary';
function handle(strings, type) { // 这里指的注意的是第一个参数是个数组,将所有的字符串常量被变量分割的收集起来,第二个参数是一个变量,可以有多个变量对应的有多个参数
    let output = strings[0];
    let varstr;
    if (type == 'ordinary') {
        varstr = '单价是100元人民币';
    }else {
        varstr = '批发价是50元人民币';
    }
    return `${output}${varstr}`
}

let show = handle`您购买的商品${user_type}`
console.log(show)

标签: javascript ES6

评论(0) 浏览(377)

ES5、ES6中的参数默认值

2019-11-5 张宇童 学习日志

在ES5中设置默认值是十分麻烦的一件事情

大家看一下,了解就好


function add(x, y, z) {
    if (y === undefined) {
        y = 12
    }
    if (z === undefined) {
        z = 20
    }
    return x + y + z;
}
add(1) // return 33


大家再来看ES6中的默认值处理方式

function add (x, y = 10, z = 20) {
    return x + y + z
}
add(3) // reutrn 33

标签: javascript ES5

评论(0) 浏览(469)

深入理解JavaScript中的class

2019-11-5 张宇童 学习日志

Class

Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。

这是摘自阮一峰老师的博客,这句话放在 ES5 可以说不为过,然而到了 ES6 这么说就已经不严谨了。因为 ES6 中已经有了专属的 class 语法了。

有的同学喜欢函数式的编程方式,有的同学喜欢面向对象的编程思维,我们今天不论长短,重点讲述怎么使用 ES6 的 class 语法完成面向对象的开发。

Intro

对于面向对象编程而言,更关注类的声明、属性、方法、静态方法、继承、多态、私有属性。

Basic Syntax

首先我们要先来说明在 JavaScript 世界里如何声明一个 “类”。在 ES6 之前大家都是这么做的:

let Animal = function (type) { 
    this.type = type 
    this.walk = function () { 
        console.log(`I am walking`) 
    } 
} 
let dog = new Animal('dog')
let monkey = new Animal('monkey')

在上述代码中,我们定义了一个叫 Animal 的类,类中声明了一个属性 type、一个方法 walk;然后通过 new Animal 这个类生成实例,完成了类的定义和实例化。当然你也可以这样写:

let Animal = function (type) {
  this.type = type
}

Animal.prototype.walk = function () {
  console.log(`I am walking`)
}

let dog = new Animal('dog')
let monkey = new Animal('monkey')

在 ES6 中把类的声明专业化了,不在用 function 的方式了,请看:

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
}
let dog = new Animal('dog')
let monkey = new Animal('monkey')

很明显,从定义上就很专业了,有构造函数、方法,但是 ES6 增加了新的数据类型 class 吗?

console.log(typeof Animal); //function

可以发现 class 的类型还是 function,和 ES5 貌似并没有什么区别,那么 class 中定义的方法在哪呢?我们知道只要是函数,就一定会有 prototype 对象。那么类的方法和 prototype 对象有什么关系呢?

console.log(Animal.prototype);
// {constructor: ƒ, walk: ƒ}
//   constructor: class Animal
//   walk: ƒ walk()
//   __proto__:
//   constructor: ƒ Object()
//   hasOwnProperty: ƒ hasOwnProperty()
//   isPrototypeOf: ƒ isPrototypeOf()
//   propertyIsEnumerable: ƒ propertyIsEnumerable()
//   toLocaleString: ƒ toLocaleString()
//   toString: ƒ toString()
//   valueOf: ƒ valueOf()
//   __defineGetter__: ƒ __defineGetter__()
//   __defineSetter__: ƒ __defineSetter__()
//   __lookupGetter__: ƒ __lookupGetter__()
//   __lookupSetter__: ƒ __lookupSetter__()
//   get __proto__: ƒ __proto__()
//   set __proto__: ƒ __proto__()

可以看出在 Animal.prototype 对象上有两个方法,一个是构造函数(constructor)、一个是自定义的方法(walk)。这是不是和 ES5 的第二种写法一模一样?我们再来看下属性,在 ES5 中有个 API 用来判断对象的自有属性(hasOwnProperty)。

console.log(dog.hasOwnProperty('type')); //true

这个表现也和 ES5 中直接使用 function 定义类的方式相同,所以得出一个结论:class 的方式是 function 方式的语法糖。

Setters & Getters

对于类中的属性,可以直接在 constructor 中通过 this 直接定义,还可以直接在类的顶层来定义:

class Animal {
  constructor (type, age) {
    this.type = type
    this._age = age
  }
  get age () {
    return this._age
  }
  set age (val) {
    this._age = val
  }
}

这个代码演示了,通过 get/set 来给类定一个属性,不过貌似没有说服力。因为 age 和 _age 都是类的属性,而且是相同的含义这样做感觉没有实际用途。但是如果一个属性是个只读的呢?

class Animal {
  constructor (type) {
    this.type = type
  }
  get addr () {
    return '北京动物园'
  }
}

毋庸赘述,大家都能看出来含义。再来看下如下的应用场景:

class CustomHTMLElement {
  constructor (element) {
    this.element = element
  }
  get html () {
    return this.element.innerHTML
  }
  set html (value) {
    this.element.innerHTML = value
  }
}

利用 set/get 实现了对 element.innerHTML 的简单封装。

可是,有时候我们真的需要设置一个私有属性(闭包),然后通过一定的规则来限制对它的修改,利用 set/get就可以轻松实现。

let #age = 1
class Animal {
  constructor(type) {
    this.type = type
  }
  get age() {
    return #age
  }
  set age(val) {
    if (val > 0 && val < 10) {
      #age = val
    }
  }
}

Static Methods

静态方法是面向对象最常用的功能,在 ES5 中利用 function 实现的类是这样实现一个静态方法的。

let Animal = function (type) {
  this.type = type
  this.walk = function () {
    console.log(`I am walking`)
  }
}

Animal.eat = function (food) {
  console.log(`I am eating`);
}

在 ES6 中使用 static 的标记是不是静态方法,代码如下:

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
  static eat () {
    console.log(`I am eating`)
  }
}

有没有很清爽,代码可读性一下子就上来了。

Sub Classes

面向对象只所以可以应对复杂的项目实现,很大程度上要归功于继承。如果对继承概念不熟悉的同学,可以自行查询。在 ES5 中怎么实现继承呢?

// 定义父类
let Animal = function (type) {
  this.type = type
}
// 定义方法
Animal.prototype.walk = function () {
  console.log(`I am walking`)
}
// 定义静态方法
Animal.eat = function (food) {
  console.log(`I am eating`)
}
// 定义子类
let Dog = function () {
  // 初始化父类
  Animal.call(this, 'dog')
  this.run = function () {
    console.log('I can run')
  }
}
// 继承
Dog.prototype = Animal.prototype

从代码上看,是不是很繁琐?而且阅读性也较差。再看看 ES6 是怎么解决这些问题的:

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
  static eat () {
    console.log(`I am eating`)
  }
}

class Dog extends Animal {
  constructor () {
    super('dog')
  }
  run () {
    console.log('I can run')
  }
}

虽然 ES6 在类的定义上仅是 ES5 定义类的语法糖,但是从开发者的角度而言,开发更有效率了,代码可阅读性大大提升。

练习

  1. 请实现一个堆栈类,具备 push、pop 功能。
  2. 请回忆下自己在业务中有哪些场景可以用类来实现。

标签: javascript ES6

评论(0) 浏览(516)

Powered by emlog