- function are first-class objects 函数对象
- function closures 闭包
- scopes 作用域
- prototype-based object orientation 原型链
- Generators 继承
- Promises 异步
- Proxies 处理器
- Advanced array methods 高级数组方法
- Maps map对象
- Regular expressions 正则表达式
- Modules 模块化
-
判断变量是否达到预期 assert(condition,message)
condition为假,message输出
栗子:
assert(a===1,"Disaster! a is not 1!")
-
获取代码段运行时间
栗子:
console.time("My operation"); for(var n = 0; n < maxCount; n++) { /*perform the operation to be measured*/ } console.timeEnd("My operation");
- enters url
- generates a request and sends it to servers
- server: performs actions or gets a resource; sends response to client;
- 接收HTML和CSS,JavaScript等文件,开始page build
- Building the DOM from HTML
- Executing JavaScript code
- 从头到尾逐句执行,HTML渲染可以被script标签或者css语句打断,而先去执行标签里的,执行完之后再渲染
- 创建和持续监控 event queue, queue里有事件则陆续执行,没有事件则不断检测是否有新的事件。
- event包括以下几种
- Broswer events , like "onload()"
- Network events , like "ajax,server-side"
- User events , like "click"
- Time events , like "timeout, interval"
- 添加监听事件有2种方法:
- el.addEventListener("click",callback)
- el.onclick = function(){}
- event包括以下几种
- 关闭网页,停止监听,释放内存
-
函数可以被赋予给一个变量
var ninjaFunction = function(){}
-
函数可以成为数组元素
ninjaArray.push(function(){})
-
函数可以成为对象的一个属性
ninja.data = function(){}
-
函数可以成为另一个函数的参数以及返回值
function call(ninjaFunction) { ninjaFunction() return function(){} }
-
函数可以被当作对象一样被赋予属性
let ninjaFunction = function(){} ninjaFunction.word = "ninja is cool"
回调函数实现原理就是调用一个函数A,函数A完成某些操作之后返回了一个函数B的执行体,所以又去执行函数B , 函数B执行完之后再把返回值给函数A , 函数A再返回函数B传过来的返回值。
栗子:
let text = 'call back demo';
report("before definning function");
function useless(ninjaCallback) {
report("In useless function");
return ninjaCallback();
}
function getText() {
report("In getText function");
return text;
}
report("before making all the calls");
assert(useless(getText) === text,"The useless function works! "+text);
report("After the calls have been made");
判断一个数是否为素数:
function isPrime(value) {
//给函数添加了一个属性 answers : {} ,用来存储之前测试过的值
if(!isPrime.answers) {
isPrime.answers = {};
}
if(isPrime.answers[value] !== undefined) {
return isPrime.answers[value];
}
let prime = value !== 1;
for(let i = 2; i < value ; i++) {
if(value % i == 0) {
prime = false;
break;
}
}
return isPrime.answers[value] = primse; //进行存储
}- Function declarations
function myFun(){}
- Function expressions
let myFun = function() {} Myfunc(function(){ return function(){}; }) (function namedFunctionExpresstion() { })(); +function(){}() -function(){}() !function(){}() ~function(){}()
- Arrow functions
myArg => myArg * 2
- function constructors
new Function('a','b','return a + b');
- generator functions
function* myGen(){}
- 根据函数参数所在不同地方,和不同作用,它们有不同的英文解释,如
function skulk(ninja){
return performAction(ninja,"skulking")
}
// (ninja),这里的ninja 叫做 function parameters
// return performAction(ninja,"skulking"),这里的ninja和"skulking"叫做function arguments- rest parameters
可以用rest parameters来代表剩余的所有参数,并且rest parameters只能放在参数里最后一个位置。
function multiMax(first,...restParameters) {
}
//restParameters是一个数组- 默认参数
function performAction(ninja, action = "skulking")当创建或者调用函数时,有2个固定对象类型的参数被传入,arguments和this。
- arguments.length 返回了一个函数的参数个数,即使函数定义时()中没有parameters,只要调用的时候传入了parameters,arguments就不等于0。 如:
function whatever() {
return arguments.length;
}
whatever(1,2,3)
//返回3- 在普通模式下,arguments[i]和如上面例子中whatever(a,b,c)相同下标的值相互影响和改变。
function whatever(a,b,c) {
arguments[0] = 4;
return a == 4;
}
whatever(1,2,3)
//返回true- 在严格模式下,arguments[i]与parameters中的值不会同步改变
'use strict';
function whatever(a,b,c) {
arguments[0] = 4;
return a == 4;
}
whatever(1,2,3)
//返回false,a == 1 - 调用一个函数的几种方法
- As a function --- skulk()
- As a method --- ninja.skulk()
- As a constructor --- new Ninja()
- use apply or call methods --- skulk.call(ninja) or skulk.apply(ninja)
- 一般情况下当不同调用时 this 的指向
- As a function,this == 严格模式:undefined,普通模式:window.
- As a method of a object, this == the object.
- As a constructor , this == the newly constructed object
- with call and apply , this == the first parameter
- 几种特殊情况,箭头函数和bind方法
- 箭头函数没有自己的this ,所以如果它是在函数里被创建的,它的this指的是这个函数,但如果它在对象里被创建的,并且被赋值给对象的一个属性,则它的this 在普通模式下是window, 在严格模式下是undefined.
- 用bind方法可以创建一个新的有一样内容的函数,并且this一定是这个新函数。
function test1() {
let sum = arguments.reduce((accumulator,value) => {
accumulator += value;
return accumulator;
},0);
return sum;
}
//等同于
function test2(...rest) {
let sum = rest.reduce((accumulator,value)=>{
accumulator += value;
return accumulator;
},0)
return sum;
} function* weaponGenerator() {
yield "Katana";
yield "Wakizashi";
return 'return';//不起作用
}
//第一种输出写法
for(let weapon of weaponGenerator()){
//weapon 为 value
assert(weapon !== undefined , weapon);
//"Katana"
//"Wakizashi"
}
//第二种输出写法
const weaponIterator = weaponGenerator();
const result1 = weaponIterator.next();
// result1 = {value:"Katana",done:false}
const result2 = weaponIterator.next();
//result2 = {value:"Wakizashi",done:false}
const result3 = weaponIterator.next();
//result3 = {value:undefined,done:true}
- 调用generator函数后从第一个yield开始算,之后每次调用.next()就唤醒函数,碰到下一个yield就停止并且挂起,下次调用.next()时从挂起的地方开始。
- 当遇到return 和 没有代码执行后就会返回一个{value:undefined,done:true}对象,并且return后面的代码不起作用
- 如果yield表达式后面接的还是个generator()函数(假设为函数A),则下次.next()重新唤醒函数的时候就进入函数A中,在函数A中以同样的规则运行。
- generator函数的上下文和标准函数不同,当执行完一次yield后,此函数的上下文会从函数栈弹出,但是它弹出时的状态被开始调用函数而使用的承接的变量(即weaponIterator)记录着,所以下一次唤醒generator时,就直接根据记录找到上次停止的地方开始执行,函数栈最顶端放置的还是generator函数上下文,只是执行状态不同。
例子:
function Ninja() {}
Ninja.prototype.swingSword = function() {
return true;
}
const ninja1 = Ninja();
//此时ninja1 == undefined
const ninja2 = new Ninja();
//此时 ninja2 是一个实例化Ninja类生成的对象,并且有swingSword属性,并且可以调用这个属性
//即: (ninja2 && ninja2.swingSword && ninja2.swingSword()) == true function Ninja() {
this.swung = false;
//[1]
this.swingSword = function() {
return !this.swung;
}
}
//[2]
Ninja.prototype.swingSword = function() {
return this.swung;
}
const ninja = new Ninja();如果 Ninja()函数中有 swingSword属性,那么当用ninja2去拿swingSword属性时,拿的是函数内部[1]的,而不是原型的[2]。
function Person(){}
Person.prototype.dance = function(){}
function Ninja(){}
Ninja.prototype = new Person();
Object.defineProperty(Ninja.prototype,'constructor',{
enumerable:false,
value:Ninja,
writable:true
})
//防止出现 ninja.constructor !== Ninja 却 === Person 的问题
var ninja = new Ninja()实例跟踪的原型是 “ 实例化 和 某个原型改变 ” 之间,即 改变之前 的原型。
例子:
function Ninja() {
this.swung = true;
}
const ninja1 = new Ninja();
Ninja.prototype.swingSword = function() {
return this.swung;
}
//此时 ninja1.swingSword()存在,可以被调用
Ninja.prototype = {
pierce:function() {
return true;
}
}
// 此时 ninja1.swingSword()存在,可以被调用
const ninja2 = new Ninja();
//此时ninja2的原型是{pierce:function() {return true;}},即改变后的原型包含生成和继承,原理还是 原型链,class只不过是个语法糖,只是内层将class转变成了原型链模式
class Person() {
constructor(name) {
this.name = name;
}
dance() {
return true;
}
}
class Ninja extends Person() {
constructor(name,weapon) {
super(name);
this.weapon = weapon;
}
wieldWeapon() {
return true;
}
}
var ninja = new Ninja('Yoshi','Wakizashi');
//此时 ninja有 Ninja 类 和 Person类的所有方法和属性
// ninja instanceof Person === true
// ninja instanceof Ninja == true-
特点
- 超过数组范围的访问将返回 undefined
- 如果数组长度(array.length = x)被直接赋值扩大,没有赋值的元素将为 undefined
- 如果数组长度被直接赋值减小,除了长度内的元素,其它元素将直接被删除
-
方法:
- push , pop - 尾部
- unshift , shift - 头部
- find,findIndex - 寻找
- IndexOf - 是否存在于,下标为多少
- splice(index,length,...insertArgs) -如果没有后面的参数就是删除,如果有则是删除后插入参数【替代】
- map,filter,reduce
- sort,回调函数返回-1,从小到大;返回1,从大到小
-
在对象Object里利用数组的方法
push的例子:
let obj = { length:0, add: function(value) { Array.prototype.push.call(this,value); //Array.prototype.push.apply(obj,[...args]) } } obj.add('lijia'); obj.add('xian'); console.log(obj) //{ '0': 'lijia', '1':'xian',length: 2, add: [Function: add] }
注意:函数和数组都是一种对象
- 意义: 解决对象存储只能把key当作string的缺陷
- 特点:Map的key可以为任何对象
- 方法:
- size 长度
- clear() 清空
- has(key), 判断Map中key是否存在,返回bool
- set(key,value) 设置map键和键值
- get(key) 获取key值
- values() 返回所有的键值
- keys() 返回所有的键
- for(let item of map){},这将遍历整个map,每个item是一个只有2个元素的数组,item[0] 为key, item[1] 为value
- 例子
const ninjas = new Map(); const ninja1 = {name:'C'}; const ninaj2 = {name:'M'}; ninjas.set(ninja1,{homeIsland:'Honshu'}); ninjas.set(ninja2,{homeIsland:'Hokhaido'}); console.log(ninjas.get(ninja1).homeIsland) //Honshu
- 特点:Set中的所有值都是独一无二的
- 意义:用来去重,取交和并集比较容易
- 方法:
- has(value),判断value值是否存在,返回bool
- add(value),从尾部添加value值,如果set集中已经存在,则不会产生任何影响
- for...of 遍历
- size 元素数量【长度】
- delete(value) 删除
- entries() 方法返回一个新的迭代器对象 ,这个对象的元素是类似 [value, value] 形式的数组
- 实例化:
//实例化时参数必须为数组
const numbers = new Set(['1','2','3']);- hiding implementation details and defining module interface (隐藏实现细节,定义模块接口)
- 实现"hiding implementation details"利用函数作用域
- 实现"defining module interface"利用返回对象和闭包保持函数变量私有
//module pattern
const MouseCountModule = function() {
let numClicks = 0;
const handleClick = () =>{
alert(numClicks);
}
return {
countClicks : () =>{
document.addEventListener("click",handleClick)
}
}
}()
typeof MouseCountModule.numClicks //=> undefined
typeof MouseCountModule.handleClick//=>undefined
typeof MouseCountModule.coutClicks()//=>function
//module extension
//各个方法的私有变量不可以相互传递
//1.
(function (module) {
let numScrolls = 0;
const handleScrolls = ()=> {
alert(++numScrolls);
}
module.countScrolls = () => {document.addEventListener("wheel",handleClick);
}
})(MouseCounterModule);
//2.
MouseCounterModule.newMethod = () => {}
//3.
MouseCounterModule.newSubmodule = () => {
return {...};
}()- AMD 异步加载,基于模块包,主要适用于浏览器
- CommonJS 同步加载,基于文件,主要适用于Node这种服务器平台
- 三者关系:ES6 modules 是AMD,CommonJS 优点的集合,CommonJS 和 ES6 modules都是 基于文件的,即 one module per file;它们的语法类似,利用export 暴露,import 引入;AMD和ES6 module 都是异步加载的
- ES6 modules 可以利用default export 简单地暴露整个模块
- 所有的import 和 exports 都可以利用 as 重新命名
-
Dom 的attribute 和 property 不是同一个东西,但是dom自带的大多数属性对于二者来说是同步的,即:DOM.setAttribute('id','name') 等于 DOM.id = name;而程序员给dom加的特殊属性只能用DOM.getAttribute获取到
-
" dom.style.property"只能获取到内联的style属性,< style >内的或者link 引入的属性都无法被获取或者记录,但是页面上会展现
-
将带“-”的属性转化为驼峰格式
function style(element,name,value) {
name = name.replace(/-([a-z])/ig,(all,letter)=>{
return letter.toUpperCase();
})
if(typeof value !== 'undefined') {
element.style[name] = value;
}
return element.style[name];
}- getComputedStyle