2019-02-05 13 JavaScript基础语法
基础语法
- 数据类型
Undefined
Null
Boolean
String
Number
Object
Symbol
- HTML DOM
- 修改HTML内容,
document.getElementById(id).innerHTML="xxx"
- 修改HTML属性,
document.getElementById(id).attribute=new value
- 修改HTML样式,
document.getElementById(id).style.property = new style
- 响应事件,
onclick=JavaScript
- 使用HTML DOM分配事件,
document.getElementById(id).onCLick=function(){displayDate()}
- 修改HTML内容,
- JS Window
- Window
window.document.getElementById("header")
- Screenscreen.availWidth
可用屏幕宽screen.availHeight
可用屏幕高 - Locationwindow.location
获取当前页面URL
, 并重定向新的页面location.href
返回当前页面的URL
- Historywindow.history
包含浏览器历史window.history.back()
返回上一页window.history.forward()
向前加载页面 - TimingsetTimeout()
未来时间执行代码clearTimeout()
取消setTimeout()
- Cookiescookie
存储访问者的变量document.cookie=xxx
var
、let
和const
let
只有代码块有效..不支持变量提升…var
全局有效, 存在变量提升, 即先使用, 再说明, 如console.log(foo)//输出Undefined; var foo=2;
const
声明只读常量, 块级作用域有效
- 变量的解构赋值, 即从数组、对象取值, 对变量进行赋值(用途)
- 交换变量的值
let x=1;
let y = 2;
[x, y] = [y, x];
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据
let jsonData = {
status: "OK",
data:[123, 456]
};
let {status, data:number} = jsonData;
- 遍历
Map
结构
const map = new Map();
map.set('first', 'hello');
for(let [key, value] of map) {
...
}
- Symbol, 防止属性命名冲突, 为一种特殊数据类型
let s1 = Symbol();
let s2 = Symbol();
s1 === s2; //false
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2; //false
let mySymbol = Symbol();
let a{};
a[mySymbol] = 'Hello';
- Proxy, 用于修改操作的默认行为, 等同于在语言层面修改, 可以理解为在目标对象设置”拦截器”
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log('getting${key}');
return Reflect.get(target, key, receiver);
}
});
++obj.count;
// getting count!
- Reflect
- 将
Object
对象属于语言内部的方法, 放到Reflect
- 修改
Object
方法给予返回结果(true
,false
) Reflect
对象的方法与Proxy
对象的方法一一对应
- 将
function Greeting(name) {
this.name = name;
}
// new的写法
const instance = new Greeting('张三');
// Reflect#construct的写法
const instance = Reflect.construct(Greeting, '张三');
- Promise(异步编程的解决方案, 保存未来结束的结果)
- 状态
pending
(进行中)fulfilled
(已成功)rejected
(已失败)
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject) {
if(this.status === 200) {
}
});
return promise;
};
getJSON("/post.json").then(function(json) {
// do something
}, function(error) {
// handle error...
});
- Iterator和for..of循环
let arr = ['a', 'b'];
let iter = arr[Symbol.iterator]();
iter.next(); // {value: 'a', done:false}
iter.next(); // {value: 'b', done:false}
iter.next(); // {value: Undefined, done:true}
- Generator函数 (提供异步编程解决方案, Generator函数是个状态机, 封装多个内部状态)
function
关键字和函数名之间有个*
- 函数体内部使用
yield
表达式, 定义不同状态
// yield类似暂停指令; Generator执行必须调用遍历器对象的`next`方法, 指针移到下一个状态, 即调用`next`, 内部指针从函数头部或上一次执行停止的地方开始, 直到`yield`或者`return`.
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function* (a) {
var length = a.length;
for(var i = 0; i < length; i++) {
var item = a[i];
if(typeof item != 'number') {
yield* flat(item);
} else {
yield item;
}
};
};
for (var f of flat[arr]) {
console.log(f);
}
// 1, 2, 3, 4, 5, 6
- 异步
- 协程 (多线程互相协作, 完成异步任务; 优势: 代码写法类似同步)
- 协程
A
执行 - 协程
A
执行到一半, 进入暂停, 执行权转移到协程B
- 协程
B
交还执行权 - 携程
A
恢复执行
- 协程
- 协程 (多线程互相协作, 完成异步任务; 优势: 代码写法类似同步)
var fetch = require('node-fetch');
function* gen() {
var url = "https://api.github.com/users/github";
var result = yield fetch(url); // 返回Promise对象
console.log(result.bio);
};
var g = gen();
var result = g.next();
// Generator函数非常简介, 但是流程管理不方便(即何时执行第一阶段、何时执行第二阶段)
result.value.then(function(data) {
return data.json();
}).then(function(data) {
g.next(data);
});
Thunk
函数 (支持”“传名调用”, 即参数等在执行时求值)
// ES5版本
var Thunk = function(fn) {
return function() {
var args = Array.prototype.slice.call(arguments);
return function (callback) {
args.push(callback);
return fn.apply(this, args);
};
};
};
// ES6版本
const Thunk = function(fn) {
return function(...args) {
return function(callback) {
return fn.call(this, ...args, callback);
}
};
};
- Generator 函数的流程管理 (如果必须保证第一步执行完, 才能执行第二步, 则
Thunk
函数有用武之地)
var fs = require('fs');
var thunkify = require('thunkify');
var readFileThunk = thunkify(fs.readFile);
var gen = function* () {
var r1 = yield readFileThunk('/etc/fstab');
console.log(r1.toString());
var r2 = yield readFileThunk('/etc/shells');
console.log(r2.toString());
};
async
函数 (Generator函数的语法糖)- 内置执行器,
async
函数自带执行器, 不需要调用next()
- 语义更清晰,
async
和await
比星号和yield
更清晰 - 更广的适用性,
async
函数的await
命令后面支持 Promise对象和原始类型的值 - 返回值为Promise
- 内置执行器,
const asyncReadFile = async function() {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
- Class (为了和C++/Java语法更接近)
// ES5, 生成实例对象的传统方法通过构造函数
function Point(x, y) {
this.x = x;
this.y = y;
}
// ES6
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
- 闭包 (当一个函数返回了一个函数, 且内部的局部变量还被新函数引用, 即为闭包)
- 延时执行
- 封装
private
成员变量 - 简化多参数为单参数的函数,
Math.pow(x, y)
可简function make_pow(n) {return function(x) {return Math.pow(x, n)}}
// 外部代码无法访问变量x, 即闭包是携带状态的函数, 并且它的状态对外隐藏
'use strict';
function create_counter(initial) {
var x = initial || 0;
return {
inc: function() {
x += 1;
return x;
};
};
};
var c1 = create_counter(10);
c1.inc();//11
c1.inc();//12
- 继承和原型链
- 创建对象
function Student(name) {
this.name = name;
// var tom 和 var lucy的hello()函数的内存地址都不一样, 如果要共享, 则
// 需要调用Student.prototype.hello = ...;
this.hello = function() {
alert('Hello' + this.name + '!');
}
}
var tom = new Student('tom'); // 必须使用 new, 否则即为普通函数
// tom的原型链为:
// tom -> Student.prototype -> Object.prototype -> null, 即如果tom.age找不到会一直往原型链往上找...
- 原型继承 (继承实际是类型的扩展, JavaScript采用原型继承, 无法直接扩展Class, 因此需要修改原型链)
// 通过中间对象...
function PrimaryStudent(props) {
Student.call(this, props);//调用Student的构造方法
this.gradle = props.gradle || 1;
}
function F() {
}
F.prototype = Student.prototype;
// 修改PrimaryStudent.prototype为F, 即引用链调整为, PrimaryStudent.prototype -> new F -> Student.prototype
PrimaryStudent.prototype = new F();
// 修复PrimaryStudent原型的构造函数为PrimaryStudent...
PrimaryStudent.prototype.constructor = PrimaryStudent;
-
并发模型和事件循环
-
高阶函数 (函数作为参数, 即为高阶函数)
function add(x, y, f) {
return f(x) + f(y);
}
对象
key
和prototype
- 创建对象, JavaScript使用
{..}
表示对象
let obj = {
name: "object",
son: {
name: "son"
}
}
// 支持动态加、减属性
obj.age = 18;// 新增age属性
delete obj.age;//删除age属性
let obj = Object.create({name:"obj"})
- 属性的可枚举性和遍历
let obj = {foo:123};
Object.getOwnPropertyDescriptor(obj, 'foo');
//
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
- 属性的遍历
for ... in
, 返回对象自身和继承的可枚举属性(不含Symbol属性)Object.keys(obj)
返回对象自身可枚举属性的键名数组(不含Symbol属性)Object.getOwnPropertyNames(obj)
返回对象自身所有属性的键名数组(不含Symbol属性)Object.getOwnPropertySymbols(obj)
返回对象自身所有Symbol属性的键名数组Reflect.ownKeys(obj)
返回自身所有键名数组
this
关键字- 默认绑定, 不带任何修饰的函数调用
- 隐式绑定, 绑定上下文对象
- 显示绑定, 通过
call
、apply
、bind
显示调用绑定this new
绑定,new XXX()
函数的构造调用this
绑定优先级,new
绑定 > 显示绑定 > 隐式绑定 > 默认绑定
super
关键字(当前对象的原型对象)
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo; // 等同于Object.getPrototypeOf(this).foo(属性)
}
}
Object.setPrototypeOf(obj, proto);
obj.find(); // hello
- 扩展运算符
- 对象的扩展运算符
...
, 用于取出对象的所有可遍历属性, 拷贝到当前对象
- 对象的扩展运算符
let z = {a:3, b:4};
let n = {...z};
n // {a:3, b:4}
函数
- 默认值
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello');
- 解构赋值默认值结合使用
function f({x, y=5}) {
console.log(x, y);
}
f({x:1}); // 1 5
- 函数的
length
属性
(function (a) {}).length // 1
- 作用域 (一旦设置参数的默认值, 函数进行声明初始化时, 参数形成单独的作用域(Context); 等初始化结束, 作用域就消失)
var x=1;
function foo(x, y = function() {x=2;}) { // 参数x在()作用域里, 因此执行y, x的赋值不生效
var x = 3;
y();
console.log(x);
}
foo(); // 3
x // 1
- 链式作用域(
var
声明的变量作用域为当前执行上下文(execution context), 即函数或全局作用域)
// 作用域链为 inner -> rainmain -> window
<script type="text/javascript">
var rain = 1;
function rainman() {
function inner() {
alert(rain);
}
inner();
}
rainman(); //输出1
</script>
- 箭头函数
var f = v => v;
// 等同于
var f = function(v) {
return v;
};
- 尾调用优化 (调用帧(Call Frame), 即
A
调用B
, 保存A
帧, 等B结束回到A
;尾调用相当于不需要保存A
帧)
// 例子
function f() {
let m = 1;
let n = 2;
return g(m+n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
- rest参数
function add(...values) {
...
}
add(1, 2, 3);
异步编程
- 回调函数
fs.readFile('/etc/password', 'utf-8', function(err, data) {
if(err) throw err;
console.log(data);
});
- 事件监听
- 发布/订阅
- Promise对象 (链式调用)
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function(data) {
console.log(data.toString());
})
.then(function () {
return readFile(fileB);
})
.then(function (data) {
console.log(data.toString());
})
.catch(function (err) {
console.log(err);
});
- Generator函数(ES6)
模块化(CommonJS, AMD, CMD, ES6)
- CommonJS
module.exports.firstName=firstName
, 导出/暴露函数或者变量- CommonJS模块即对象, 加载(查找)模块, 调用
require('fs')
, 运行时加载, 缺点是无法”静态优化”
- ES6
export
, 暴露变量、函数让外部模块访问
// 写法1
export var firstName = 'Michael';
// 写法2
var firstName = 'Michael';
export {firstName};
// 默认导出/暴露, 不需要导入
export default firstName = 'Michael';
import
, 加载外部模块
import {firstName} from './profile.js'
// 重新命名使用as关键字
// 引用变量只读, 不允许修改
import {firstName as name} from './profile.js'
// 整体加载模块
import * as profile from './profile.js'