九九乘法表
var str = ''
for(var i = 1; i <= 9; i++) {
for(var j = 1; j <= i; j++){
str += j + '*' i + '=' + i*j + '\t'
}
str += '\n'
}
console.log(str)
冒泡排序
var arr = []
var temp
for(var i = 0; i < arr.length -1; i++){
for(var j = 0; j < arr.length - i -1; j++){
if (arr[j] > arr[j+1]) {
temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] =temp
}
}
}
console.log(arr)
预解析
js引擎会把js里面的所有var和function提升到当前作用域的最前面。
分为变量预解析(变量提升) 和 函数预解析(函数提升)
变量提升: 就是把所有的变量声明提升到当前作用域最前面,但不提升赋值操作
函数提升: 就是把所有的函数声明提升到当前作用域最前面,但不调用函数
数组的常用方法
增删改
arr.push("hello") //在数组的末尾添加 返回添加元素后的数组长度 影响原数组
arr.unshift("hello") //在数组的头部添加 返回添加元素后的数组长度 影响原数组
arr.pop() //在数组的末尾删除一个元素 并返回删除的元素 影响原数组
arr.shift() //在数组的头部删除一个元素 并返回删除的元素 影响原数组
arr.splice(截取开始下标,截取个数,加入元素) //影响原数组
splice(index,count[,元素1,…,元素n])
splice() 方法功能比较强,它可以实现删除指定数量的元素、替换指定元素以及在指定位置添加元素。这些不同功能的实现需要结合方法参数来确定:
当参数只有 index 和 count 两个参数时,如果 count 不等于 0,splice() 方法实现删除功能,同时返回所删除的元素:从 index参数指定位置开始删除 count 参数指定个数的元素;
当参数为 3 个以上,且 count 参数不为0时,splice() 方法实现替换功能,同时返回所替换的元素:用第三个及其之后的参数替换 index 参数指定位置开始的 count 参数指定个数的元素;
当参数为 3 个以上,且 count 参数为 0 时,splice() 方法的实现添加功能:用第三个及其之后的参数添加到 index 参数指定位置上。
查询和拼接
str.slice(start, end) //截取返回从下标start开始到下标end之前的字符串,不影响原字符串
str.substr(start, length) //截取返回从下标start开始,指定length长度的字符串
arr.concat(arr1) 或者 [...arr,...arr1] //数组合并不影响原数组
arr.join("+") //数组转换为字符串 各元素之间用'+'连接
str.split(',') //字符串转换为数组
排序
arr.sort((a,b)=>{
return a-b //a-b正序 ,b-a倒序
})
//改变原数组而且返回原数组,默认的排序规则是按照ASCII表码值排序
arr.reverse() //按照下标的顺序倒过来重排列元素 改变原数组返回原数组
验证是否包含某一项
indexOf() //返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1
find() 用于找出第一个符合条件的数组成员,没有则返回 undefined
findindex() 用于找出第一个符合条件的数组成员的下标,没有则返回-1
includes() 表示某个数组是否包含给定的值,返回布尔值。
迭代
// foreach 迭代(遍历)数组
var arr = [1, 2, 3]
arr.forEach(function (value, index, array) {
console.log('每个元素值' + value);
console.log('每个元素的索引' + index);
console.log('数组本身' + array);
})
// filter方法创建一个新数组(返回新的数组),新数组中的元素通过检查指定数组中符合条件的元素,主要用于筛选数组
var arr1 = [12, 56, 33, 88, 66];
var newArr = arr1.filter(function (value, index) {
return value > 33;
})
console.log(newArr);
// some方法 用于检测数组中的元素是否满足指定条件,返回值是布尔类型,查找到则返回true,反之false
// 如果找到第一个满足条件的元素,则终止循环,不再查找
var arr2 = [33, 44, 55];
var flag = arr2.some(function (value) {
return value > 50;
})
console.log(flag);
map(callback)返回一个新的数组。为每个元素执行callback方法
let arr = [1,2,3,4];
let newArr = arr.map((item,index)=>{return item*2}); //callback要有return
console.log(newArr); // [2,4,6,8]
every(callback)返回Boolean 判断数组中每一个元素是否满足callback函数(只有所有的元素都满足时才返回true,只要有不满足的元素就立即终止遍历并返回false)
let arr = [1,2,3,4]
let res = arr.every((item,index)=>{
console.log(item); // 1
return item>2
});
console.log(res) //false
Math
Math.abs() 求绝对值
Math.ceil(10.1) 返回大的值11
Math.floor(10.9) 返回小的值10
Math.random() 随机数
Math.round() 四舍五入
节点操作
.parentNode 得到离元素最近的父节点
.childNodes 得到子元素的节点和文本
.children 只得到子元素节点
.nextSibling下一个兄弟节点
ul.appendChild(li)添加节点到末尾
ul.insertBefore(li, ul.children[0])添加节点到头部
ul.removeChild(ul.children[0])删除节点
// 克隆节点
/* 括号为空或者里面是false 是浅拷贝 只复制标签不复制内容
括号里面是true 是深拷贝 复制标签和内容 */
ul.children[0].cloneNode(true);
注册事件
传统方式
btn.onclick = function () {}
监听方式
btn.addEventListener('click', function() {})
事件流(捕获→目标→冒泡)
事件委托也称之为事件代理(Event Delegation)。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
JS执行机制
一大特点就是单线程。
意味着所有任务需要排队,前一个任务结束,才会执行后一个。
导致的问题:如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
为了解决这个问题,HTML5提出了Web Worker标准,允许JavaScript脚本创建多个线程。
于是,JS出现了同步和异步。
事件循环
先把同步任务放到主线程执行栈中,如果有异步任务(回调函数)就放到任务队列(消息队列)中先不执行,等同步任务做完再把异步任务(回调函数,Ajax,点击事件等)放到执行栈中执行。
主线程执行完毕,读取任务队列,取出一个任务,插入主线程处理,重复该动作。
该过程称为事件循环
构造函数
利用对象字面量创建
var obj = {
username: ''
age: ''
sayHi(): function() {}
}
利用new object创建对象
var obj = new Object()
obj.username = ''
obj.age = ''
obj.sayHi = function() {}
自定义构造函数
function fn(name, age) {
this.name = name
this.age = age
this.sayHi = function() {}
}
构造函数、实例、原型对象三者关系
Star的原型对象prototype ldh的对象原型__proto__
原型链结构
call() apply() bind()
严格模式
(function () {
'use strict';
// 所有脚本写在这
})();
严格模式下全局作用域中的函数中的this时undefined
如果构造函数不加new调用,this会报错
闭包(closure)指有权访问另一个函数作用域中的变量
function fun() {
var sum = 10;
function fn() {
// 可访问fun函数中的sum 即fn为闭包函数
console.log(sum);
}
return fn;
}
var f = fun(); // f接收的是 返回的 fn
f(); // 所以可以f()调用
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
// 递归函数:函数内部自己调用自己,这个函数就是递归函数
var num = 1;
function fn() {
console.log('我要打印6句话。');
if (num == 6) {
return; // 递归中必须加退出条件 否则会栈溢出(stack overflow)
}
num++;
fn();
}
fn();
ES6
var const let区别
箭头函数不绑定this关键字,指向的是函数定义位置的上下文this
函数体只有一句代码,且代码的执行结果就是返回值,可以省略花括号{}
function sum(a, b) {
return a + b;
}
const sum = (a, b) => a + b;
如果形参只有一个,可以省略括号()
function fn(i) {
return i;
}
const fn = v => v;
箭头函数+剩余参数
const sum = (...args) => {
let total = 0
args.forEach(item => total += item)
return total
}
// startWith() 表示字符串是否在原字符串的头部 返回布尔值
let str = 'hello world!';
str.startsWith('hello');// true
str.endsWith('!');// true
// repeat() 表示将源字符串重复n次 返回新字符串
'x'.repeat(3);// 'xxx'
Symbol(未完成)
Promise实例
const promise = new Promise((resolve, reject) => {
// ... some code
if (异步操作成功) {
resolve(value);
} else {
reject(error);
}
})
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
// success
}, function(error) {
// failure
}
Promise.prototype.then()
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
Promise.prototype.catch()
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
})
上面代码中,getJSON()方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。
如果 Promise 状态已经变成resolved,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
上面代码中,Promise 在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。
未完...
Iterator(遍历器)的概念
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
next方法返回一个包含value和done两个属性的对象。value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
下面是一个模拟next方法返回值的例子。
function makeIterator(array) {
var nextIndex = 0
return {
next: function() {
return nextIndex < array.length
? {value: array[nextIndex++]}
: {done: true}
}
}
}
未完...
Generator 函数
Generator 函数是 ES6 提供的一种异步编程解决方案
形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(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 函数里面,用在其他地方都会报错。
与 Iterator 接口的关系
任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。
由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。
next 方法的参数
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
Generator 函数的异步应用
// 异步编程: 文件操作 网络操作(ajax, request) 数据库操作
// 案例: 1s后控制台输出111 2s后输出222 3s后输出333
// 回调地狱
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333);
// }, 3000);
// }, 2000);
// }, 1000);
// Generator解决回调地狱
function one() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 1000);
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000);
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000);
}
function * gen () {
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
async函数
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
就是 Generator 函数的语法糖。
const gen = function* () {
const f1 = yield readFile('/etc/fstab');
const f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
上面代码的函数gen可以写成async函数,就是下面这样。
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
async函数对 Generator 函数的改进,体现在以下四点。
1)内置执行器。
async函数的执行,与普通函数一模一样,只要一行。
2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
3)更广的适用性
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
返回 Promise 对象
async函数返回一个 Promise 对象。
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
await 命令
正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
async function f() {
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
Module 的语法
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
export命令
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
export的写法,除了像上面这样,还有另外一种。
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export { firstName, lastName, year };
优先考虑使用这种写法
特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
// 报错
export 1;
// 报错
var m = 1;
export m;
上面两种写法都会报错,因为没有提供对外的接口。
正确的写法是下面这样。
// 写法一
export var m = 1;
// 写法二
var m = 1;
export {m};
// 写法三
var n = 1;
export {n as m};
import 命令
// main.js
import { firstName, lastName, year } from './profile.js';
上面代码的import命令,用于加载profile.js文件,并从中输入变量。import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
export default 命令
使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。