对象:
实质上的事物、可以是任何的东西 包含属性和方法
类
把部分对象的的共同特征的抽象
封装
封装的内容一般有:1、相关的数据 2、基于这些数据的方法
封装的结果就是暴露给其他对象一个操作这些数据的方法
聚合
将一个复杂的对象分解为多个简单的对象
继承
优雅的实现代码的重用,但是js中没有具体的类,所以有继承关系的只能是对象之间
多态
worker继承了person的全部的方法,这就意味这在这个类中实现了不同的talk()方法,当各自类生成的对象调用这个talk方法的时候,会实现各自的功能,这个现象就是多态。
数字、字符串、布尔值、undefined、null
undefined和null的区别
js试图访问某个不存在的或者是没有经过赋值的变量,就会得到一个undefined
1+undefined undefined
1+null 1
什么是函数:代码的一种分组形式。
参数:传递给函数多余的参数,函数会自动省略掉没有用的参数,可以利用函数的滋生的属性arguments这个数组来访问参数
预定义函数
js中已经预定了一些函数,parseInt()、parseFloat()、idNaN()。。。。。
isNaN() 判断一个值是否是可以参与运算的数字
encodeURI
eval()
变量作用域
js中不能为变量定义特定的块级作用域,但是可以为其定制特定的函数域
如果变量是定义在某个函数中,在函数之外这个变量是不可见的
如水果是定义在if或者for语句中,这个变量在外界是可见的
匿名函数
匿名函数的作用:
1、可以将匿名函数作为参数传递给其他的函数,接收方就能利用我们所传递的函数来完成某些事情
2、定义某个匿名函数来完成某些一次性的事情
回调函数
将函数作为参数传递给另一个函数,可以理解为一个函数调用操作交给了另一个函数
自调函数
在一个函数后边加一个()就会自己调用一边
内部函数
想要函数A里边有一个函数B当调用函数A的时候B也会被调用,必须在函数A定义的时候B能够被调用。
函数和函数对象的区别
var aa=new function (){this.a="fun"}; var cc=function (){this.a="ccFun"}; console.log(typeof cc); console.log(typeof aa);
aa是一个函数 cc是一个函数对象 call方法切换的对象的上下文。
call方法和apply方法
call方法(obj,arg1,arg2)
这个方法可以代替另一对象obj调用一个方法。 将一个函数的对象上下文从初始的上下文改变为this.obj的上下文,
var aa=new function (){this.a="fun"}; function bb(x) { var a="myfun"; console.log(this.a); console.log(x); } bb.call(aa,3); //fun 3
调用bb的时候函数的上下文被切换到aa中,所以a被赋值为fun
apply方法(obj,[arguments])和call的功能一样但是传递的参数是不一样的
var aa={ a:"12121" }; function bb(x) { var a="myfun"; console.log(this.a); console.log(x); } bb.apply(aa,[3]); //12121 3
调用call和apply以后将obj的所有的属性和方法都给了调用的这个
var base={ member:'qq', xx:function(){ console.log(111); } } function extend() { console.log(this.member); console.log(this.xx); } extend.call(base);
上面的程序和下面的程序的运行效果一致
function base() { this.member='qq'; this.xx=function(){ console.log(111); } } function extend() { base.call(this); //extend会继承base所有的属性和方法 console.log(this.member); console.log(this.xx); } extend();
通过闭包可以突破js的函数作用域链:函数内部定义一个函数返回一个函数内部的变量 外部就可以访问这个变量
var n; var aa=function (){ var b="cc"; n=function() { return b; } } aa(); /aa必须先执行一遍 console.log(n()); //将b升级成了全局的变量,突破了js的作用域链
一个函数需要在其父级函数之后留住对父级作用域链的话,此时就是用闭包。。
循环中的闭包
var aa=function (){ var a=[]; var i; for(i=0;i<3;i++){ a[i]=function () { return i; } } return a; } var xx=aa(); console.log(xx[0]()); console.log(xx[1]()); console.log(xx[2]());
没有输出对应的1 2 3
下面的这个程序是正确的
var aa=function (){ var a=[]; var i; for(i=0;i<3;i++){ a[i]=(function (x) { return function(){ return x; }; })(i) } return a; } var xx=aa(); console.log(xx[0]()); console.log(xx[1]()); console.log(xx[2]());
会输出 0, 1 ,2
定义一个将变量本地化的函数MakeLocal()
function makeLocal(x){ return function (){ return x; } } var aa=function (){ var a=[]; var i; for(i=0;i<3;i++){ a[i]=makeLocal(i) } return a; } var xx=aa(); console.log(xx[0]()); console.log(xx[1]()); console.log(xx[2]());
依然会输出0,1,2
设置secret变量的set和get的操作,这样secret变量就不可被直接访问
var getValue,setValue; (function(){ var secret=0; getValue=function (){ return secret; }; setValue=function (v){ secret=v; } })(); setValue(3); console.log(getValue()); //3
练习:
1、编写一个将16进制的字符串转换为颜色 将0000FF转换为0,0,255
function ge(value1,value2){ var result=Math.pow(16,0)*value1+Math.pow(16,1)*value2; return result; } function getRGB(jinzhi){ var zu=[]; for(var i=0;i对象
构造函数,通过constructor能够得到构造器属性
function A(name){ this.name=name; } var aa=new A('juan'); console.log(aa.constructor) //得到function A这个函数instanceof操作符
判断某个对象是不是某个类的实例function A(name){ this.name=name; } var aa=new A('juan'); console.log(aa instanceof A);传递对象
当我们拷贝某个对象或者将它传递给一个函数的时候,其实就是传递这个对象的引用,对这个对象的操作都会实质性的改变这个对象。
对象之间的比较
当我们对对象进行比较的时候,当且仅当两个引用指向同一个对象时为true;var A={name:1}; var B={name:1}; console.log(A==B) //false两个对象的引用不同,所以输出为false
内置对象
数据封装类对象 Object Array Boolean Number String
工具类对象 Math Date RegExp
错误类对象
Object
所有对象的父级对象
属性 constructor 返回构造属性 所有的构造属性都是只读的,不能被改变
方法 1、tostring() 2、valueOf()var A=[1,3,4] console.log(A.valueOf()) //[1, 3, 4] console.log(A.toString()) //1,3,4Array
属性 length
方法 sort ,reverse,join,slice,push,splice
Function()
属性
length 参数的个数
caller 会返回一个调用该函数对象的外层函数的引用function A(){ console.log(A.caller) ; } function B(){ return A(); } B(); //function B()在B中执行A的结果就是返回A的caller(也就是B)
原型
每一个对象都有自己的原型
function A(){ console.log(1); } console.log(A.prototype) //object通过函数的prototype属性来为函数添加属性和方法
function A(name){ this.name=name; this.say=function () { console.log(this.name); } } var aa=new A('juanjuan'); aa.say(); A.prototype.www=function () { console.log(111) } var bb=new A('juanjuan'); bb.www();但是只限于添加,并不能改变原来的function中的方法,想要改变原来的对象的方法,可以先将原来对象的方法删除。再在原型上添加方法,这样就实现了改变原来对象方法的功能
var yuan=function (){ this.say=function (x) { console.log(x); } } yuan.prototype.say=function (x) { console.log(x+2) } var yuan1=new yuan(); yuan1.say(2); yuan.prototype.say1=function (x) { console.log(x+2) } yuan1.say1(2);而且原型可以随时被修改,并且与之相关的对象都会随之改变。
原型只能向对象添加方法,但是不能改变原来的方法。这是因为如果遇上对的自身属性与原型属性同名的时候 自身属性的优先级高于原型属性 如果删除了自身的同名属性,原型上的这个同名属性就会出现var yuan=function (){ this.say=function (x) { console.log(x); } } var yuan1=new yuan(); delete yuan1.say; yuan.prototype.say=function (x) { console.log(x+2) } yuan1.say(2);自身属性和原型属性
通过hasOwnProperty来判断var yuan=function (name,age){ this.name=name; this.age=age; } yuan.prototype={ price:100, rating:3 } var yuan1=new yuan("赵文娟",12); for(var cc in yuan1){ console.log(cc+yuan1[cc]); //谁输出自身和原型的所有的属性 } console.log(yuan1.hasOwnProperty("name")); //true 自身有着个属性 console.log(yuan1.hasOwnProperty("price")); //false 自身没有这个属性当前对象是否是另一个对象的原型
isPrototypeOf()函数var monkey=function (name,age){ this.name=name; this.age=age; } var human=function(){} human.prototype=monkey; var hh=new human(); console.log(monkey.isPrototypeOf(hh)); //monkey是人类这个对象的原型神秘的proto连接
我们知道当访问一个在当前对象中不存在属性的时候,原型就会被纳入查找的范围。这个属性就可以指向它的原型,var monkey=function (){ this.feeds='香蕉'; this.breaths='空气'; } var human=function(){} var mon=new monkey(); human.prototype=mon; var hh=new human(); hh.name="juanjuan"; console.log(hh.feeds); //香蕉 console.log(mon.isPrototypeOf(hh)); //true console.log(hh.__proto__); //monkey {feeds: "香蕉", breaths: "空气"} console.log(hh.prototype); //undefined继承
js中每一个函数都有一个名为prototype的对象的属性 new的时候会创建出一个一个对象,并且通过proto指针来连接原型,这样就形成了原型链
通过原型链实现js 中的继承function shape(){ this.name='shape'; this.toString=function (){ return this.name; } } function TwoDshape(){ this.name='2Dshape' } function Trigle(side,height){ this.name='Trigle'; this.side=side; this.height=height; this.getArea=function(){ return this.side*this.height/2; } } //对对象的prototype属性重写 TwoDshape.prototype=new shape(); Trigle.prototype=new TwoDshape(); //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以 TwoDshape.prototype.constructor=TwoDshape; Trigle.prototype.constructor=Trigle; var tt=new Trigle(3,4); console.log(tt.toString()); //Trigle console.log(tt.getArea()) //6演示继承的效果 一定要注意的是对prototype完全覆盖以后,会对constructor有影响,所以需要
TwoDshape.prototype.constructor=TwoDshape; Trigle.prototype.constructor=Trigle;以上的实验结果的分析:
遍历tt对象中的所有属性。没有找到一个叫做toString 的方法。就查看proto所连接的实体,也就是回去TwoDshape的new出来的实体中去找,也没有找到,就会去shape的new的实体找toString这个方法 。同时我们也在原型覆盖之后重新定义了constructor这个属性,所以TwoDshape和Trigle都是本身console.log(tt instanceof shape); //true console.log(tt instanceof TwoDshape); //true console.log(shape.prototype.isPrototypeOf(tt)) //true将需要共享的属性都迁移到原型中
当使用构造创建的属性,每一次的new都会在实体中的多一个这样的属性。所以将共享的属性和方法迁移到原型中是有必要的。function shape(){} shape.prototype={ name:'shape', toString:function (){ return this.name; } } function TwoDshape(){ } TwoDshape.prototype=new shape(); TwoDshape.prototype.constructor=TwoDshape; function Trigle(side,height){ this.side=side; //因为这个属性是每一个实体独有的属性 this.height=height; //因为这个属性是每一个实体独有的属性 } //对对象的prototype属性重写 Trigle.prototype=new TwoDshape(); //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以 Trigle.prototype.constructor=Trigle; Trigle.prototype.getArea=function(){ return this.side*this.height/2 } var tt=new Trigle(3,4); console.log(tt.toString()); //Trigle console.log(tt.getArea()) //6 console.log(tt instanceof shape); //true console.log(tt instanceof TwoDshape); //true console.log(tt.hasOwnProperty('name')) //false console.log(tt.hasOwnProperty('height')) //true值得注意的是扩展原型对象之前,一定要完成继承关系的构建
只继承原型
尽可能的将重用的属性和方法添加到原型中,这样就通过原型链就实现了继承,不再需要shape的实体来实现继承关系。function shape(){} shape.prototype={ name:'shape', toString:function (){ return this.name; } } function TwoDshape(){ } TwoDshape.prototype=shape.prototype; TwoDshape.prototype.constructor=TwoDshape; function Trigle(side,height){ this.side=side; //因为这个属性是每一个实体独有的属性 this.height=height; //因为这个属性是每一个实体独有的属性 } //对对象的prototype属性重写 Trigle.prototype=TwoDshape.prototype; //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以 Trigle.prototype.constructor=Trigle; Trigle.prototype.getArea=function(){ return this.side*this.height/2 } var tt=new Trigle(3,4); console.log(tt.toString()); //Trigle console.log(tt.getArea()) //6 console.log(tt instanceof shape); //true console.log(tt instanceof TwoDshape); //true console.log(tt.hasOwnProperty('name')) //false console.log(tt.hasOwnProperty('height')) //true测试的结果和上面的一致,但是js在找toString的时候,直接找的是原型
子对象访问父对象
js中本身没有这样的属性,但是可以通过子类调用父类的同名方法来实现function shape(){} shape.prototype={ name:'shape', toString:function (){ var result=[]; if(this.constructor.urber){ result[result.length]=this.constructor.urber.toString(); } result[result.length]=this.name; return result.join(',')+"11"; } } function TwoDshape(){ } function F(){}; F.prototype=shape.prototype; TwoDshape.prototype=new F(); TwoDshape.prototype.constructor=TwoDshape; TwoDshape.urber=shape.prototype; TwoDshape.prototype.name='2D图形'; function Trigle(side,height){ this.side=side; //因为这个属性是每一个实体独有的属性 this.height=height; //因为这个属性是每一个实体独有的属性 } //对对象的prototype属性重写 var F=function(){}; F.prototype=TwoDshape.prototype; Trigle.prototype=new F(); //对对象的prototype属性重写时,可能会对对象的constructor属性产生一个负面的影响所以 Trigle.prototype.constructor=Trigle; Trigle.urber=TwoDshape.prototype; Trigle.prototype.getArea=function(){ return this.side*this.height/2 } Trigle.prototype.name="三角形"; var tt=new Trigle(3,4); console.log(tt.toString()); //shape11,2D图形11,三角形11改进了toString 用urber属性指向了父类的原型
将继承的部分封装function extend(child,parent) { var F=function () {}; F.prototype=parent.prototype; child.prototype=new F(); child.prototype.constructor=child; child.uber=parent.prototype; //实现子类继承父类的属性 } function shape(){} shape.prototype={ name:'shape', toString:function (){ var result=[]; if(this.constructor.uber){ result[result.length]=this.constructor.uber.toString(); } result[result.length]=this.name; return result.join(',')+"11"; } } function TwoDshape(){} extend(TwoDshape,shape); TwoDshape.prototype.name='2D图形'; function Trigle(side,height){ this.side=side; //因为这个属性是每一个实体独有的属性 this.height=height; //因为这个属性是每一个实体独有的属性 } extend(Trigle,TwoDshape); Trigle.prototype.getArea=function(){ return this.side*this.height/2 } Trigle.prototype.name="三角形"; var tt=new Trigle(3,4); console.log(tt.toString()); //shape11,2D图形11,三角形11对象之间的继承 浅拷贝
js中没有类 丢掉构造函数来实现继承 就是多个属性的拷贝
使用多个属性的拷贝实现了类之间的继承,中间没有使用函数,js就实现了类之间的继承function extendCopy(p) { var c={}; for(var i in p){ c[i]=p[i]; } c.uber=p; return c; } var shape={ name:'图形', toString:function (){ return this.name; } } var twoDee=extendCopy(shape); twoDee.name='2D图形'; twoDee.toString=function(){ return this.uber.toString()+this.name; } var trigle=extendCopy(twoDee); trigle.name="三角形"; trigle.toString=function(){ return this.uber.toString()+this.name; } trigle.side=3; trigle.height=4; trigle.getArea=function(){ return this.height*this.side/2 } console.log(trigle.toString()); //图形2D图形三角形 console.log(trigle.getArea()); //6深拷贝
之前的extendCopy实现 的是浅拷贝,要想实现深拷贝实际上遇到一个对象引用性的属性的时候,我们需要再次调用深拷贝函数
实现深拷贝function deepCopy(p,c) { var c=c||{}; for(var i in p){ if(typeof p[i]=="object"){ c[i]=(typeof p[i===Array])?[]:{}; deepCopy(p[i],c[i]) //实际上是一个递归实现的深拷贝 } else{ c[i]=p[i]; } } return c; }比较深拷贝和浅拷贝
function deepCopy(p,c) { var c=c||{}; for(var i in p){ if(typeof p[i]=="object"){ c[i]=(typeof p[i===Array])?[]:{}; deepCopy(p[i],c[i]) //实际上是一个递归实现的深拷贝 } else{ c[i]=p[i]; } } return c; } function extendCopy(p) { var c={}; for(var i in p){ c[i]=p[i]; } c.uber=p; return c; } var p={ numbers:[1,2,3], letters:['a','b','c'], obj:{ name:'zhaowenjuan' }, boolean:true } var test=deepCopy(p); test.numbers.push(3,4); console.log(test.numbers); //1,2,3,4 console.log(p.numbers); //1,2,3 发生的是深拷贝 备份与原来相互独立 var test2=extendCopy(p); test2.numbers.push(3,4); console.log(test2.numbers); //1,2,3,4 console.log(p.numbers); //1,2,3,4 发生的是浅拷贝 备份与原来是一个