理解Object.defineProperty

vue.js的双向数据绑定就是通过Object.defineProperty方法实现的,俗称属性拦截器。Object.defineProperty不支持shim及es5,是一个新的特性,所以不支持IE8及以下浏览器。

Object.defineProperty()

方法会直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。

1
2
3
4
5
6
7
// 语法:
/*
* @param: obj:需要定义属性的对象;
* prop:需要定义或修改的属性;
* descriptor:将被定义或修改属性的描述符
*/
Object.defineProperty(obj,prop,descriptor)

对象里目前存在的属性描述符主要有两种形式: 数据描述符和存取描述符。

  • 数据描述符: 拥有可写或不可写值的属性*

可选键值:
configurable: 当且仅当configurable为true时,改属性描述符才能够被改变,也能被删除
enumerable: 当其值为true时,该属性才能够出现在对象的枚举属性中,默认为false
writable: 当且仅当该属性的值为true时,该属性才能被赋值运算符改变, 默认为false。
value: 该属性对应的值,可以是任意有效的javascript的值(数值,对象,函数等),默认为undefined

  • 存取描述符: 由一对getter-setter函数功能来描述的属性*

可选键值:
configurable: 当且仅当configurable为true时,改属性描述符才能够被改变,也能被删除
enumerable: 当其值为true时,该属性才能够出现在对象的枚举属性中,默认为false
get: 给属性提供getter的方法,如果没有 getter 则为undefined。当我们读取某个属性的时候,其实是在对象内部调用了该 方法,此方法必须要有return语句。该方法返回值被用作属性值。默认为 undefined
set:设置属性值的方法, 如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。也就是说,当我们设置某个属性的时候,实际上是在对象的内部调用了该方法。

  • note:两者不能同时定义, 否则报错==

示例:

1
2
3
4
5
6
7
8
9
10
11
12
var a = {};
Object.defineProperty(a, 'b', {
set: function(newValue) {
console.log('赋值操作, 赋值' + newValue);
},
get: function() {
console.log('取值操作');
return 2;
}
});
a.b = 1; // 赋值操作,赋值1
a.b; // 取值操作2

Object对象有一个freeze的方法,用于实现对象属性和方法的不可更改

1
2
3
4
// 使用方法:
const arr = [1,2,3,4];
Object.freeze(arr); // 变量arr不可更改
arr.push(5); // 报错:不能添加属性

Object.definePropperty也可以实现规定变量的不可更改

1
2
3
4
5
const obj = { key: 'chris', vlaue: 'person' };
Object.defineProperty(obj, 'key', {
configurable: false, // 不可删除
writable: false, // 不可写
});

手把手用typescript写React项目

最近写了一个基于React的UI库项目,本意是希望使用TypeScript去写。正好Webpack4.x也没有配过,正好能看一下比起webpack3的配置有哪些区别。这次的教程就主要写下创建项目的顺序,还有尿点。首先创建一个文件夹,然后使用yarn创建项目和package.json文件 1yarn init 接下去就是各种回车和输入,知道package.json文件创建完成。 接着创建目录-build |-webpack.base.js |-webpack.dev.js |-webpack.prd.js-src |-component |-style |-main.tsx-index.html-index.js index.html: 模板文件index.js: npm插件通过impo...

阅读全文

webpack4.x 配置下载第三方库,分离js成单个文件引入HTML

依赖webpack打包时,需要引入第三方库的方法有许多,最简单的是直接npm下载并引入(不推荐)

1
2
3
4
5
6
cnpm i jquery -S
import $ from 'jquery'
$(xxx).on()
$(xxx).css()

还有一种方式是通过webpack自带的ProvidePlugin这个api引入

1
2
3
4
5
6
7
8
9
10
11
12
13
const webpack = require('webpack');
// 在plugins里面使用
plugins:[
new Webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title:'Hello World',
template: './src/index.html' //模板地址
}),
new Webpack.ProvidePlugin({ //下载Jquery库
$:'jquery'
})
]

通过ProvidePlugin和 import直接引入区别:

  • import $…,引入之后,无论你在代码中是否使用jquery,打包后,都会打进去,这样其实产生大量的冗余js
  • Provideplugin, 只有你在使用到此库,才会打包

在webpack3.x版本之前:使用new webpack.optimize.CommonsChunkPlugin现在已经不支持
提取第三方库(或者想单独提出来的)js库,增加一个optimization配置,和plugins同级

1
2
3
new webpack.optimize.CommonsChunkPlugin({
name:'jquery'
})

在webpack4.x以后提取第三方库或js单独引入html使用如下方法

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
// 1.配置入口文件
entry:{
entry: jsonConfig.entry,
jquery:'jquery',
angular:'angular'
}
// 2.下载库
plugins: [
new Webpack.ProvidePlugin({
$:'jquery', //下载Jquery
A:'angular' // 下载Angular
})
]
// 3.分离单独JS,注意:optimization和Plugins是同级,而不是在Plugins内
optimization:{
splitChunks:{
cacheGroups:{ // 单独提取JS文件引入html
aaa:{ // 键值可以自定义
chunks:'initial', //
name:'jquery', // 入口的entry的key
enforce:true // 强制
},
bbb:{
chunks:'initial',
name:'angular',
enforce:true
}
}
}
}

React组件间通信

前言关于组件化开发规范,希望申明一个原则——能不用Redux就不要使用Redux解决。在普通开发中遇到父子组件通信时,需要考虑通过传统Props和子组件的回调来解决基本通信,今天主要整理关于组件通信的解决方案 父组件向子组件通信父组件通过向子组件传递 props,子组件得到 props 后进行相应的处理。1234567891011121314.....import Sub from 'Sub.js'; // 子组件class Container extends React.Component{ constructor(){ super(); } render(){ return ...

阅读全文

es6里的__proto__ 属性,Object.setPrototypeOf(),Object.getPrototypeOf()

( 1 )proto 属性proto属性(前后各两个下划线),用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括 IE11 )都部署了这个属性。 12345678// es6 的写法 var obj = { method: function() { ... } }; obj.__proto__ = someOtherObj; // es5 的写法 var obj = Object.create(someOtherObj); obj.method = function() { ... }; 该属性没有写入 ES6 的正文,而是写入了附录,原因是proto前后的双下划线,说明它本质上是一个...

阅读全文

浅谈super如何实现

应该是super关键字只能在class内部使用,外部直接调用就会出错,因为你根本不知道父类的构造函数是那个啊。它们只是语法糖而已,JavaScript仍然是基于原型的继承,super本质上就是借用构造函数的一种表现形式,我们可以通过如下清楚看出来。

原始的class实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function() {
return this.name;
}
function Child(name, age) {
//借用构造函数
Parent.call(this, name);
this.age = age;
}
//实现继承
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.getAge = function(){
return this.Age;
};
var people = new Child("lily", 20);
console.log(people.getName());

语法糖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Parent {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
getAge() {
return this.age;
}
}
const people = new Child("lily", 20);
console.log(people.getName());

面向对象的Javascript-了解ES6类

概述non-class(非类)代码1234567891011121314151617// set today to December 24let today = { month: 12, day: 24,}; let tomorrow = { year: today.year, month: today.month, day: today.day + 1,}; let dayAfterTomorrow = { year: tomorrow.year, month: tomorrow.month, day: tomorrow.day + 1 < = 31 ? tomorrow.day + 1 : 1,}; ...

阅读全文

全角半角的字符检测与相互转换

全角和半角是什么意思啊?

全角:
是一种电脑字符,是指一个全角字符占用两个标准字符(或两个半角字符)的位置。全角占两个字节。
汉字字符和规定了全角的英文字符及国标GB2312-80中的图形符号和特殊字符都是全角字符。在全角中,字母和数字等与汉字一样占据着等宽的位置。

半角:
是指一个字符占用一个标准的字符位置。半角占一个字节。
半角就是 ASCII 方式的字符,在没有汉字输入法起作用的时候,输入的字母、数字和字符都是半角的。
每个半角字符只占用一字节的空间(一字节有8位,共256个编码空间)。汉语、日语、及朝鲜文等象形字语言的字库量远大于256个编码空间,所以改用两个字节来储存。同时,由于中日韩等象形文字的书写习惯,如果统一使用全角字符的话,排列起来也显得整齐。
为了排列整齐,英文和其它拉丁文的字符和标点也提供了全角格式。

如何判断在javascript中输入的文字是全角还是半角?

1
2
3
4
5
6
7
8
9
10
11
function issbccase(source) {
if(source=="") {
return true;
}
var reg=/^[\w\u4e00-\u9fa5\uf900-\ufa2d]*$/;
if(reg.test(source)) {
return false;
}else {
return true;
}
}

半角全角相互转换的js函数

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
///全角空格为12288,半角空格为32
///其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
//半角转换为全角函数
function ToDBC(txtstring) {
var tmp = "";
for(var i=0;i<txtstring.length;i++) {
if(txtstring.charCodeAt(i)==32) {
tmp= tmp+ String.fromCharCode(12288);
}
if(txtstring.charCodeAt(i)<127) {
tmp=tmp+String.fromCharCode(txtstring.charCodeAt(i)+65248);
}
}
return tmp;
}
//全角转换为半角函数
function ToCDB(str) {
var tmp = "";
for(var i=0;i<str.length;i++) {
if(str.charCodeAt(i)>65248&&str.charCodeAt(i)<65375) {
tmp += String.fromCharCode(str.charCodeAt(i)-65248);
}
else {
tmp += String.fromCharCode(str.charCodeAt(i));
}
}
return tmp
}

面试的心得(2017-6-19)

有幸和一位大神聊过,发现自己有好多地方都略显不足。

函数式编程和面向对象式编程?

面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

将业务逻辑细化,抽象,封装成一个个功能函数,并借助语言自带的高阶函数api,将整个业务流程转化为函数之间的相互调用,这就是函数式编程。

什么是对象?

对象就是属性和方法的集合,所有的数据类型都是对象,他们都有自己的默认支持的方法。

Array.prototype.slice.call

查看jQuery的源代码,会看到类似:

slice = Array.prototype.slice,

array = Array.prototype.slice.call( array, 0 );

的代码。

干嘛用的呢?

作用就是:将类似数组的对象转换为真实的数组。

真实数组具有slice方法,可以对数组进行浅复制(不影响原数组),返回的依然是数组。

类似数组虽然有length属性,可以使用for循环遍历,却不能直接使用slice方法,会报错!但是通过Array.prototype.slice.call则不会报错,本身(类似数组)被从头到尾slice复制了一遍——变成了真实数组!

上一集demo中函数内部的arguments是应该都熟知的类似数组,于是:

Array.prototype.slice.call(arguments)

bind函数,改变上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
var OOO = {
color: "#cd0000",
element: $("#text"),
events: function() {
$("input[type='button']").addEventListener("click", function(e) {
this.element.style.color = this.color;
}.bind(this));
return this;
},
init: function() {
this.events();
}
};

为IE6~8自定义bind方法

1
2
3
4
5
6
7
8
9
10
if (!function() {}.bind) {
Function.prototype.bind = function(context) {
var self = this
, args = Array.prototype.slice.call(arguments);
return function() {
return self.apply(context, args.slice(1));
}
};
}

很多原理性的知识点无法从碎片连成面

看来在接下去的时间里,必须再好好学习基础知识。

array数组操作

数组常用方法数组的创建12345var arrayObj = new Array(); //创建一个数组var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]); //创建一个数组并赋值 要说明的是,虽然第二种方法创建数组指定了长度,但实际上所有情况下数组都是变长的,也就是说即使指定了长度为5,仍然可以将元素存储在规定长度以外的,注意:这时长度会随之改变 数组的元素的访问12var testGetArrValue = arrayObj[1]; //获取数组的元素值arrayObj[1] = &...

阅读全文

© 2018 Qing的前端开发Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero