JavaScript #
基本语法 #
hasOwnProperty 与 in #
hasOwnProperty
检查属性是否对象本身的一个成员,此方法不检查原型链。
in
检查对象或其原型链中中是否有此属性。
function Test(){
this.a = 'abc';
}
Test.prototype.b = 'efg';
var test = new Test;
alert(test.hasOwnProperty('a')); //输出 true
alert(test.hasOwnProperty('b')); //输出 false
alert('a' in test); //输出 true
alert('b' in test); //输出 true
let 与 const #
let
类似于 var
,但是所声明的变量,只在 let
命令所在的代码块内有效,所以很适合作为 for 计数器。
const
则用于声明常量,指向的是地址。
作用域 #
JavaScript 的作用域是由函数决定的。 函数作用域的嵌套关系是由定义时决定的而不是调用时,所以 JavaScript 的作用域称为静态作用域,又叫词法作用域。
块作用域 #
ES6 有了块级作用域,所以自释放函数不再有必要
跨模块常量 #
导出常量
export const A = 1;
使用常量
import {A, B} from './constants';
import * as constants from './constants';
解构变量 #
var [a, b, c] = [1, 2, 3];
let [head, ...tail] = [1, 2, 3, 4];
var { bar, foo } = { foo: "aaa", bar: "bbb" };
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
}
let { id, status, data: number } = jsonData;
默认值
var [foo = true] = [];
函数结构+默认值
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
工具 #
Babel #
用于将高版本的 js 转换为低版本的 js
安装 #
为了各项目的版本问题,尽量不要使用全局安装
npm install --save-dev babel-cli
使用 #
编译文件
babel <src_js> -o <target_js>
编译目录
babel <src_dir> -d <target_dir>
结合 gulp 实时编译 ES2015(ES6) #
- 安装 gulp-babel
npm install --save-dev gulp-babel
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-stage-0
- 安装 gulp
npm install --global gulp gulp-cli
npm install --save-dev gulp
- 创建
.babelrc
,指定规则
{
"presets": [
"es2015"
],
"plugins": []
}
- 创建
gulpfile.js
var gulp = require('gulp');
var babel = require('gulp-babel');
const es6 = {
src: 'src/*.js',
dest: 'target_dir'
}
gulp.task('babel', function () {
return gulp.src(es6.src)
.pipe(babel())
.pipe(gulp.dest(es6.dest))
});
gulp.task('watch', function () {
gulp.watch(es6.src, ['babel']);
});
- 在
package.json
创建任务
"scripts": {
"foo":"gulp watch"
}
- 运行
npm run watch
执行任务
Browserify #
Browserify 可以以 CommonJS 方式为浏览器端的 js 添加 require 特性。
安装 #
npm install -g browserify
使用 #
- 编写需要进行预编译的普通 js 文件。
- 编译为普通 js,语法:
browserify core.js > bundle.js
- 在页面导入生成后的普通 js 文件。
ES 6 #
String #
新增方法
var s = 'Hello world!';
console.log(s.startsWith('Hello')); // true
console.log(s.endsWith('!')); // true
console.log(s.includes('o')); // true
console.log('x'.repeat(3)); // xxx
遍历字符串
for (let c of 'foo') {
console.log(c);
}
多行字符串
console.log(`string text line 1
string text line 2`);
字符串模板
注意使用字符串模板使用
进行包裹。
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);
数字 #
无穷判断
console.log(Number.isFinite(NaN)); // false
console.log(Number.isFinite(Infinity)); // false
NaN 判断
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(15)); // false
字符串转数字
// ES 5
parseInt('12.34'); // 12
// ES 6
Number.parseInt('12.34'); // 12
类型判断
注意在 js 中 25.0
和 25
是一样的
Number.isInteger(25); // true
Number.isInteger(25.0); // true
Number.isInteger(25.1); // false
Math 工具方法
Math.trunc(-4.1); // -4
Math.sign(-5); // -1
Math.sign(5); // +1
Math.sign(0); // +0
array #
ArrayLike
只要对象有 length
属性,就可以通过 Array.from()
转换为真实的数组对象。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let array = Array.from(arrayLike);
console.log(array.pop()); // c
console.log(array.length); // 2
let set = new Set(['a', 'b']);
console.log(Array.from(set)); // ['a', 'b']
Array.from()
还接收第二个参数实现 map()
功能。
let nums = [1, 2, 3];
console.log(Array.from(nums, n => n * 3)); // [ 3, 6, 9 ]
// 以上相当于
console.log(Array.from(nums).map(n => n * 3)); // [ 3, 6, 9 ]
Array.of() 用于将多个参数转为数组
console.log(Array.of(1, 2, 3).length); // 3
Loop
for (let i of array.keys()) {
console.log(i); // 0 1
}
for (let v of array) {
console.log(v); // a b
}
for (let e of array.entries()) {
console.log(e[0], e[1]);
}
其它方法
console.log([1, 2, 3, 4, 5, 6].filter(n => n % 2 == 0)); // 2 4 6
console.log([1, 2, 3, 4, 5, 6].find(n => n % 2 == 0)); // 2
[10, 'a'].forEach((x, i) => console.log(x, i)); // 1
[10, 'a'].every(x => x === 'a'); // false
[10, 'a'].some(x => x === 'a'); // true
[, 'a', undefined, null].join('#'); // "#a##"
[, 'a', undefined, null].toString(); // ",a,,"
正则表达式 #
var regex = new RegExp('xyz', 'i');
regex = /xyz/i;
// ES 6 新支持
regex = new RegExp(/xyz/i);
Set #
var set = new Set();
[2, 3, 5, 4, 5, 2, 2].map(n => set.add(n));
set = new Set([1, 2, 3, 4, 4]);
console.log([...set]); // [ 1, 2, 3, 4 ]
set.add(10);
set.delete(3);
console.log(set.has(1)); // true
// Loop
for (let i of set) {
console.log(i); // 1 2 4 10
}
Map #
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是 “键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
let map = new Map();
map.set('x', 1);
map.set('y', 10);
console.log(map.get('x'));
console.log(map.has('y'));
map.delete('x');
let m = new Map().set('x', 10).set('foo', 'bar');
console.log([...m]);
// Loop
for (let entry of map.entries()) {
console.log(entry[0], entry[1]);
}
Iterator #
只要实现了 iterator
就可以用于 let..of
循环。
const colors = ['red', 'green', 'blue'];
let iterator = colors[Symbol.iterator]();
for (let v of iterator) {
console.log(v); // red green blue
}
for (let i in colors) {
console.log(i); // 0 1 2
}
for (let v of colors) {
console.log(v); // red green blue
}
Object.keys(colors).forEach(function (key) {
console.log(key);
});
Function #
剪头函数
var f1 = function (v) {
return v;
};
var f2 = v => v;
console.log(f1('foo'));
console.log(f2('bar'));
对象 #
创建对象 #
var foo = {};
foo.name = 'foo';
foo.echo = function () {
return 'foo';
}
使用对象初始化器创建对象 #
var foo = {
name: 'foo',
echo: function () {
return 'foo';
}
};
使用构造函数创建对象 #
定义构造函数
function Foo(name) {
this.name = name;
this.echo = function () {
return 'foo';
};
}
使用构造函数
var foo = new Foo('foo');
属性 #
属性的简写
ES6 允许在对象之中,只写属性名,不写属性值。这时,属性值等于属性名所代表的变量。
var foo = 'bar';
var bar = {foo};
console.log(bar); // { foo: 'bar' }
// 相当于
console.log({foo: foo}); // { foo: 'bar' }
function f(x, y) {
return {x, y};
}
console.log(f(1, 2)); // { x: 1, y: 2 }
方法 #
方法的简写
var obj = {
hello(){
console.log('Hello!');
}
};
var obj2 = {
hello: function () {
console.log('Hello!');
}
};
obj.hello();
obj2.hello();
assgin #
Object.assign()
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
var target = {};
var source1 = {x: 1};
var source2 = {y: 10};
Object.assign(target, source1, source2);
console.log(target);
借助 assign()
方法可以完成对象的深复制。
function clone(source) {
return Object.assign({}, source);
}
target = clone(source1);
call, apply, bind #
可以用 call 或 apply 方法改变函数上下文,但如果重复使用会不方便,因为每次都要把上下文对象作为参数传递,而且还会使代码变得不直观。针对这种情况,我们可以使用 bind 方法来永久地绑定函数的上下文。
func.bind(ctx, args...);
bind 还有一个重要的特性就是可以绑定参数列表
原型对象 #
原型对象指构造函数的 prototype
属性指向的对象。每个对象可以通过 prototype
扩展构造函数,也可以通过 __proto__
属性访问其指向的原型,从任何对象沿着它开始遍历最终都可以追溯到 Object.prototype
Symbol #
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。
创建 Symbol #
Symbol 值通过 Symbol 函数生成。
var s1 = Symbol();
var foo = Symbol("foo");
通过 Symbol.for(name)
创建的 Symbol 会放在池中,之后可以得到重用。
var s3 = Symbol('s3');
var s4 = Symbol('s4');
var s5 = Symbol.for('s4');
var s6 = Symbol.for('s4');
console.log(s3 === s4); // false
console.log(s5 === s4); // false
console.log(s5 === s6); // true
作为属性名 #
对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
有三种实现方式
第一种
var obj1 = {};
obj1[foo] = 'one';
第二种
var obj2 = {
[foo]: 'two'
};
第三种
var obj3 = {};
Object.defineProperty(obj3, foo, {value: 'three'});
其它操作 #
Symbol 作为属性名,该属性不会出现在 for...in
、for...of
循环中,需要通过 Object.getOwnPropertySymbols()
来获得。
for (let v in obj1) {
console.log(v); // bar
}
console.log(Object.getOwnPropertySymbols(obj1)); // [ Symbol(foo) ]
Promise #
ES6 原生提供 Promise 功能。
var fs = require('fs');
var file = '../inputs/students.json';
var promise = new Promise(function (resolve, reject) {
fs.readFile(file, function (err, res) {
if (err)
reject(err);
else
resolve(res);
});
});
promise.then(function (res) {
return JSON.parse(res);
}, function (err) {
console.error(err)
return err;
}).then(function (res) {
console.log(res);
});
Generator #
Generator 是普通函数,但是 function
后跟着星号,且函数体内可以含有 yield
关键字。调用时返回迭代器而不是立即执行。
以下创建了三个状态
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true }
hw.next() // { value: undefined, done: true }
yield
可以中断程序的运行,即执行到此将执行权让给其它函数。Generator 中不含有 yield
的话则相对于普通的惰性加载函数。
yield
可以包含参数,参数会作为 next
的返回值返回。
yield
用在表达式中需要添加括号,例:'foo' + (yield 2)
Generator 函数可以用在 for...of
循环中
function *foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
Generator 返回的迭代器对象可以抛出异常由 Generator 函数内部来处理
var g = function* () {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数。
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return("foo") // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
yield*语句
用于在一个 Generator 函数中执行另一个 Generator 函数
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
如果yield命令后面跟的是一个遍历器对象,需要在yield命令后面加上星号,表明它返回的是一个遍历器对象。这被称为yield*语句。
异步操作同步化
function* loadUI() {
showLoadingScreen();
yield loadUIDataAsynchronously();
hideLoadingScreen();
}
var loader = loadUI();
// 加载UI
loader.next()
// 卸载UI
loader.next()
Thunk 函数 #
Promise 只是将回调函数的横向加载,改成纵向加载,是回调函数的改进。
Thunk 函数
“求值策略”,即函数的参数到底应该何时求值。 一种意见是"传值调用"(call by value),即在进入函数体之前,参数表达式已经进行计算。 另一种意见是"传名调用"(call by name),将参数表达式作为整体传入。
编译器的"传名调用"实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。
function f(m){
return m * 2;
}
f(x + 5);
// 等同于
var thunk = function () {
return x + 5;
};
function f(thunk){
return thunk() * 2;
}
JavaScript语言是传值调用,它的Thunk函数含义有所不同。在JavaScript语言中,Thunk函数替换的不是表达式,而是多参数函数,将其替换成单参数的版本,且只接受回调函数作为参数。
// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);
// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
var Thunk = function (fileName){
return function (callback){
return fs.readFile(fileName, callback);
};
};
任何函数,只要参数有回调函数,就能写成Thunk函数的形式。
thunkify 模块
thunkify 模块可以将函数转换为 thunk 函数
var thunkify = require('thunkify');
var fs = require('fs');
var read = thunkify(fs.readFile);
read('package.json')(function(err, str){
// ...
});
async 函数 #
async 函数就是 Generator 函数的语法糖。将Generator函数的星号 * 替换成async,将yield替换成await,仅此而已。
Generator 版本
var fs = require('fs');
var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) reject(error);
resolve(data);
});
});
};
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
async 版本
var asyncReadFile = async function (){
var f1 = await readFile('/etc/fstab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
async 自带执行器,不用像 Generator 函数需要多次调用 next(),async 执行时会自动输出最后的结果。 async 返回值是 Promise,参数也是 Promise 对象,如果不是的话会被转换为 Promise 对象
async function getStockPriceByName(name) {
var symbol = await getStockSymbol(name);
var stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result) {
console.log(result);
});
多种形式
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} }
// 箭头函数
const foo = async () => {};
注意:await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中。
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
};
}
Html 操作 #
innerHTML #
使用 DOMContentLoaded
和 insertAdjacentHTML
代替 document.write()
和 innerHtml
。
document.addEventListener("DOMContentLoaded", function (e) {
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
document.body.innerHTML += "<p>today is " + year + "/" + month + "/" + day;
<!--更高速-->
document.body.insertAdjacentHTML("beforeend", "<p>today is " + year + "/" + month + "/" + day);
}, false)
前端工具总结 #
Browserify 打包 Node 模块的依赖环境,使其可以运行在浏览器中 PostCSS 使用 JS 来处理 CSS