模块化就是将一个复杂系统分解为多个独立模块的代码组织形式。
// a.js
define(function() {
return {
test: function() {
console.log('test');
}
};
});
// b.js
require(['a', 'other'], function(a, other) {
a.test(); // test
});
// a.js
var a = 'test';
function foo() {
console.log('foo');
}
module.exports = {
a,
foo
};
// b.js
let {a, foo} = require('./a.js');
console.log(a);
foo();
// test foo
// a.js
var a = 'test';
function foo() {
console.log('foo');
}
export {a, foo}
// b.js
import {a, foo} from './a.js';
foo(); // foo
// 还可以使用export default导出,但一个文件中只能有一个default
var a = 'test';
export default a
// b.js
// 本质上输出名为default的变量,导入时可以为它取任意名字
import a from './a.js';
console.log(a)
require第一次加载脚本时就会执行整个脚本,在内存中生成该模块的说明对象。
{
id: '', //模块名,唯一
exports: { //模块输出的各个接口
...
},
loaded: true, //模块的脚本是否执行完毕
...
}
一旦出现循环加载,就只输出已经执行的部分,没有执行的部分不输出。
// main.js
let a = require('./a.js');
let b = require('./b.js'); // 不会在执行,从缓存中取
console.log('main.js', '执行完毕', a.done, b.done);
// a.js
exports.done = false;
let b = require('./b.js');
console.log('a.js', b.done);
exports.done = true;
console.log('a.js', '执行完毕');
//b.js
exports.done = false;
let a = require('./a.js'); // 此时回去缓存中找,而a.js未执行完,此时a.done为false
console.log('b.js', a.done);
exports.done = true;
console.log('b.js', '执行完毕');
// 执行main.js
// 输出
// b.js false
// b.js 执行完毕
// a.js true
// a.js 执行完毕
// main.js 执行完毕 true true
ES6模块是动态引用,遇到模块加载命令import时不会去执行模块,只是生成一个指向被加载模块的引用。
// even.js
import {odd} from './odd';
var counter = 0;
export function even(n){
counter ++;
console.log(counter);
return n == 0 || odd(n-1);
}
// odd.js
import {even} from './even.js';
export function odd(n){
return n != 0 && even(n-1);
}
// main.js
import * as m from './even.js';
var x = m.even(5);
console.log(x);
var y = m.even(4);
console.log(y);
// 1 2 3 false
// 4 5 6 true
主要目的就是让页面的打开速度更快,以得到更好的用户体验。
浏览器每次发请求时都会附加到请求头中发送给服务器。
// 设置cookie
function setCookie(key, value, exday) {
var d = new Date();
d.setTime(d.getTime() + exday*24*60*60*1000);
document.cookie = key + '=' value + ';expires=' + d.toGMTString();
}
// 获取cookie
function getCookie(key) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var c = cookies[i].split('=');
if (c[0].trim() == key) {
return c[1];
}
}
return '';
}
统一的api来操作和设置数据:
一般localStorage存JSON数据,使用JSON.stringify与JSON.parse:
var data = {
name: 'Lily',
age: 20,
sex: 'female'
};
var d = JSON.stringify(data);
localStorage.setItem('data', d);
var jsonData = localStorage.getItem('data');
var obj = JSON.parse(jsonData);
主要在于不同分辨率的适配。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
css文件:
js文件:
函数被调用时,调用函数的对象会被传递到执行上下文中,this的值就指向调用函数的对象。
var m = 'global';
function test() {
console.log(this.m);
}
test(); // 'global'
'use strict'; //严格模式
function test() {
console.log(this);
}
test(); // undefined
var m = 'global';
var obj = {
m: 'obj',
test: function() {
console.log(this.m);
}
};
obj.test(); // 'obj'
// 注意下面这个情况,由于test是在全局中调用的,this指向window
var test = obj.test;
test(); // global
function Student() {
this.id = '2012349';
}
var s1 = new Student();
console.log(s1.id); // '2012349'
var m = '123';
var obj = {
m: 'obj123',
test: function() {
console.log(this.m);
}
};
setTimeout(obj.test, 1000); // '123'
setTimeout(function() {
obj.test();
}, 1000); // 'obj123'
var obj = {
m: 1,
test: function() {
console.log(this.m);
return () => {
console.log(this.m);
return () => {
console.log(this.m);
}
};
}
};
obj.test()()(); // 1 1 1
var test = obj.test(); // 1
// 不受调用环境的影响
test()(); // 1 1
一般用来判断基本数据类型,不能用于判断引用类型。只能判断出number/string/boolean/undefined/null/object/function几种,无法区分具体的对象类型。
// 基本数据类型中无法判断null
typeof '123' // string
typeof 123 // number
typeof true // boolean
var a;
typeof a // undefined
typeof null // object
// 可以判断出function
a = function() {}
typeof a // function
// 其余引用类型判断都为object
typeof {} // object
typeof [] // object
利用原型链来进行具体对象类别的判断。但是不能区分基本数据类型(包装类new出来的除外)。
// 不能判断基本数据类型
true instanceof Boolean // false
123 instanceof Number // false
null instanceof Object // false
undefined instanceof Object // false
//包装类new的可以判断
var a = new Number(123);
a instanceof Number // true
// 判断数组以及其他的引用类型
[] instanceof Array // true
new Date() instanceof Date // true
返回[object 构造函数名]格式的字符串,不能用于检测非原生的构造函数名。
Object.prototype.toString.call('123') // //[object String]
Object.prototype.toString.call(123) //[object Number]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(undefined// [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call({}) // [object Object]
Object.prototype.toString.call(function() {}) // [object Function]
// 非原生的无法判断
function Student(){}
var xiaoming = new Student()
Object.prototype.toString.call(xiaoming) // [object Object]
使用constructor判断构造函数,但是null/undefined没有constructor属性。并且constructor还可能被手动重写,所以不安全。
var a = true;
a.constructor === Boolean // true
a = 123;
a.constructor === Number // true
a = '123';
a.constructor === String // true
a = [];
a.constructor === Array // true
a = {};
a.constructor === Object // true
a = function() {}
a.constructor === Function // true
function Student(){}
a = new Student()
a.constructor === Student // true
在子类构造函数中调用父类的构造函数(call/apply)
function Super(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}
Super.prototype.sex = 'male';
function Sub(name, age) {
Super.call(this, name);
this.age = age;
this.getAge = function() {
return this.age;
}
}
var son1 = new Sub('lili', 10);
var son2 = new Sub('mary', 18);
console.log(son1.name); // lili
console.log(son2.sex); // undefined
console.log(son1.getName === son2.getName); // false
将父类的实例作为子类的原型。
function Super(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}
Super.prototype.sex = 'male';
Super.prototype.run = function() {
console.log('in Super prototype run');
};
function Sub(age) {
this.age = age;
this.getAge = function() {
return this.age;
}
}
Sub.prototype = new Super('父类');
Sub.prototype.constructor = Sub;
var son1 = new Sub(12);
var son2 = new Sub(15);
son1.sex = 'female';
console.log(son2.sex); // female
function Super(name) {
this.name = name;
}
Super.prototype.getName = function() {
return this.name;
}
function Sub(name, age) {
Super.call(this, name);
this.age = age;
this.getAge = function() {
return this.age;
}
}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
注:可以通过Object.assign实现多继承
function Sub() {
Super.call(this);
}
Sub.prototype = Object.create(Super.prototype);
Object.assign(Sub.prototype, One.prototype, Two.prototype);
Sub.prototype.constructor = Sub;
事件委托就是只指定一个事件处理程序,来管理某一类型的所有事件。事件委托的原理是事件冒泡,利用event.target/srcElement来判断是否为目标节点
window.onload = function() {
let ul = document.getElementById('ul');
ul.addEventListener('click', function() {
if (e.target.nodeName.toLowerCase() === 'li') {
console.log(e.target.innerHtml);
}
}, false);
}
在一个DOM上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次,先执行冒泡还是捕获。
<div class="box">测试div>
var box = document.querySelector('.box');
box.addEventListener('click', function() {
console.log('bubble box');
}, false);
box.addEventListener('click', function() {
console.log('capture box');
}, true);
// bubble box
// capture box
var box = document.querySelector('.box');
box.addEventListener('click', function() {
console.log('capture box');
}, true);
box.addEventListener('click', function() {
console.log('bubble box');
}, false);
// capture box
// bubble box
<div class="box">
<button class="btn">点击button>
div>
var box = document.querySelector('.box');
var btn = document.querySelector('.btn');
box.addEventListener('click', function() {
console.log('capture box');
}, true);
box.addEventListener('click', function() {
console.log('bubble box');
}, false);
btn.addEventListener('click', function() {
console.log('capture btn');
}, true);
btn.addEventListener('click', function() {
console.log('bubble btn');
}, false);
// capture box
// capture btn
// bubble btn
// bubble box
文档片段接口,表示一个没有父级文件的最小文档对象。作为一个轻量版的document使用。
// 向一个ul中增加多个li
var element = document.querySelector('ul');
var fragment = document.createDocumentFragment();
var i = 0;
while(i < 10) {
var li = document.createElement('li');
li.innerHTML = i;
fragment.appendChild(li);
}
element.appendChild(fragment);