Open HolyZheng opened 6 years ago
执行环境定义了变量或函数有权访问的其他数据,决定了他们的行为。每个执行环境都有一个与之对应的变量对象,环境中定义的所有变量和函数都包含在这个对象中,比如web浏览器中,全局执行环境对应的对象就是window。
ps:执行环境对应于作用域,作用域它表明了变量的可访问范围,比如全局作用域,局部作用域。
作用域链
执行环境是用一个环境栈来管理的,栈的最底部就是我们的全局作用域,在执行代码的时候,每遇到一个新的执行环境,就把它推进栈中,栈的最顶部就是当前的执行环境。 作用域链,在函数调用的时候会给该函数创建一个作用域链,作用域链第一位为当前函数执行环境对应的变量对象,第二位对应该函数的外部函数的执行环境对应的变量对象,直到最后以为对应全局执行环境的变量对象,它的作用在于保证执行环境对有权访问的变量和函数的有序访问。
延长作用域链的方法
try catch语句的catch模块,它会在作用域链的顶端临时增加一个变量对象,并在代码执行后移除。
变量提升
JavaScript在编译阶段会把变量和函数的声明放入内存中,所有我们可以在代码中函数声明前正常使用函数,在变量声明前使用变量不会报错(值为undefined)。 ps: es6引入的const和let不存在变量提升。
上下文
是指函数this的指向,如当函数作为对象的方法被调用时,this 被设置为调用方法的对象;通过new的操作符创建一个对象的实例,this 的值将被设置为新创建的实例
闭包
闭包是指有权访问另一个函数作用域中变量的函数,常见的闭包创建方式是在一个函数内部创建另一个函数。
function wrap () { var data = 'something' return function() { console.log(data) } } var fun = wrap() fun() // 'something'
闭包产生的原因是内部函数的作用域链中包含了外部函数的作用域。 如何释放闭包中变量占用的内存呢
fun = nul
解除对匿名函数的引用,以便释放内存。
闭包的应用场景
- 作为访问私有变量和私有方法的共有方法
function obj () { var one = 1; var two = 2; return { getOne: function () { // 访问私有变量one return one; }, getTwo: function () { // 访问私有变量two return two; } } }
- 单例模式
function obj(data) { // .... } // 利用闭包实现单例模式,确保obj类只有一个实例 function singleton (data) { var instance; return function () { if (!instance) { instance = new obj(data) } return instance } }
事件模型
事件模型(事件流)分为三个阶段 事件捕获 -> 目标阶段 -> 事件冒泡
- 事件捕获的思想就是:不太具体的外层节点应该更早的接收到事件,而最具体的目标节点最后接收到事件;事件的触发顺序是从外层节点向内层具体目标节点传递。
- 事件冒泡则是事件由最具体的目标元素开始,逐级向上传播到外层不具体的节点上去。
- 目标阶段就是事件的触发了。
事件冒泡的利用:事件委托
在JavaScript中,添加到页面的事件处理程序的数量直接关系到页面的整体性能,绑定的事件处理程序越多,对性能的影响越大。事件委托就是一个解决“事件处理程序过多”的方案。 具体实现:在dom树中尽可能高的层次上添加事件处理程序,在事件冒泡阶段处理在子节点中触发的事件。 event.target指向触发事件的子节点,event.currenttarget指向事件处理程序绑定的元素。
<ul id="list"> <li>item 1</li> <li>item 2</li> <li>item 3</li> ...... <li>item n</li> </ul>
// 给父层元素绑定事件 document.getElementById('list').addEventListener('click', function (event) { // ie6-8 event.srcElement; var target = event.target // 判断是否匹配目标元素 if (target.nodeName.toLocaleLowerCase === 'li') { console.log('the content is: ', target.innerHTML); } });
// 阻止事件冒泡 function stopPropagation(e) { var e = e || window.event; if ( e && e.stopPropagation ){ e.stopPropagation(); }else{ e.cancelBubble = true; } } // 阻止默认行为 function stopDefault(e) { var e = e || window.event; if (e && e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } return false; }
//跨浏览器事件处理程序 var eventUtil = { // 添加句柄 addHandler: function(element, type, handler){ if(element.addEventListener){ element.addEventListener(type, handler, false); }else if(element.attachEvent){ element.attachEvent('on' + type, handler); }else{ element['on' + type] = handler; } }, // 删除句柄 removeHandler: function(element, type, handler){ if(element.removeEventListener){ element.removeEventListener(type, handler, false); }else if(element.detachEvent){ element.detachEvent('on' + type, handler); }else{ element['on' + type] = null; } } };
var oBtn = document.getElementById('btn'); function evtFn(){ alert('hello world'); } eventUtil.addHandler(oBtn, 'click', evtFn); eventUtil.removeHandler(oBtn, 'click', evtFn);
### 深浅拷贝
> ps: 趁热理解浅拷贝和深拷贝 对于原始类型如字符串,深浅拷贝都是是对值的复制,对于引用类型如对象来说,浅拷贝是对对象地址的复制,深拷贝则是对整个对象的拷贝。
[es5的数据类型](https://segmentfault.com/a/1190000012808752)
JavaScript有5种基本类型:
undefined null boolean string number es6: Symbol
4种引用类型:
Object Array Data RegExp es6: Set Map
typeof 返回的值有
```js
typeof {}
"object"
typeof []
"object"
typeof null
"object"
typeof undefined
"undefined"
typeof function a () {}
"function"
typeof 'abc'
"string"
typeof true
"boolean"
typeof 1
"number"
typeof new Date()
"object"
let a = {
age: 1
}
let b = Object.assign({}, a)
// let b = {...a}
a.age = 2
console.log(b.age) // 1
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
// 但是该方法会忽略掉函数和`undefined`
// 递归实现
let cloneObj = function (obj) {
if (typeof obj !== 'object') {
return;
} else {
let newobj = obj.constructor === Array ? [] : {};
for (var i in obj) {
newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i]
}
return newobj;
}
}
ps: 面向对象三大特征: 封装,继承,多态。可通过闭包实现私有变量,私有方法,共有方法来实现封装,继承方法很多,es6才引进class/extends关键字来实现类和继承。js本身是一个动态的语言,本身支持多态。可以通过判断参数数量进行不同操作来模拟函数重载
面向对象的语言都有一个标准——他们都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。但是JavaScript本身没有类的概念,所以在JavaScript的对象与其他基于类的语言的对象不一样,在JavaScript中,对象的定义是:属性的集合,其中的属性可以是基本值,对象或者函数。
var obj = {
name: 'xx',
age: 12
}
function Obj () {
this.name = 'xx',
this.age = 12,
this.fun = function(){}
}
var objOne = newObj()
function Obj () { }
Obj.prototype.name = 'xx'
Obj.prototype.age = 12
function Obj(arg) {
this.data = arg
}
Obj.prototype.fun = function () { // ... }
function createObj (data) {
var obj = {}
obj.somedata = data
return obj
}
原型链继承就是将父类的实例赋值给子类的原型。
// 父类
function SuperType () {}
// 子类
function Sub () {}
// 继承
Sub.prototype = new SuperType()
问题:通过继承得到的属性和方法会在子类的所有实例之间共享
在子类构造函数的内部使用子类构造函数的执行上下文调用父类的构造函数
// 父类
function SuperType () {}
// 子类
function Sub () {
// 继承
SuperType.call(this)
}
问题:父类原型中的方法对子类是不可见的,只能继承构造函数中定义的属性,所有继承过来的属性,在子类创建实例的时候都会重新创建一遍。
组合继承就是原型链继承和借用构造函数继承的组合,通过原型链继承来继承来自父类原型的属性,通过借用构造函数的方式来继承来自父类构造函数的属性。
function SuperType () {}
function Sub () {
SuperType.call(this)
}
Sub.prototype = new SuperType()
Sub.prototype.constructor = Sub
问题:子类的原型与实例中存在着相同的属性。
先创建一个临时的构造函数,然后将传入的对象作为这个临时构造函数的原型,最后返回这个临时构造函数的实例。与 Object.create()的作用相似。
function object (o) {
function F () { }
F.prototype = o
return new F()
}
问题:子类实例之间存在属性共享的问题,子类和父类之间是一个浅复制的关系。
创建一个仅用于封装继承过程的函数,函数内部动态的给函数添加属性。
function object(o) {
var sub = Object.create(o)
sub.prototype.xxx = xxx
return sub
}
问题子类之间有属性共享的问题,子类和父类之间是浅复制关系
先创建一个空对象,然后父类构造函数的原型赋值给空对象的原型,再将空对象赋值给子类构造函数的原型
function SuperType () {}
function Sub () {
SuperType.call(this)
}
// 过滤掉父类构造函数中的属性
Sub.prototype = Object.create(SuperType.prototype)
Sub.prototype.constructor = Sub
最完美的继承方式
ES6 class 与 extends
class
ES6引进了class关键字,但是它只是语法糖,只是让对象的写法更加清晰更像面向对象的语法,如:
// es5 function Point (x,y) { this.x = x this.y = y } Point.prototype.doSomething = function () {}
// es6 class Point { constructor (x, y) { this.x= x this.y = y } doSomething() {} }
typeof Point === Function Point === Point.prototype.constructor
#### 注意:
1. es6内部定义的方法是不可枚举的,如disomething()
2. 类必须使用new运算符,不能直接运行
3. 不存在变量提升
#### 只是语法糖
```js
// es6
class Point {
constructor (x, y) {
this.x= x
this.y = y
}
doSomething() {}
}
等同于,全部定义在原型上
Point.prototype = {
constructor (x, y) {
this.x= x
this.y = y
}
doSomething() {}
}
es6通过extends关键字实现继承,这比es5通过原型实现继承的写法要清晰和方便得多。
class ColorPoint extends Point {
constructor (x, y, color) {
super(x, y) // 调用父类构造函数
this.color = color
}
doSomething() {}
}
extends继承的效果等同于es5中的寄生组合式继承
作为对象,指向父类得原型对象。
ColorPoint.__proto__ === Point
ColorPoint.prototype.__proto__ === Point.prototype
可通过static关键字定义静态成员
class Obj {
constructor(){}
static doSomething(){ console.log('static') }
}
Obj.doSomething() // 'static'
可以直接重写某个属性的getter和setter。
class Car {
constructor (name) {
this._name = name;
}
set name (name) {
this._name = name;
}
get name () {
return this._name;
}
} let car = new Car('Tesla'); console.log(car.name); // Tesla car.name = 'BMW'; console.log(car.name); // BMW
这篇文章主要 解决的问题 是:什么是
__proto__
?什么是prototype
?他们的关系是什么?在原型链中扮演什么角色?
prototype
是函数的一个属性,在定义构造函数的时候自动创建,它指向函数的原型,被 __proto__
指向。这个原型对象里包含着自定义的方法属性。__proto__
是对象的内部属性,它指向构造器的prototype
,对象依赖它来进行原型链的查询,instanceof方法也是依赖它来判断是否存在继承关系。prototype
只能作为构造函数的属性,而__proto__
可以作为任意对象的属性。看一段代码:
function Foo(name) { this.name = name };
Foo.prototype.age = 18;
let student = new Foo("holy");
我们通过一张图来表示这段代码构建的原型链:
这张图中原型链可分成两部分:
student ---> Foo.prototype ---> Object.prototype ---> null
Foo ---> Function.prototype ---> Object.prototype ---> null
我们从对象student
看起:根据 概念3 , prototype 只能作为构造函数的属性,proto只能作为对象的属性。所以对象sutdent
只有proto,没有prototype。
student.prototype;
undefined
而 student对象
是Foo构造函数的一个实例,根据 概念2 它的proto指向Foo.prototype
student.__ptoto__ == Foo.prototype;
true
以为 Foo.prototype
是一个对象,所以 Foo.prototype.proto指向 Object.prototype
Foo.prototype.__proto__ == Object.prototype;
true
再来看第二部分:
Foo 是一个函数
,所以 Foo.proto指向 Function.prototype
Foo.__proto__ == Function.prototype
true
再 JavaScript 中函数都是第一公民,而且函数也是对象,所以Function.prototype.proto指向 Object.prototype
Function.prototype.__proto__ == Object.prototype
true
student.name
在student中找到 name属性,返回“holy”;student.age
在student中未找到,于是通过student.__proto__在Foo.prototype中找到,返回 18;student.toString()
在student中未找到,接着通过student.__proto在Foo.prototype中寻找,未找到,继续通过Foo.prototype.__proto在Object.prototype中寻找,找到了,返回‘[object object]’。student.getWeight()
依次在student、Foo.prototype、Object.prototype中寻找,均未找到,抛出错误。 bind()方法,返回一个绑定函数,第一参数作为绑定函数的执行上下文,其他参数会在绑定函数执行的时候置于其他实参之前传递给绑定函数。
var pokemon = {
firstname: 'Pika',
lastname: 'Chu ',
getPokeName: function() {
var fullname = this.firstname + ' ' + this.lastname;
return fullname;
}
};
var pokemonName = function() {
console.log(this.getPokeName() + 'I choose you!');
};
var logPokemon = pokemonName.bind(pokemon);
logPokemon();
// 'Pika Chu I choose you!'
call()方法接收多个参数,第一个参数作为函数this的指向,其他参数作为函数的参数,并且不会返回新的函数,而是直接执行函数。
apply()方法和call类似,不过apply()方法只有两个参数,第一个为函数的this指向,第二个为一个数组,数组的元素作为函数的参数,跟call一样会立即执行这个函数
var pokemon = {
firstname: 'Pika',
lastname: 'Chu ',
getPokeName: function() {
var fullname = this.firstname + ' ' + this.lastname;
return fullname;
}
};
var pokemonName = function(snack, hobby) {
console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby);
};
pokemonName.call(pokemon,'sushi', 'algorithms'); // Pika Chu loves sushi and algorithms
pokemonName.apply(pokemon,['sushi', 'algorithms']); // Pika Chu loves sushi and algorithms
Function.prototype.myCall = function (ctx) {
var ctx = ctx || window
// 给 ctx 添加一个属性
ctx.fn = this
// 将 ctx 后面的参数取出来
var args = [...arguments].slice(1)
var result = ctx.fn(...args)
// 删除 fn
delete ctx.fn
return result
}
Function.prototype.myApply = function (ctx) {
var ctx = ctx || window
ctx.fn = this
var result
if (arguments[1]) {
result = ctx.fn(...arguments[1])
} else {
result = ctx.fn()
}
delete ctx.fn
return result
}
Function.prototype.myBind = function (ctx) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
var _this = this
var args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(ctx, args.concat(...arguments))
}
}
function Person() {
this.name = 'holz'
}
let p = new Person();
创建数组的方法:
let arr = new Array() // new Array('a', 'b', 'c')
let arr = [] // ['a', 'b', 'c']
concat(), every(), filter(), forEach(), indexOf(), isArray(), map(), pop(), push(), reduce(), reverse(), some(), sort(), splice(), toString(), unshift(), slice() 会对原数组造成影响的有: pop(), push(), reverse(), splice(), sort(), shift(), unshift(),
concat() 用于连接两个数组,不会影响,而是返回一个被连接数组的副本
arrA.concat(arrB)
arrA.concat(arrB, arrC)
arrA.concat('a', 'b', 'c')
every() 检查是否所以成员都符合条件
var ages = [32, 33, 16, 40];
arges.every(age => {
return age > 18
})
// false
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。不影响原数组
isArray(),判断一个对象是否是数组
Array.isArray('sdadas')
// false
Array.isArray([])
// true
Array.isArray({length:0})
// false
join() 方法用于把数组中的所有元素转换一个字符串。默认分隔符是 逗号 不影响原数组
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var energy = fruits.join();
// Banana,Orange,Apple,Mango
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。不影响原数组
let arr = [1, 2, 3, 4]
arr.map(item => {
return item > 2 ? item : 0
})
// [0, 0, 3, 4]
reduce(),法对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => {
console.log(accumulator,currentValue);
return accumulator + currentValue
};
// 过程 array1.reduce(reducer) 1 2 3 3 6 4
// 1 + 2 + 3 + 4 console.log(array1.reduce(reducer)); // expected output: 10
// 5 + 1 + 2 + 3 + 4 console.log(array1.reduce(reducer, 5)); // expected output: 15
8. slice(),选取数组的的一部分,并返回一个新数组。**不影响原数组**
```js
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1,3);
// Orange,Lemon
splice() 方法用于插入、删除或替换数组的元素。返回一个数组包含被删除的数组成员,会对原数组造成影响
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2,0,"Lemon","Kiwi");
// Banana,Orange,Lemon,Kiwi,Apple,Mango
sort(),方法用于对数组的元素进行排序 对原数组有影响
// 默认排序顺序是根据字符串Unicode码点
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
// Apple,Banana,Mango,Orange
var points = [40,100,1,5,25,10]; points.sort() // [1, 10, 100, 25, 40, 5] points.sort((a,b) => a-b) // [1, 5, 10, 25, 40, 100]
### ES6
> 扩展运算符,Array.from(),Array.of(),find(),findIndex(),fill(),entries(),keys(),values(),includes()
1. 扩展运算符
```js
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
// 复制数组 es5和es6
const a2 = a1.concat();
const a2 = [...a1];
// 合并数组
[...a1, ...a2]
扩展运算符分为数组的扩展运算符和对象的扩展运算符,在数组方面可以将具有Iterator 接口的数据接口转成数组:比如
[...arguments]
[...'abcdef']
[...[1,2,3]]
[...NodeList]
在对象方面,可以提取对象的可遍历属性:
let obj = {a: 1, b: 2}
let a = { ...obj }
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
3. Array.of(),Array.of方法用于将一组值,转换为数组。
```js
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' // 'b'
for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" // 1 "b"
7. includes()
```js
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
HttpOnly:不能通过 js 访问 cookie,减少XSS攻击 Secure:只允许在https请求中携带cookie SameSite:规定浏览器不能再跨域请求中携带cookie,减少csrf攻击 Domain,path规定 cookie 的作用域,即在那个url下有作用。
localStorage.setItem('name', 'holz')
let name = localStorage.getItem('name')
localStorage.removeItem('name')
localStorage.clear()
### sessionStorage
- 页面关闭就清理
- 5 M容量
```js
// 保存数据到sessionStorage
sessionStorage.setItem('key', 'value');
// 从sessionStorage获取数据
var data = sessionStorage.getItem('key');
// 从sessionStorage删除保存的数据
sessionStorage.removeItem('key');
// 从sessionStorage删除所有保存的数据
sessionStorage.clear();
下面的示例会自动保存一个文本输入框的内容,如果浏览器因偶然因素被刷新了,文本输入框里面的内容会被恢复,因此写入的内容不会丢失。
// 获取文本输入框
var field = document.getElementById("field");
// 检测是否存在 autosave 键值
// (这个会在页面偶然被刷新的情况下存在)
if (sessionStorage.getItem("autosave")) {
// 恢复文本输入框的内容
field.value = sessionStorage.getItem("autosave");
}
// 监听文本输入框的 change 事件
field.addEventListener("change", function() {
// 保存结果到 sessionStorage 对象中
sessionStorage.setItem("autosave", field.value);
});
Service Worker 简介 Service workers 本质上充当Web应用程序与浏览器之间的代理服务器。它目的在于创建更好的离线体验。
// index.js
if (navigator.serviceWorker) {
navigator.serviceWorker
.register("sw.js")
.then(function(registration) {
console.log("service worker 注册成功");
})
.catch(function(err) {
console.log("servcie worker 注册失败");
});
}
// sw.js
// 监听 `install` 事件,回调中缓存所需文件
self.addEventListener("install", e => {
e.waitUntil(
caches.open("my-cache").then(function(cache) {
return cache.addAll(["./index.html", "./index.js"]);
})
);
});
// 拦截所有请求事件 // 如果缓存中已经有请求的数据就直接用缓存,否则去请求数据 self.addEventListener("fetch", e => { e.respondWith( caches.match(e.request).then(function(response) { if (response) { return response; } console.log("fetch source"); }) ); });
使用for..in
迭代,并通过 hasOwnProperty
进行筛选
for (let item in obj) {
// 过滤掉原型上的属性
if (obj.hasOwnProperty(item)) {
console.log(obj[item])
}
}
使用 getOwnPropertyNames
进行迭代返回自身所有可枚举和不可枚举属性的名字,并筛选不通过 propertyIsEnumerable
方法检测的属性
let obj = function () {}
obj.prototype.addObj = 1
for (let item of Object.getOwnPropertyNames(obj)) {
if (!obj.propertyIsEnumerable(item)) {
console.log(obj[item])
}
}
length 0
name obj
arguments null
caller null
prototype {addObj: 1, constructor: ƒ}
通过 getOwnPropertyNames
for (let item of Object.getOwnPropertyNames(obj)) {
console.log(obj[item])
}
AJAX 是一种在无需重新加载整个网页的情况下,进行页面的局部更新的技术。主要通过XMLHttpRequest对象实现,它可以让我们通过JavaScript向服务器发起异步请求。
var requestObj;
if (window.XMLHttpRequest) { requestObj = new XMLHttpRequest(); } else { requestObj = new ActiveXObject("Microsoft.XMLHTTP") }
requestObj.open("方法", url, async); requestObj.setRequestHeader("Content-Type", "xxxxxxxx") //根据方法设置相应的头 requestObj.send();
// 获取响应 requestObj.onreadystatechange = function() { if (requestObj.readyState == 4) { if (requestObj.status == 200) { console.log(requestObj.reponseText); } } }
/ 0 未初始化,即未调用open 1 启动,已经调用了open,但未调用send 2 发送,调用send 3 接受,接受到了部分数据 4 数据接受完成 /
### 2. Fetch
提供了一个 JavaScript接口,进行请求和响应
```js
// Example POST method implementation:
postData('http://example.com/answer', {answer: 42})
.then(data => console.log(data)) // JSON from `response.json()` call
.catch(error => console.error(error))
function postData(url, data) {
// Default options are marked with *
return fetch(url, {
body: JSON.stringify(data), // must match 'Content-Type' header
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, same-origin, *omit
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, *same-origin
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // *client, no-referrer
})
.then(response => response.json()) // parses response to JSON
}
<form action="http://foo.com" method="get">
<div>
<label for="say">What greeting do you want to say?</label>
<input name="say" id="say" value="Hi">
</div>
<div>
<label for="to">Who do you want to say it to?</label>
<input name="to" id="to" value="Mom">
</div>
<div>
<button>Send my greetings</button>
</div>
</form>
当你提交表单的时候,您将看到
www.foo.com/?say=Hi&to=Mom
在浏览器地址栏里。 如果是post方法
POST / HTTP/1.1
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
say=Hi&to=Mom
typeof instanceof Array.isArray Object.prototype.toString.apply()
无法区分null,数组和对象
typeof {}
"object"
typeof []
"object"
typeof null
"object"
typeof undefined
"undefined"
typeof function a () {}
"function"
typeof 'abc'
"string"
typeof true
"boolean"
typeof 1
"number"
typeof new Date()
"object"
一个变量在其原型链中是否存在某个构造函数的 prototype 属性 instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
[] instanceof Array
true
[] instanceof Object
true
let obj = {}
undefined
obj instanceof Object
true
function f () {}
undefined
f instanceof Object
true
f instanceof Function
true
null instanceof Object
false
undefined instanceof Object
false
'a' instanceof String
false
1 instanceof Number
false
true instanceof Boolean
Object.prototype.toString.apply({})
"[object Object]"
Object.prototype.toString.apply([])
"[object Array]"
Object.prototype.toString.apply("str")
"[object String]"
Object.prototype.toString.apply(1)
"[object Number]"
Object.prototype.toString.apply(null)
"[object Null]"
Object.prototype.toString.apply(undefined)
"[object Undefined]"
function f () {}
Object.prototype.toString.apply(f)
"[object Function]"
f.constructor === Function
true
[].constructor === Array
true
let obj = {}
obj.constructor === Object
true
let n = null
n.constructor === Object
/*
* VM810:1 Uncaught TypeError: Cannot read property 'constructor' of null
* at <anonymous>:1:3
* (anonymous) @ VM810:1
*/
let un = undefined
un.constructor
/*
* VM93:1 Uncaught TypeError: Cannot read property 'constructor' of undefined
* at <anonymous>:1:4
*/
"s".constructor === String
true
let num = 1;
num.constructor === Number
true
箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
关于this,箭头函数没有自己的this,他内部出现的this,指的是它定义时所在的上下文。
不应该使用箭头函数的情况:
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
const s = new Set();
const set = new Set([1, 2, 3, 4, 4]);
// 数组去重
let arr = [1,1,2,2,3,3]
let s = new Set(arr)
[...s]
// [1, 2, 3]
Set 结构的实例有以下属性。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
成员只能时对象
Map类似于对象,也键值对的集合,但是他的键可以是各种类型的值。
键名只能是对象。 它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。 只有 get()、set()、has()、delete()。
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
[...arr1, ...arr2]
let array = [...nodeList];
如果没有迭代器接口,如类数组对象arrayLike,可以通过array.prototype.slice.call
Array.prototype.slice.call(arrayLike)
vue生命周期,官网生命周期图示
beforeCreate,create,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed
作者:holyZheng 转载请注明出处
DOM
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描述了一个层次化的节点树,允许开发人员添加,移除和修改页面的某一部分。
节点层次
DOM可以将任何html或xml文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型。 常见类型:
1. node类型
JavaScript中所有节点类型都继承自node类型,所以都共享着相同的基本属性和方法,比如
2. Document类型
表示文档,在浏览器中docuemnt是HTMLDocument(继承自Document)的实例,而且document是window对象的一个属性。此类型的nodeType = 9,nodeName = ”#document“。
3. Element 类型
用于表示html或xml元素,nodeType = 1,nodeName 的值为元素的名称,parentNode可能是Document或Element。
4. Text 类型
表示文本节点,nodeType = 3,nodeName的值为”#text“,nodeValue的值为文本值
5 . Comment 类型
表示注释,nodeType = 8,nodeName的值为”#comment“, nodeValue为注释的内容
6. DocumentFragment类型
是一种”轻量级“的文档,可以包含和控制节点,但不会占用额外资源,vue1.0就是采用它来进行dom操作的优化,vue2.0才引进了virtual dom,nodeType = 11,nodeName的值为”#document-fragment“
7. Attr类型
表示元素的特性,nodeType = 2, nodeName是特性名,nodeValue是特性值
DOM扩展
选择符 api
1. querySelector()
接收一个css 选择符号,返回第一个匹配的元素
2. querySelectorAll()
接收一个css 选择符号,返回一个nodelist的实例
3. matchesSelector()
接收一个css 选择符,如果调用元素与该选择符相符,返回true。
元素遍历
HTML5
好像写得太细。。赶紧结个尾先。。
总结
DOM是针对HTML和XML文档的一个API(应用程序编程接口),将任何html或xml文档描绘成一个由多层节点构成的结构,允许开发人员添加,移除和修改页面的某一部分。比如一些反映节点关系的api,操作节点的api,查看文档信息的api,创建节点的api,查询节点的api等。