function add(x,y){ //函数,声明提升,可以在函数定义之前调用 return x+y } var add = function (x,y){ //函数表达式,不会提升声明 return x+y } var sum1 = function _sum(x){ //函数表达式不省略名字,也只能在函数内部使用 if (x==1) // if后不能加分号 return 1; return x+_sum(x-1); } // console.log(sum(5)) const counter = function (){ let c = 0 return function (){ return ++c } } c = counter() arr = new Array(1,2,3,4,5) var map = function map(arr,fn){ let newarry = [] for (i in arr) newarry[i] = fn(arr[i]) return newarry } // console.log(map(arr,function(x) {return ++x}))//匿名函数 // console.log(map(arr,x=>++x)) //箭头函数,就是匿名函数,更加简洁 var map = function * (arr,fn){ for(i in arr) yield fn(arr[i]) } let newarr = map(arr,x=>++x) /* 箭头函数:如果一个函数没有参数使用(); 如果只有一个参数,可以省略小括号 多个参数不能省略小括号,且使用逗号间隔 箭头函数返回值:如果函数体部分有多行,就需要使用{},如果有返回值使用return 如果只有一行语句,可以同时省略大括号和return,有return必有{} */ const sum = function (...args){ //[1,2,3] let result = 0 console.log(arguments) //所有的参数,包括位置参数 for (let x in args){ //[[1,2,3]] // console.log(args[x],'~~~~~~~~~`') result += args[x] } return result } // console.log(sum(...[1,2,3,4,5])) // console.log(100+[1,2,3,4]) //1001,2,3,4 const rvalue = (x,y) => {return x,y} console.log(rvalue(5,6)) /* 表达式的值 赋值表达式的值:等号右边的值 逗号表达式的值:最后一个表达式的值 */
1.1es6之前的类定义
定义一个函数(构造器对象)函数首字母大写 使用this定义属性 使用new和构造器创建一个对象 本质还是一个function //[Function: Point]
function Point(x,y){ //Es6之前 this.x = x this.y = y this.show = ()=>console.log(this.x,this.y) } console.log(Point) p1 = new Point(3,4) console.log(p1) function Point3d(x,y,z){ Point.call(this,x,y) //继承 this.z = z console.log('this is Poind3d') } p2 = new Point3d(1,2,3) console.log(p2) p2.show()
注意:如果不使用new关键字,就是一次普通的函数调用,this不代表实例
1.2 es6中class的定义
1.从es6开始,新提供了class关键字,是的创建对象更加简单,清晰 2.类定义使用class关键字,创建的本质还是函数,是一个特殊的哈数 3.一个类只能拥有一个constructor的构造器方法,如果没有显示的定义一个构造方法,则会添加一个默认的构造方法 4.继承使用extends关键字 5.一个构造器可以使用super关键字来调用一个父类的构造函数 6.类没有私有属性
1.2.1 类的继承从父类全部继承
class Poing{ constructor(x,y){ this.x = x this.y = y } show() { console.log(this) //实例p1 console.log(this,this.x,this.y) } } p1 = new Poing(4,5) console.log(p1) class Poing3d extends Poing{ //继承 constructor(x,y,z){ super(x,y) this.z = z } } p2 = new Poing3d(7,8,9) console.log(p2) p2.show()
1.2.2 es6静态属性
class Poing{ constructor(x,y){ this.x = x this.y = y } show() { console.log(this) //实例p1 console.log(this,this.x,this.y) } } p1 = new Poing(4,5) console.log(p1) class Poing3d extends Poing{ //继承 constructor(x,y,z){ super(x,y) this.z = z } static set(){ console.log('set') } } p2 = new Poing3d(7,8,9) console.log(p2) Poing3d.set() p2.constructor.set() //实例只能通过这种方式访问静态属性
2.1 this出现的问题整理与总结
c++。java是静态编译型语言,this是编译期间绑定,js是动态语言,运行期绑定 var school = { name:'python', getNameFunc:function(){ console.log(this.name) console.log(this) return function (){ console.log(this === global) return this.name } } } 函数执行期间会开启新的上下文环境executioncontext,创建this属性,但是this是什么就要看函数怎么调用 1.myfunction(1,2,3)普通函数的调用方式,this指向全局对象,全局对象是nodejs的global或者浏览器的windows 2.myobject.myfunction(1,2,3)对象的调用方式,this指向包含该方法的对象 3.call和apply方法调用,需要看第一个参数是谁
2.1.1 this的显示传入
var school = { name:'python', getNameFunc:function(){ console.log(this.name) console.log(this) return function (that){ //普通函数这块传入一个参数 console.log(that === global) return that.name } } } console.log(school.getNameFunc()(school))
es3
apply.call方法都是函数对象的方法,第一个参数都是传入对象引入的 apply传入其他参数需要使用数组 call传入其他参数需要使用可变参数收集
var school = { name:'python', getNameFunc:function(){ console.log(this.name) console.log(this) return function (){ //普通函数这块传入一个参数 console.log(this === global) return this.name } } } console.log(school.getNameFunc().apply(school)) console.log(school.getNameFunc().call(school))
2.1.2 bind es5,最常用的方式解决this问题
var school = { name:'python', getNameFunc:function(x,y){ console.log(1,this) console.log(2,this.x,this.y) return function(){ console.log(3,this === global) return this.name } } } // console.log(school.getNameFunc().bind(school)) //错误用法 var func = school.getNameFunc() //等同于上条调用 var boundfunc = func.bind(school) //bind返回i虚拟的函数,先为函数绑定this,调用时直接用 console.log(boundfunc())
2.1.3 箭头函数解决this问题 es6新技术,不需要兼容this问题
var school = { name:'python', getNameFunc:function(x,y){ console.log(1,this) console.log(2,this.x,this.y) return ()=>{ console.log(3,this === global) return this.name } } } // console.log(school.getNameFunc().bind(school)) //错误用法 var func = school.getNameFunc() //等同于上条调用 var boundfunc = func.bind(school) //bind返回i虚拟的函数,先为函数绑定this,调用时直接用 console.log(boundfunc())
3.1高阶对象MIXIN模式
/* 四种类的定义以及转换 */ class A{} const B = class { constructor(x){ console.log(x) } } const C = class extends B{} const D = Sup => class extends Sup{}//用一个函数来返回类的定义 cls = D(B) //返回类定义 d = new cls(300)
代码改造前后
class Serialization { constructor(){ console.log('serialization constructor') if (typeof this.stringify!=='function'){ throw new ReferenceError('show define stringify') } } } class Point extends Serialization{ constructor(x,y){ console.log('Point constructor') super() this.x = x this.y = y } stringify(){ console.log(`Point <${this.x}:${this.y}>`) } } class Point3D extends Point { constructor(x,y,z){ super(x,y) this.z = z } } p = new Point(2,3) pd = new Point3D(5,6) console.log('~~~~~~~~~~~~~~~~~~~~') p.stringify() pd.stringify()
改造后
var serialization = Sup =>class extends Sup { constructor(...args){ console.log('serialization constructor') super(...args) if (typeof this.stringify!=='function'){ throw new ReferenceError('show define stringify') } } } class Point { constructor(x,y){ console.log('Point constructor') this.x = x this.y = y } stringify(){ console.log(`Point <${this.x}:${this.y}>`) } } class Point3D extends serialization(Point) { constructor(x,y,z){ super(x,y) this.z = z } } pd = new Point3D(5,6,6) console.log(pd)
js foreach
var metadata ={ title:'python', translations:[ { locale:'de', url:{} } ] } console.log(Object.keys(metadata)) console.log(Object.values(metadata)) console.log(Object.entries(metadata)) var copy = Object.assign({},metadata,{school:"mage"},{url:null}) console.log(copy) const arr = [1,2,3,4,5] newarr = [] arr.forEach( function(x){ newarr.push(x) } ) console.log(newarr)
export default
使用export default时,对应的import语句不需要使用大括号;不使用export default时,对应的import语句需要使用大括号。
export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。import命令后面才不用加大括号,因为只可能对应一个方法。
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字