文章目录
1995 Brendan Eich
(布兰登*艾奇)发明了javascript,现任Mozilla公司CTO.
- H5可以允许其多线程,但只能有一个线程操作
DOM
! - js运行时都包含了一个任务队列,其上的每个任务(异步任务)都有对应的回调函数(可能代码相同).
- 所有的同步任务都在栈上执行,当栈中代码执行完毕,主线程才去任务队列中取(
FIFO
)任务放到主线程执行. - 编译器预处理步骤:
- 查找所有函数,包括递归的内部函数, 但不包括
var
声明的函数, 并解析其定义! - 查找所有
var
声明的变量, 直接用=声明并赋值的变量不会被编译器优先识别! 注意: 仅是声明,此时还不会执行赋值动作!
- 查找所有函数,包括递归的内部函数, 但不包括
undefined
(undefined对象)null
(object对象)boolean number string object(function...)
basic
// js中的整数有个上限:Number.MAX_SAFE_INTEGER:9007199254740991(16位).其实都是用double类型保存的,所以精度上有损失(小数点后最多16位精度).
var foo = require('/home/user/foo.js') // 可以被多次导入,但仅会被初始化一次
var b = c = 2; // window.c
var a = [];
console.log(typeof(a));
// 绝大多数场合应该使用 ===, 因为如下表达式的值都为true: '2'==2 && 0=='' && 1==true && null==undefined!
// false: undefined null '' 0 NaN
// undefined: 不存在或没有赋值或void(0): 1+undefined-->NaN; ''+undefined-->undefined
// null: 1+null-->1; 1*null-->0; ''+null-->'null'
isNaN(a) == true; // 注意:如果是字符串,还会尝试能不能转换为数字!
parseInt(a); // NaN.
for (var i=0; i<10; i++) { // 如果是let(let可看成局部的),结果为6!
// 此处的a[i]只登记了地址!
a[i] = function(e) { // 相当于内部 var e;
// 被调用的时候才解释执行(找i的值),此时其值已被改变! 链式查找,优先查找最近的作用域,最后才去window找!
console.log(i);
console.log(b);
var b; // 会在函数的所有代码执行之前被声明!
a = 1; // 认为是全局变量,如果全局中没有则会创建window.a
};
}
string
text = "Hello"; text.length == 5;
// 以下操作均不改变原有字符串!
text.charAt(index); substring(start, end); concat(str,str1..) trimLeft();trimRight();trim();
indexof(str, start); replace(regex, rep/*可使用$1这些*/); search(regex); toUpperCase(); split(dlim, limit=-1);
slice(startIndex, endIndex:默认结尾); // substring()与其一样,只是会视负数为0(若右侧变0后小,会交换);
substr(startIndex, count) // 同slice,只是第二个参数是count,-3会与长度相加.
str = JSON.stringify(obj); // obj --> string,会忽略函数,原型,与undefined成员!
JSON.parse(str); // str --> obj
encodeURI(`http://...?query=${var}`)
decodeURI('http://...?query=%E7%90%86%E8%A7%A3');
date
var d = new Date("July 21, 1983 01:15:00"); // 如果为空则为系统时间,内部会调用parse()!返回从'1970/01/01 -> 2005/07/08'之间的毫秒数
d = new Date(Date.UTC(2005,4,5,17,55,55)); // 2005年5月5日...
d.now(); // 当前时间的毫秒数
d.getDate(); // 0-31此处返回的是 21
d.getDay(); // 0-6, 周末是 0
d.getMonth(); // 0-11,此处返回的是 6(7月)
d.getFullYear(); // xxxx, 此处返回的是 1983
d.getHours(); // 0-23, 此处返回的是 1
d.getMinutes(); // 0-59, 此处返回的是 15
d.getSeconds(); // 0-59, 此处返回的是 0
d.getMilliseconds(); // 0-999
d.toTimeString(); // "01:15:00"
d.toDateString(); // "21"
d.setDate(d.getDate() - 7); // 上周
document.write(d/(1000*60*60*24*365)); // 转换成年,document. == this.
var ci = setInterval(func, 1000); // 每秒执行函数func
clearInterval(ci);
var t = setTimeout(func, 1000); // 1秒后执行参数1中的语句.不会重复.
clearTimeout(t); // 清除计时器,必须在1秒钟前.
array
these members change the original array: push,pop,shift,unshift,splice,sort,reverse
var cars = new Array('Saab') // Array(3):表指定维度为3,每个元素都是undefined; Array(3, 'hello'):表存俩个元素,类型随意
Array.isArray(cars);
car.push('leiz', 1) // ['Saab', 'leiz', 1],返回新数组的长度.也可使用a[index]=val来插入数值,中间空的会undefined.
car.pop() // 删除并返回数组中的最后1个元素; warning: array will be changed
car.unshift(0) // 向队列开头添加1个的元素,返回新数组的长度
car.shift() // 删除并返回数组中的开头元素
car.toString() // 转换为字符串: 'Saab,leiz'
car.indexOf('leiz', startIndex=0) // 1,第1个查找的值所在的索引,类比lastIndexOf()!
cars.length == 2
cars.join("-") // warning: do not change the original array!
for (var i in cars) {
// 字典:遍历的是key, 对象:遍历的是属性
}
var a = [1, 2, ...cars] // ...可用来解包{}和[]
a.reverse()
a.concat(4,5,[6,7]) // 3,2,1,4,5,6,7; warning: do not change the original array!
a.slice(startIndex, end) // 参看string::slice即可; warning: do not change the original array!
a.splice(start, delCount, value) // 拼接的意思. splice(1,1,v):替换第2个元素,返回原值.不写v是删除.count=0是插入!
a.sort() // 以字符串比较/数值方法对数组进行排序,可以加个函数function(a,b){}控制排序的规则
a.some(f(item,index,array){}) // f(每项),只要有1项f运算返回true,则返回true!
a.every(f) // f(每项)都返回true,才返回true.
a.filter(f) // f(每项),返回[f后等于true的成员]. forEach()没有返回动作. warning: do not change the original array!
a.map(f) // f(每项),返回[f调用后的结果]
a.reduce(f(prev,cur,index,array){ // 第1次prev=a[0],cur=a[1];第2次prev=上次f的返回值,cur=a[2]... warning: do not change the original array!
return prev + cur.done ? 1 : 0
})
Dict/Object
对象可以随时随时添加属性.属性也可以是方法!
属性的访问: o.attrname; o['attrname']; for attr in o ...
// 创建对象1
var person = new Object(); // 或者-->
person = {firstname:"bill", lastname:"gates", id : process.env.sys_env_name || 1};
person.firstname = "leizi";
person["lastname"] = "hello"; // 可动态添加属性,括号中可以是变量!
person.eyecolor = "blue";
// 或者 -->
function Person(name, age) {
this.name = name; // 对象属性,其中的每个属性都是对象上的.
this.age = age; // 其实属性名也可以是数值,会转化为字符串
this.friends = ['leiz', 'rong'];
// 仅会在属性sayName不存在时调用一次,添加到原型中
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function() {}
}
}
// 定义原型:需要共享的部分,类属性.
Person.prototype = { // p.__proto__.newMember
constructor : Person;
name : "Nicholas", // 这些直接添加到原型对象中(共享的),创建对象时会先查找对象属性,找不到才查找此处的原型.
age : 29,
sayName : function () { /* 这里面的this也可指代调用的对象 */ }
};
p = new Person('leiz', 20); // 创建对象,以构造函数的形式!
p instanceof Person; // true
'name' in p; // true
p.hasOwnProperty('name'); // false
Object.getPrototypeOf(p).name == Person.prototype.name; // 访问的属性不存在时返回undefined
// 如果传入的是对象,则返回的是对象的属性.getOwnPropertyNames()只获得对象的属性.
Object.keys(Person.prototype); // ['name', 'age', 'job', 'sayName']
math
var num = 8;
num.toString(8); // 以8进制转换为字符串
num.toFixed(2); // 转换为字符串,保留2位小数,没有补零,四舍五入.
var pi_value = Math.PI;
var sqrt_value = Math.sqrt(15);
Math.round(-4.40) // -4
Math.random() // 0-1
Math.max(-3,7.3) // 7.3
regexp
注意: 以下两种写法在ECMAScript5以下有点不同:
构造函数方法会每次新生成.而第一种方法即使在循环内部也仅生成1次!
var reg = /.at/gi; // 匹配所有以at结尾的三个字符,不区分大小写.或-->
var reg = new RegExp(".at", gi);
reg.test("hello world!"); // 返回false,未找到'e'.注意:第2次调用会接着上次找到的位置后面(.lastIndex属性,若已测到尾部则折回)!
reg.exec("leizi"); // [匹配到的整个字符串, 第1个捕获组匹配到的内容=.$1, .., index:匹配的位置, input:..],没有匹配到返回null!
reg.compile("h"); // 改变检索模式,匹配字符'h'
function
闭包中的匿名函数比较特殊:具有全局特性!其中的this
通常指代window
对象,而不是常规调用者.
async function f(p1, p2) {
arguments.length; // 也可以用来访问修改参数,索引访问.
try {
doSomething();
// throw "some msg"
} catch (e) {
txt += "Error description: " + e.message + "\n\n"
alert(txt);
}
// await迫使func1同步执行,只能用在async函数内部!
await func1().catch(e => {}) // 简单的捕捉并处理错误
return p1 * p2; // 返回值成为then的参数,返回值必然是个Promise,默认会await(p1*p2)转换!
}
f(1,2).then(
v => console.log(v)
).then(
e => console.log(e)
)
/* lambda */
// 注意: 只有一个参数时可以省略`()`, 但当没有参数时,必须用括号`()`!
p => v // 等价于 p => { return v }.
(p1, p2) => {} // 等价于 function(p1,p2){}.
BOM
window.innerWidth; // 内页宽度 window.innerHeight;
window.open() // 打开新窗口 window.close() // 关闭当前窗口
window.moveTo() // 移动当前窗口
window.resizeTo() // 调整当前窗口的尺寸
location.hostname // web主机的域名
location.port // 端口,没有时返回''
location.protocol // http:// 或 https://
location.pathname() // /js/js_window_location.asp
location.search // 搜索参数?=.....
location.href // 当前页面的URL
location.assign() // 加载新的文档或网址
location.reload() // 加载新的文档或网址
history.back() // history.go(-1)
history.forward() // history.go(1)
navigator.platform // Win32
navigator.systemLanguage() // zh-cn
navigator.cookieEnabled() // true
screen.availWidth // 可用的屏幕宽度,浏览器的水平像素
screen.availHeight // 可用的屏幕高度(除去任务栏)
confirm() // 确认框,确认:true alert()
prompt() // 用户需要输入某个值,确认:返回值为输入的值;取消:null
DOM
如果在文档已完成加载后执行 document.write 整个HTML页面将被擦除重写
https://www.runoob.com/jsref/prop-html-innerhtml.html
http://www.w3school.com.cn/js/jsref_events.asp
node = document.createElement("p"); // 添加新的段落,类似于tinyxml
node.appendChild(document.createTextNode("新段落的文字")); // 将文字节点连接到段落
node = document.getDocumentById("idname").insertAdjacentHTML('beforeEnd','<p><input type='text'></p>');
node.innerText = ""; // 修改标签的内容(value)
node.onclick = function(){} // 时候绑定,省的HTML中每个标签均指定事件了!
node = document.getElementByTagName(tagname).parentElement.lastElementChild;
node.removeChild(child);
node.setAttribute('attrname', 'value'); // getAttribute,removeAttribute
node.className; // 'class class1',返回的是一个字符串
node.classList.add('class2'); // classList返回的是一个list
node.addEventListner('click', function(){}, true); // true:从外层向里层响应顺序.默认是冒泡即相反.
// event
document.onkeypress = function(event) {
event.keyCode; // 65:表按下'A'键
}
http use Ajax or jQuery
var xhr = XMLHttpRequest();
xhr.onreadystatechange = function() {
// 4:数据返回完整 3:只有一部分返回 2:有调用send 1:有调用open 0:未初始化(未调用open)
if (xhr.readyState == 4) {
console.log(xhr.responseText);
}
}
xhr.open('open', '01.php');
xhr.send(null); // 若是post请求则给出请求的数据!
// jquery
$.ajax(
url: '/host',
type: 'POST',
data: $('#formid').serialize(), // 省的一个个取赋值
traditional: true, // 防止data中的list不能被正确处理
success: function(data) {
var r = JSON.parse(data); // 服务器那边一般是HttpResponse(json.dumps({...}))
}
)
jQuery
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">;</script>
input[attrname^='text'] {} /* 标签+属性选择器(^=表开头,$=表结尾,*=表包含),*[]表示所有标签的属性限制 */
body, head {} /* 组合选择器:或的关系.属性[]也可用在此处或下面 */
div span {} /* 层级选择器:div下面的所有span,递归 */
div > span {} /* 层级选择器:div下面的span,不递归 */
#id_name {} /* id不能重复,所以一般用在特例上 */
.class_name :hover {}
.c:first // 第1个
.c:eq(2) // 索引位置的第3个
.c :text // input的text控件 == .c input[type='text']; password radio checkbox submit reset button file image
$(':checkbox').prop('checked', true); // 全选,prop同attr,但专门用于checkbox+radio!
$(':checkbox').each(function(index) { // 反选
this.checked = !this.checked; // 此时的this指代当前循环的dom对象,$后可转换为jQuery对象.
})
// == on/bind('click', function...) | off/unbind.
// .delegate('li', 'click', function...) :更牛逼,可以给动态创建的子元素绑定委托(点击的时候才执行代码).
$('#id').click(function() {
// prev parent children siblings nextAll prevUntil eq.
$(this).next().addClass('left').find('.c').removeClass('left').text();
.hasClass('c1').toggleClass('c1'); // 有则移除,没有则添加
.text('setvalue');
.val(); // input控件当前值,等价于DOM中的.value!
.attr('attrname'); // 获取属性值;俩参时:属性不存在会添加,值不一样会修改!removeAttr()
.css('color','green').append('<li>2</li>'); // prepend after(另起一个ul)
.eq(1).remove(); // 删除DOM标签. empty(清空内容)
)
.offset().left() // 标签坐标,相对于window. position:相对于父标签
.scrollTop(0) // 滚动条,最上头
.extend({ // jQuery扩展,类似于$.ajax,可以直接$.func()调用.
'fun' : function(){}
})
$.cookie('key')