1.什么是javascript
.2 BOM {location, navigator, screen, 弹出新窗口}
2.html中的javascript
.1
-
script标签 : 一般放在body后面
async: 立即下载脚本,但是不会中断页面和其他脚本的加载执行。
derfer:延迟下载
src: if you use it, can not add code in this element, code will be ignored.
browser will sent a get request to get this src.
type: application/javascript2.代码中不能有, if you need, have to use “</script>”
.2行内代码和外部文件
1.js 最好一起放在外部独立文件中:
可维护性,缓存
.4 noscript
write html element in <body>, when browser do not support js, it will be displayed.
3.语言基础
3.1 语法
1.区分大小写
.2 第一个字符必须是字母,下划线,美元
3.1.5 推荐加分号
3.3 变量
松散型, 不使用var.
var 添加到最近的上下文,
3.3.1 var 函数作用域,可以重复声明,全局声明会变成window属性
不初始化,保存undefined
var (上下文作用域): 有声明提升,把变量声明提到函数作用域顶部。( var name = “aa” == name = “aa”; var name;)。重复声明会被忽略不会报错
3.3.2 let 块作用域({}), 同一个块中不允许重复声明, 没有声明提升,全局声明不会变成window属性。
3.3.3 const: 和let一样,必须初始化变量,不能再次修改值,但是修改不是对象的键const会报错,相当于全局变量。 不能重复声明
3.4 不用的话就是全局变量
3.4数据类型
六种 (null == undifined)
Undefined: 为定义的,if(!iundifined)==true
Null: 空对象指针,定义将来要保存对象的变量 if(!null)==true
Boolean: 全部小写, True是标志符, boolean()转换-规则和C一样。
- “”,NAN,0 ,undefined,null== flase
Number: 八进制:0,16进制:0x, 1.0会变成1, 0.1+0.2!=0.3, isNaN()判断是不是不是数值(本来应该是数值),isNAN(true/“10”)==true(会先转换成number).
转换成数值类型:
Number(param):Number(null)==0,Number(undefined)==nan,Number (“asdf”)=nan.
parseInt(" “, 进制):parseInt(“22.5”)=22, parseInt(“11adsf”)=11, parseInt(”")=nan.
parseFloat: 类似
String: 定义后不会变(重新赋值:先自动销毁再赋值), " ", ’ ', ` `
转换成字符串:
toString():11.tostring(), 2.tostring(2)=“1010”, null.tostring=null, nudefined.toString()=undefined, null and undefined do not have tostring().
模板字面量:` `, 保持换行符,可以自由换行。
`rqre
qwer`
字符串插值:`${value} insert into`, 调用了toString()方法来转换。
String.raw: 获取原始字符串(换行符unicode字符),不会转义直接的换行“enter”。
Symbol: es6新增,let a = Symbol(),和别的不一样不用New,
复杂数据类型:object:所有对象的基本类型
constructor, toLocaleString(), toString(), valueOf(), isPrototypeOf()判断是不是另一个对象的原型。
3.5操作符
3.5.1一元操作符
自增自减:字符串转换成数值再操作, true and false 转换成1 和0, 对象另说
3.5.2位操作符
js是32位表示
1.第32位是符号位
2.负值(补码):确定绝对值的二进制,取反码,加1 。
3.运算符:
- 非(~):反码,相当于取负值再减一。
- 与(&):相当于 &&
- 或:
- 异或(^):1,1=0 1,0=1. 0,0=0
- 左移(<<):保留符号位 右移(>>)
4.布尔运算:
let object = preferredO || backupO; //如果prefer是null就赋值backup
5.常规运算符
- 指数:3 ** 2 = 9; num **= 2;
- 小于等于大于:“b” > “azzz”; “23”<"3; "23>3( transfer to number); “a” can not be compared it will be NaN, so the result will always be false;
null == undefined; nan != nan; “5” == 5 but “5” === 5 //flase;
3.6语句
-
循环
-
for in: 循环键属性(对象,数组)
-
for of: 循环值属性(数组),Object.keys(obj)–转化对象到数组。
-
标签语句和continue,break:
//退出到标签指定标签的位置 outermost: for(i;i<10;i++){ for(j;j<10;j++){ if(i==5&&j==5){ break outermost; } } }
-
-
判断
- switch:用的是全等 ===。
4.变量作用域和内存
4.1原始值,引用值(对象,数组), 复制值
let a = String("zhe shi string, 原始值"); // 不能添加属性,栈内存
let b = new String("zhe shi object, 引用值") // 可以添加属性 let b.name = "zain",堆内存
let a2 = a //互不影响
let b2 = b //指向内存,互相影响
注意:函数传值也是复制值。
2.typeof检测是不是原始值, (typeof a)
instanceof检测对象是什么类型的,(b instanceof Array)
4.2上下文,作用域
1.按照顺序,当前执行的函数会创建一个执行上下文域,执行完后跳出到上一个上下文,上下文有包含自己和之前上下文的变量。(全局上下文,函数上下文)
2.进入新的上下文会创建一个作用域链,找当前作用域的变量,如果没有往上找。
3. with和catch会在当前上下文的前端增加一个新的上下文
4.3 垃圾回收
1.标记清理:离开作用域的会被标记清除 主流
2.计数清理: 0的时候清除
3. 提高性能:数据不在必要就设null解除引用, 使用const和let,
5.基本引用类型
5.1 Date
5.2 RegExp
/pattern/flags;
let reg = /pattern/flags;
let matches = reg.exec()
flags: g(全局), i(不区分大小写), m(多行), y, u, s
看书5.2
5.3原始值包装类型
1.let s1 = “'asdf” //原始值, 没有方法
let s2 = s1.substring(2) // 先创建一个String类型的实例, 调用方法,销毁实例
2 .Boolean对象一般不用
3.Number(): toString(), toFixed(2)包含几位小数, isInteger() 1.0=true
4.String: return a new string
- length属性,
- charAt(),
- concat(),
- slice(start, end), substr(start, length), substring(start, end) ,
- indexOf()第一个找到的位置,lastindexOf()最后找到的位置。
- startsWith(str, start),endsWith(str, end),includes().
- trim()去除前后空格,
- repeat(次数)返回重复几次的字符串,
- padStart(length, 填充的str默认是空格),padEnd()。
- toLowerCase(), toLocaleLowerCase(), toUpperCase(),
- str.match(RegExp),
- replace( 被替换字符串,替换字符串), replace(Reg, 替换字符串)
- for(const c in str) console.log( c )
- […str]变成数组。
5.glocal 相当于 window对象: 基本数据类型是他的属性
5.4.2 Math
属性:E, PI
方法:
-
min(), max()
Math.max(1,2,3) let values = [1,2,3]; let max = Math.max(...values)
-
ceil() 向上取舍
-
floor() 向下取舍
-
round() 四舍五入
-
fround()
-
random():0~1. better:window.cryto.getRandomValues().
6.集合引用类型
6.2 Array
数组的每个槽位可以存不同类型的数据
-
数组的创建: new Array(length); new Array(“a”, “b”, “c”); []; 可以省略 new;
-
Array.from():
a. Array.from(“Marry”) --> [M,a,r,t,y];
b. 转换集合和映射和迭代器const m = new Map().set(1,2).set(3,4); const s = new Set().add(1).add(2).add(3); Array.from(m) ---> [[1,2],[3,4]]; Array.from(s) ---> [1,2,3];
c.浅复制当前数组
const a1 = [1,2,3]; const a2 = Array.from(a1); a1 === a2 -> false;
-
Array.of: 把一组参数转换成数组
Array.of(1,2,3) --> [1,2,3]; -
数组的空位是 undefined [,]; 避免使用
-
length
let a = [1,2,2];
a[3] = 3 // zidong kuo jian [1,2,2,3]
a.length = 3 // zidong shanchu zuihou yixiang [1,2,2]
a.length = 5 //zidong kuojian undefiend [1,2,2,undefined, undefined]
- 迭代器
//Array.keys() 返回keys的迭代器
//.values()返回值的迭代器
//.entries()返回键值对的迭代器
for(const (index, value) of (a.entries())){
} // for of return value, here entries like a two dimensional array
Array.from(a.keys())--> [1,2,3]
- 复制和填充 fill()
- 转换方法: 所有对象都有 toLocaleString(), toString()逗号分隔的字符串, valueOf()返回数组本身。
- 栈方法 a.push()插入到最后; a.pop()弹出最后一项。 数组类似于栈(后进先出)。
- 队列的方法(先进先出):push; a.shift()弹出第一项。a.unshift()开头加元素。
- 排序: reverse()反向; sort()正向从小到大,但是即使是数字也会先转换成字符串;
let a = [5,10];
a.sort() ---> [10,5]; //xian zhuanhuan cheng zifu chuan
//so we need to use a compare funcion in sort() like following
function compare(v1, v2){
if(v1 < v2) {
return -1;
}else if(v1 > v2){
return 1;
}else{
return 0;
}
}// huozhe return v1 - v2
a.sort(compare); //[5 ,10] 也可以充大到小
//也可以写成箭头函数
a.sort( (v1, v2) => {v1 < v2 ? 1 : a > b ? -1 : 0} )
- concat(): 拼贴数组,返回新数组。
- slice(start, end): 剪数组, 返回新数组
- splice(start,要删除的个数, 要插入的元素,要插入…): 删除;插入;替换
- indexOf(), lastIndexOf(), includes();
- 断言函数
const people = [
{
name:"matte",
age:27
},
{
name:"kkk",
age:32
}
];
console.log(people.find( (element, index, array) => { age < 30; } );
- 迭代方法
a.every( (item, index, array) => { item > 2;} ):每一项传入函数,全部返回true,就返回true
filter(): 函数返回true的项组成新的数组返回
forEach(): 相当于for循环
map( (element, index, array) => e**2; ):返回每次调用函数的结果构成的数组
some(): 有一项返回true就返回true。 - 归并 a.reduce((pre,cur,index,array)=>prev+cur). 迭代全部元素, return的值作为下一次迭代的pre.
6.3历史和未来
跳过
6.4Map 键值对,类似于对象,但有区别
const m = new Map([
["key1", "val1"],
["key2", "val2"],
]);
m.size
m.set("newkey", "newName");
m.get("key");
m.has("key");
m.delete("key");
m.clear();
- 对象和map都没有重复的key
- 对象的key可以是数值,字符串,符号。 map可以是任意数据类型。
- 对象的迭代是无序的, map的迭代是有序的
const m = new map([......])
for (let pair of m.entries()){} // keys() and values() is the same
- map比obj占用内存小
- map插入更快
- obj查找更快
- map删除更快
6.5 WeakMap
键只能是对象 或者继承对象的类型。
不可迭代, 没有clear();
使用: DOM节点元数据
6.6 Set
const s = new Set(["v1", "v2", "v3"]);
s.size
s.add("newV");//返回布尔值,表示是否含有要增加的数
s.has("v");
s.delete("v"); //返回布尔值,表示是否含有要删除的数
s.clear();
迭代和map一样。保留插入顺序
6.7 WeekSet
类似WeekMap
7.迭代器和生成器
return 也可以提前结束迭代
8. 对象 类 面向对象编程
8.1 对象
- Object.defineProperties() 设置对象属性的特性
- 对象属性的特性有: configurable(是否可以通过delete删除),enumerable(是否可以for in 循环), writable, value。
- Object.getOwnPropertyDescriptor()查看对象属性的特性
- 合并对象: Object.assign(目标对象,对象1,对象2);
- Object.is 类似于 ===;
- 对象结构赋值:[key:value] = object{""};
- 获取和设置访问器
在对象内部设置函数
set name(newname){this.name = newname};
get nam(){return this.name};
8.2创建对象
8.2.2 工厂模式
定义函数,返回对象的模式
function gongchang(){
let ob = new Object();
ob.name = "aaa";
return ob;
}
8.2.3构造函数模式
定义函数,赋值给this,没有return,New 对象。
function gouzaohanshu( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
this.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
}
let shili = new fouzaohanshu();
//实例化后不能共享同一个toString
8.2.4 原型模式
利用prototype定义属性,方法=定义在原型链上
function yuanxing( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
yuanxing.prototype.toString = function(){
return this.model + " has done " + this.miles + " miles";
}
let shili = new yuanxing();
//实例化后共享同一个toString
理解原型:Object.prototype是原型。 Object.prototype.proto fangwen yuanxing
1.isPrototypeOf() // 确定对象之间是否存在原型关系
2.Object.getPrototypeOf(object1) // 获取实例对象的原型
4.hasOwnProperty(name) // 检测一个属性是否在实例中
5.原型与in操作符 “name” in person // 对象能访问到给定属性时返回包括原型上的属性。
6.Object.keys(obj) // 返回一个包含所有可枚举属性的字符串数组(实例属性)
let a = {
"name":123
}
function b(){
this.name = 123;
}
b.prototype.age = 456;
let c = new b();
console.log(Object.keys(a)) //[ 'name' ]
console.log(Object.keys(c))//[ 'name' ]
console.log(Object.getOwnPropertyNames(c))//[ 'name' ]
//对象原型链上的属性都是不可枚举的(自带的属性方法都在原型链上)
7.Object.getOwnPropertyNames() //获取所有实例属性,包括不可美枚举的
8.3 继承(ES5,也要理解)
duixiang.prototype.constuctor构造函数
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
console.log(SuperType.prototype.constructor)
ƒ SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
1. 原型链,盗用构造函数继承,组合继承
//原型模式初始化一个超类
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
//原型链继承
// 1. 原型中包含的引用值会在所有实例中共享 2. 子类型在实例化的时候不能给父类型的构造函数传参数
function sub1(name){}
sub1.prototype = new SuperType();
//盗用构造函数继承
// 1. 必须在构造函数中定义方法, 所以方法不能重用
//原型链上的方法不能继承
function sub2(name){
SuperType.call(this, name);
}
//组合继承
function sub3(name){
SuperType.call(this, name);
}
sub3.prototype = new SuperType();
sub3.prototype.constructor = sub3;
let instance1 = new sub1("zain");
let instance2 = new sub2("zain");
let instance3 = new sub3("zain");
console.log(instance1.name);
console.log(instance1.colors);
instance1.sayName();
console.log(instance2.name);
console.log(instance2.colors);
//instance2.sayName(); 不能继承公用方法,方法只能在构造函数内部定义,所以不能公用。
console.log(instance3.name);
console.log(instance3.colors);
instance3.sayName();
//细节
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function sub1(name){
//SuperType.call(this, name);
}
sub1.prototype = new SuperType();
let instance1 = new sub1("zain1");
instance1.colors.push("123123");
console.log(instance1.colors)
instance1.sayName(); //因为子类不能向父类传值 所以是 undefined
//不同的对象不会公用
function sub2(name){
//SuperType.call(this, name);
}
sub2.prototype = new SuperType();
let instance2 = new sub2("zain2");
console.log(instance2.name); //因为子类不能向父类传值 所以是 undefined
console.log(instance2.colors);
//实例化同一个对象的时候会共用引用值
let instance3 = new sub1("zain1");
console.log(instance3.colors)
//组合继承和寄生继承就可以传值
function sub3(name){
SuperType.call(this, name);
}
sub3.prototype = new SuperType();
let instance4 = new sub3("zain")
console.log(instance4.name);
console.log(instance4.colors);
2. 原型式继承,寄生式继承,寄生式组合继承
// 在object()函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数原型,最后返回了这个临时类型的一个新实例.
// object()本质上对其中传入的对象进行了一次浅复制
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
let oneperson = object(person);
oneperson.name = 'adff';
let oneperson = Object.create(person,{
name = 'asdf'
})
// 初始化一个超类
var person = {
name: "kebi",
friends: ["kuli", "hadeng"],
getFriends: function(){
console.log(this.friends)
}
};
// 原型式继承, 引用值会共享
var onePerson = object(person);
onePerson.name = "heyushuo";
onePerson.getFriends();
onePerson.friends.push("heyushuo");
var twoPerson = object(person);
twoPerson.name = "yaoming";
twoPerson.getFriends();
twoPerson.friends.push("yaoming");
console.log(twoPerson.friends); //['kuli','hadeng','heyushuo','yaoming']
//原型式继承专有函数 Object.create()
var person = {
name: "kebi",
friends: ["kuli", "hadeng"]
};
var onePerson = Object.create(person, {
name: "heyushuo"
});
onePerson.friends.push("heyushuo");
var twoPerson = Object.create(person, {
name: "yaoming"
});
twoPerson.friends.push("yaoming");
//这里打印
console.log(twoPerson.friends); //['kuli','hadeng','heyushuo','yaoming']
//寄生式继承
// 函数的主要作用是统一为构造函数新增属性和方法,以增强函数
//原型继承存在的缺点他都存在
//使用寄生式继承为对象添加方法,会由于不能做到方法的复用而降低效率,这一点和构造函数模式类似
function createAnother(original) {
var clone = object(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function() {
// 以某种方式来增强对象
console.log("hi");
};
return clone; // 返回这个对象
}
//寄生继承 原型继承的扩展. 引用值会共享
function jisheng(father){
let clone = Object.create(father);
clone.son = 'asdf';
return clone;
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();
//寄生组合继承
//寄生式继承的基本模式
function inheritPrototype(subType, superType) {
var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型的属性和方法
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
// 借用构造函数继承构造函数的实例的属性(解决引用类型共享的问题)
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
// 将子类型的原型重写替换成父类的原型
inheritPrototype(SubType, SuperType);
// 对子类添加自己的方法
SubType.prototype.sayAge = function() {
console.log(this.age);
};
var instance1 = new SubType("heyushuo");
var instance2 = new SubType("kebi");
instance1.sayName(); //heyushuo
instance2.sayName(); //kebi
instance1.colors.push("yellow"); // ["red", "blue", "green", "yellow"]
instance2.colors.push("black"); // ["red", "blue", "green", "black"]
寄生组合继承
function Sup(grade){
this.grade = grade
}
Sup.prototype.sayGrade = function (){
console.log(this.grade)
}
function Sub(name){
Sup.call(this,'一3班')
this.name = name
}
Sub.prototype = Object.create(Sup.prototype);
Sub.prototype.constructor = Sub;
var instance = new Sub('小强');
console.dir(instance);
console.dir(instance.sayGrade);
8.4 类(ES6,代码简单)
8.4.1 类的定义
class Person{}
const Person = class {}
- 类的定义不能提升
- 函数受函数作用域限制, 类受块作用域限制
- 首字母大写
.2类的构造
构造函数方法,实例方法,获取函数,设置函数,静态类方法
8.4.2类的构造函数
1.constructor 关键字告诉解释器在shi用new实例化的时候要调用这个函数,不定构造函数则默认是空函数。
2.调用类构造函数必须使用new
3.类构造函数实例化后,会成为实例的普通实例方法, 可以被调用
class Person{}
let p1 = new Person();
let p2 = new p1.constuctor();
- 实例化: new. (类实例化传入的参数会成为构造函数的参数)
使用new实例化的操作等于调用其构造函数
a. 在内存中创建一个新的对象
b. 新对象内部的prototype指针被赋值为构造函数的prototype
c. 构造函数内部的this指向新对象
d. 执行构造函数内部代码(给新对象添加属性)
e. 返回这个对象
8.4.3实例原型和类成员
- 构造函数内的属性不会在原型链上共享
- 共享的方法写在构造函数外面,叫做 ‘类块方法’.
- 虽然方法可以定义在类块中,但是不能直接在类块中给原型添加原始值或者对象作为成员数据。
- 但是可以在类的外面手动添加
- 类支持设置和获取访问器
- 静态方法,不能被实例化,存在于类,适合用作实例工厂
class Person{
constructor(name){
this.name = name;
this.locate = () => console.log('instance');
}
kkk :'jake'; //报错
locate(){
console.log('prototype');
}
locate2(){
console.log('prototype2');
}
static locate(){
console.log('static');
}
//实例工厂
static create (name){
return new Person(name);
}
}
Person.kkk = 'jake'; //ok
let p = new Person();
p.locate();
p.locate2();
Person.locate();
8.4.5es6继承
关键字 extends
类或者普通构造函数都可以用
- super():
a. 只能在派生类的构造函数,实例方法和静态方法内部使用
b. 用this之前必去调用super()
c. 调用super会调用父类构造函数,返回实例赋值给this
d. 如果需要给父类构造函数传参数,需要手动传入
e. 没有定义类的构造函数,自动调用super传入父类所有
f. 如果派生类有构造函数,它必须调用super或者返回一个对象(return {})
class Vehicle{
constructor(name){
this.name = name;
this.age = 12;
}
static test(){
}
}
class Bus extends Vehicle{
constuctor(name){
super(name);//super可以传值
console.log(this.age);
}
static test(){
super.test();
}// 静态方法中shiyong
}
9.代理和反射
代理目标函数,是目标函数的替身,完全独立于目标函数
可以在handler中定义 get set
// const p = new Proxy(target, handler)
let obj = {
a: 1,
b: 2,
}
const p = new Proxy(obj, {
get: function(target, key, value) {
if (key === 'c') {
return '我是自定义的一个结果';
} else {
return target[key];
}
},
set: function(target, key, value) {
if (value === 4) {
target[key] = '我是自定义的一个结果';
} else {
target[key] = value;
}
}
})
console.log(obj.a) // 1
console.log(obj.c) // undefined
console.log(p.a) // 1
console.log(p.c) // 我是自定义的一个结果
obj.name = '李白';
console.log(obj.name); // 李白
obj.age = 4;
console.log(obj.age); // 4
p.name = '李白';
console.log(p.name); // 李白
p.age = 4;
console.log(p.age); // 我是自定义的一个结果
代理模式
跟踪属性访问,
get set添加条件就可以隐藏属性
属性验证
const user = {
name:'jake';
}
const proxy = new Proxy(user,{
get(target, property, receiver){
console.log(`etting ${property}`);
},
set(target, property, value, receiver){
console.log(`setting ${property}'= ${value});
}
}
proxy.name; // getting name
proxy.age = 27; //setting age=27
10. 函数
(函数实际上是对象,每个函数都是function类型的实例)
1.创建函数
函数声明
有函数声明提升
//直接赋值,默认参数,调用时候没有这个参数的时候会使用默认参数
function sum(num1 = ‘zain’, num2){ return num1+num2; }
//暂时性死区 默认参数按照顺序(可以理解为let定义)
function sum(num1 = num2, num2){ return num1+num2; }
函数表达式
没有函数声明提升, 和let无关
let sum = function(num1, num2){ return num1 + num2; };
箭头函数
//箭头函数不能使用 arguments,super,构造函数,没有prototype属性
//但是可以在包装函数(闭包)传入arguments
let sum = (num1, num2) => { return num1 + num2; }
2.扩展参数
...[1,2,3] 会变成一个一个的参数
getSum(...[1,2,3])
10.9函数内部
自动存在的对象
- arguments: 参数 和 arguments.callee();自调用递归
- this:标准函数中this是调用时候的上下文,, 箭头函数中的this是定义时候的上下文。
- target.new:
10.10 函数的属性和方法
属性
- length:参数的长度
- prototype:
方法: - apply() : functionname.apply(this/别的上下文对象, 数组)
- call(): functionname.apply(this, 参数1,参数2…)
10.13尾调用优化
尾调用指的是函数的最后一步调用另一个函数。我们代码执行是基于执行栈的,所以当我们在一 个函数里调用另一个函数时,我们会保留当前的执行上下文,然后再新建另外一个执行上下文加 入栈中。使用尾调用的话,因为已经是函数的最后一步,所以这个时候我们可以不必再保留当前 的执行上下文,从而节省了内存,这就是尾调用优化。但是 ES6 的尾调用优化只在严格模式下 开启,正常模式是无效的。
10.14 闭包
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函 数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。闭包有两个常用的用途。闭 包的第一个用途是使我们在函数外部能够访问到函数内部的变量。通过使用闭包,我们可以通过 在外部调用闭包函数,从而在外部访问到函数内部的变量,可以使用这种方法来创建私有变量。 函数的另一个用途是使已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数 保留了这个变量对象的引用,所以这个变量对象不会被回收。其实闭包的本质就是作用域链的一 个特殊的应用,只要了解了作用域链的创建过程,就能够理解闭包的实现原理。
1.this: 闭包箭头函数要注意(直接使用会用全局this,需要 let that = this;)
2. 内存泄漏
3.
//
function test(){
let a = 1;
console.log(a)
return function(){
console.log(a);
a = 3;
}
console.log(a)
}
//ff就是return的function, 一直在执行的是这个return的function
//原始值和引用值都会被完全复制到return的function。
let ff = test();//1
ff();//1
ff();//3
let ff2 = test();//1
ff2();//1
10.15立即调用的函数表达式
//紧跟第一个括号后面的第二组括号会立即调用前面的函数表达式
(
function(){
//块级作用域
}
)()
//es5
(
function(){
//块级作用域
for(var i =0; i < 10; i++){
console.log(i)
}
}
)();
//外面不能访问i
//es6 用let
for(let i =0; i < 10; i++){
console.log(i)
}//外面不能访问i
10.15私有变量
用let和闭包实现
1.特权方法; 变量方法都是共享的
//构造函数中实现
//缺点:每个实例都会重新创建一遍方法。
function Person(name){
let name=name;//私有
let p2 = 10;
function pricateFunction(){} //私有
this.sayName=function(){
alert(name);
console.log(p2);
}//共有
};
var person1=new Person("Bob");
var person2=new Person("Mike");
person1.sayName(); //Bob
//静态私有变量实现, 公共方法可以重用。
(
function(){
let private1 = 10;
function privateF(){
return 1;
}
MyObject = function(){};
MyObject.prototype.publicF = function(){
private1++;
return privateF();
}
}
)();
11.期约和异步函数
Promise(执行器函数)
- resolve() and reject() can only do one
let p = new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log(20);
resolve(30)
},1000)
console.log(10)
})
p.then((result)=>{
console.log(result);
return 40;
})
.then((result)=>{
console.log(result);
return 50;
})
.then((result)=>{
console.log(result);
})
2.上述代码是期约连锁
Promise.all(Promise1, Promise2)
let p = Promise.all([
Promise.resolve(3),
Promise.resolve(3),
]);
//全部期约完成后 返回结果数组
3.期约合成
function addtwo(x){return x+2;}
function add(x){
return Promise.resolve(x)
.then(addtwo)
.then(addtwo)
add(8).then(console.log);
异步函数
async/await.
1.async
//声明
async function foo(){}
let bar = async function(){}
let baz = async() => {}
//返回值 同步 return
async function foo(){
console.log(1);
return 3 //return a Promise
}
foo().then(console.log);
console.log(2);
//1,2,3
2.await
await 会暂停执行异步函数后面的代码
其实都会暂停
await 必须用在异步函数中 但是后面等待的什么都可以加
async function foo(){
console.log(2);
console.log(await Promise.resolve(8));
console.log(9);
}
async function bar(){
console.log(4);
console.log(await 6);
console.log(7);
}
console.log(1);
foo();
console.log(3);
bar();
console.log(5);
//1,2,3,4,5.......
12.BOM
BOM的核心是window, 也可以说是global, var 会 变成window的属性和方法–全局变量
窗口关系
window.parent 父窗口
window.top 浏览器窗口
窗口位置和像素
window.screenLeft/Top 窗口相对于屏幕左侧和顶部的像素
window.moveTo(x, y). 移动到到
window.moveBy(x, y) 需要移动的距离
窗口大小
window.innerWidth: 浏览器视窗大小
document.documentElement.clientWidth. 视窗减去margin
IE8: document.body.clientWidth
offsetWidth: 当前节点的大小
offsetTop: 和父节点的距离
//改变视窗大小
window.resizeTo(x, y)
window.resizeBy(x, y)
//移动视窗
window.scrollBy(x ,y);
window.scrollTo(x, y);
//打开新窗口
window.open(url);
定时器
setTimeout()
let id = setTimeout(()=>{
console.log(11);
}, 1000)
clearTimeout(id); //11不会输出
setInterval() 每个一段时间执行
let num = 0;
let foo = function(){
num++;
if(num == 10){
clearInterval(id);//取消 常用
alert("done");
}
}
let id = setInterval(foo, 500);
系统对话框
alert()
confirm() it will return true or false
if(confirm("are you sure"){
}else{}
prompt(); inputbox return that user input
let result = prompt("what is your name");
if(result != null){
console.log(result);
}
location对象
BOM的一个对象
存 当前文档和URL的信息(location.host href port)
location.search 返回?及其后面的参数
URLSearchParams 用来操作URL参数
let search = new URLSearchParams(url);
search.has("param");
search.get("param")
search.set("new",3);
search.delete("new")
操作地址
location.assign()
location = new
location.href = “new”
navigator
浏览器的信息 电脑的信息
screen
浏览器外面的客户端的现实器的信息
不太用
history
history.go(-1);//后退一页
history.back() .forward()
13.客户端检测
跳过
14.DOM
html文档可以用DOM表示一个有节点构成的层级结构
node 类型
DOM节点都继承node 类型
somenode.nodeType == 1
//一共有12种, 1代表element
somenode.nodeName
somenode.childNodes[0];
somenode.firstChild .lastChild
somenode.parentNode
somenode.appendChild(newNode) //在子节点列表最后添加
somenode.insertBefore(newNode,node)
somenode.replaceChild(newNode,node)
somenode.removeChild(node)
14.1document类型
document是window对象的一个属性,是一个全局对象 nodetype == 9
定位元素
document.getElementById(); // 返回这个ID的元素, is not a list
document.getElementByTagName("img") // 返回标签名的list
1.element类型
nodetype == 1;
属性
id className title lang dir
获取属性
getAttribute(attribute), setAttribute(), removeAttribute()
let div = document.get....("asdf");
div.getAttribute("id")
创建元素
document.createElement()
let div = document.createElement("div");
dic.id = "mydiv";
.
.
.
2.text 类型
文本
nodeValue或者data 节点报刊的文本
不支持子节点
每个元素最多只能有一个文本节点
方法:
appendData(text):
deleteData(offset(位置),count):
insertData(offset, text):
substringData(offsset, coumt):提取内容
//创建插入 文本节点
let element = document.create....("div");
element.className = "message";
let textNode = docu...createTextNode("hello!");
element.appendChild(textNode);
document.body.appendChild(element)
//使用
<div>adsf</div>
let textnode = div.firstChild.nodeValue = "something else"
14.2 dom编程
14.2.3 操作表格
<table> 特有的属性和方法
tFotot
tHead
rows
createTHead()
createTFoot()
createCaption()
deleteTHead()
deleteRow(position)
insertRow(position)
<tbody>
rows 该元素中所有行的html collection
deleteRow§
insertRow§
<tr>
cells
deleteCell§
insertCeii§
htmlcollection: let divs = documents.getElementsByTagNmae(“div”) 集合
14.2.4NodeList
all of the node’s : a list
15.DOM扩展
1.querySelector(): 返回一个
div:tagname
#mydiv: id
.mydiv: class
div.mydiv:
2.querySelectorAll(): 返回一个列表 , 可以用 for of 迭代
3.matches()
document.body.matches("#mydiv"), return true or false, check this node could be find by querySelector()
15.2 元素遍历
childElementCount
firstElementChild
lastElementChild
15.3 HTML5
后面讨论
15.3.1 css类扩展
1.getElementsByClassName(): 返回list
结合使用
document.getElementbyId().getElementsByClassName
2.classlist
add()
contains
remove
toggle
div.classList.remove("user");
15.3.2 焦点管理
document.activeElement: 包含当前有用焦点的元素
.hasFocus() : 确定文档是否有焦点
15.3.3documents 扩展
document.readyState : 返回 complete(完成加载), loading
15.3.6 插入标记
1.innerHTML:
返回这个节点下面的所有节点的html code
divnode.innerHTML = “<p>adf</p>”. 替换之前节点的child的html。
2.outerHTML:
innerhtml+节点自身
16. DOM2 DOM3
16.2样式
三种方法:
- 外部样式<link>
- 文档样式 <style>
- 元素特定样式 node.style.color = “black” 或者 <div style = “color:black;”>
16.2.3 偏移尺寸
元素外边框和父亲内边框的距离
offsetHeight
offsetLeft
offsetTop
offsetWidth
元素内边框的内的长度大小
clientHtight
clientWidth
滚动尺寸
scrllHeight
.
.
.
17. 事件
17.1 事件流
- 事件冒泡流: 从下到上
- 事件捕获流: 从上到下
17.1.3 DOM 事件流
事件捕获— 接受事件—事件冒泡
17.2 事件处理
- addEventListener(event, function, isCapture(true/false)) removeEventListener():
两个方法传入的函数必须完全一样
添加多个时,按照顺序触发
事件绑定的函数的 this是自身作用域。
2.IE 是 attachEvent(). detachEvent()
添加多个是,出发顺序相反
事件绑定的函数的 this是window。
17.3事件属性
1.event.type : 判断事件类型。click mouseover …
2.preventDefault: 取消默认行为,<a> 标签
3.stopPropagation()。IE(cancelBubble)
4.eventPhase: 事件流的阶段 1,2,3(冒泡)
17.4 事件类型
- UI:
1.load: addEventListener(“load”, (event)=>{}) / <img οnlοad="console.log(“loaded)”>
2.unload
3.error select resize scroll - focuse:
1.blur: 失去焦点的时候
2.focus:触发焦点 - mouse
- wheel
- input
- keyboard:
1.keydown
2.keypress: 按下某个键,并产生字符时触发(所有按键有效)
3.keyup
4.textInput: keypress 的扩展,只在编辑去触发(只有字符有效)
17.5 内存和性能
1.事件委托
利用冒泡给根节点添加事件,用子节点的ID区分事件的函数。onclick
2.及时删除事件
18 动画和canvas
18.1 动画 requestAnimationFrame
18.2 canvas
首先 获取绘图上下文
let context = drawing.getContext("2d");
let imgURL = drawing.toDataURL("image/png");
fillStyle
strokeStyle
fillRect(x,y,width,height)
strokeRect()
clearRect()
fillText()
strokeText()
arc() //绘制圆弧
arcTo()
context.lineTo(); context.stroke()//绘制路径
moveto()
claearPath()
rotate()
scale()
drawImage(image, x,y, width,height)
//渐变
context.fillSyle = gradient;
19.表单脚本
19.1 表单基础
getElementById() get the form
or
document.forms: return the list of the forms in the document
1.提交表单
<input type = 'submit'>
<button type = ''submit'>
<input type='image' src='img.gif'>
form.addEventListener("submit", (event) => { event.preventDefault(); })
from.submit();
2.重置表单
<input type = ' reset'>
<button type = ''reset'>
form.addEventListener("reset", (event) => { event.preventDefault(); })
form.reset();
3.表单中的元素字段
表单中的元素都可以用elements来访问: form.elements[0] or form.elements[“name of the element”] .
4.表单下字段的方法
focus(): 是这焦点到这个元素
blur()
5.表单字段的公共事件: addElementListener()
focus()
change
blur()
19.2 文本框编辑
1.<input>:
属性:
- type
- size
- value:初始值
- maxlength
2.<textarea>
属性
- rows
- cols
- 初始值 包含在 <>chushizhi<>
3.读取值 设置值
console.log(elemtent.value);
element.value = "new text"
4.全选文本
select()
textbox.addElementListener("focus", event =>{ event.target.select(); })
5.输入过滤
keypress
textbox.addEventListener("keypress", event => {
if( Reg.test(String.fromCharCode(event.charCode)) ){
event.preventDefault();
}
}
)
6.自动切换
通过判断
改变focus
7.表单验证
- 给字段添加 required 属性
- type=“email”/“url”; number, data month week time
- max min step
- stepUP() and stepDown() 当前数值加一减一
- checkValidity()检测是否有效
if(element.checkValidity()){}else{}
19.3 选择框编程
选择框是用 <select> <option> 构成
1.select属性方法
- add(newoption, reloption): rel之前添加新的选项
- multiple
- options:set of the all options
- remove(index)
- type:“select-one” / “select-mutiple”
2.option 属性方法
- index
- label
- selected
- text
- value
3.获取值
selectedIndex 好用
let selectbox = docu. forms[0].elements[0]
let text = selectbox.options[selectbox.selectedIndex].text / value.
20.JavaScript API
23.JSON
对象
方法:
-
stringify(): 把 javascript 转换成 json undefined会被跳过
第二个参数可以是 数组 或者 函数,
第三个参数缩进的空格
let book = {
title:"",
authors:[],
}
let jsontext = JSON.stringify(biid, ["title"])
//只会加title
let jsontext = JSON.stringify(biid, (key, value) => {
switch(key){
case "title":
return "a";
}
}
})
- parse(): 把 json 转换成javascript
24.网络请求和远程资源
1.FormData()
可以作为body内容发送
var formdata=new FormData();
//通过append()方法在末尾追加key为name值为laoliu的数据
formdata.append("name","laoliu");
//通过append()方法在末尾追加key为name值为laoli的数据
formdata.append("name","laoli");
//通过append()方法在末尾追加key为name值为laotie的数据
formdata.append("name","laotie");
//通过get方法读取key为name的第一个值
console.log(formdata.get("name"));//laoliu
//通过getAll方法读取key为name的所有值
console.log(formdata.getAll("name"));//["laoliu", "laoli", "laotie"]
formdata.set("name","laoli");
//通过get方法读取key为name的第一个值
console.log(formdata.get("name"));//laoli
2.fetch()
别的看 18340
25.客户端存取
18354
跳过