1. js原始类型
js有5种原始数据类型:即 Undefined、Null、Boolean、Number 和 String。
2. js对象分类
js对象可以分为3类:本地对象、内置对象、宿主对象。
本地对象:ECMA-262 把本地对象定义为“独立于宿主环境的,由ECMAScript 提供的对象”。
再来看一下,“本地对象”包含哪些内容:
Object
Function
Array
String
Boolean
Number
Date
RegExp
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
本地对象就是 ECMA-262 定义的类(引用类型)。
内置对象:ECMA-262 把内置对象定义为“独立于宿主环境的,由ECMAScript 提供的对象,在 ECMAScript 程序开始执行时出现”。
这意味着开发者不必明确实例化内置对象,它已被实例化了。直接使用就行了。
ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。
Global对象的属性列表:
Global对象的方法:
例如isNum(),isFinite(),parseInt(),parseFloat()等,都是Global对象的方法。
encodeURI():对传递给浏览器的URI进行编码。对应的解码函数:decodeURI()。
encodeURIComponent():对传递给浏览器的URI进行编码。对应的解码函数:decodeURIComponent()。
这两个方法的主要区别是:
encodeURI()不对URI中的特殊字符编码,例如冒号、斜杠、问号和英镑符号;
encodeURIComponent()会对它发现的所有非标准字符进行编码。而对应有decodeURI()和decodeURIComponent()解码函数。
这些URI方法代替了BOM中的escape()和()方法。URI方法更可取,因为它们会对所有的Unicode符号编码,而BOM方法只能对ASCII符号正确编码。应尽量避免使用escape()方法。
Math对象常用方法:
min()、max()
abs()方法返回数字的绝对值。
ceil()表示向上舍入
floor()表示向下舍入
round()标准的四舍五入
宿主对象:由 ECMAScript 实现的宿主环境提供的对象。所有 BOM 和 DOM 对象都是宿主对象。
BOM对象:window、location、screen、history、navigator。
DOM对象:document、form、button等。
开发人员可以自定义对象。
3.封装JS对象
JavaScript里一切皆对象。所以函数也是对象,是Function的实例。函数名可以理解为指向该实例的引用。
JS里封装对象的常用方式有5种:
显示自定义、工厂方法、构造函数方式、原型方式、构造函数+原型方式;
显式自定义对象
var obj1 = {
nick: 'Byron',
age: 20,
printName: function(){
console.log(obj1.nick);
}
}
var obj2 = {
nick: 'Casper',
age: 25,
printName: function(){
console.log(obj2.nick);
}
}
适用场合:
临时对象。比如作为方法的参数传递时,可以这样封装对象。
全局常量对象。很少做修改情况下适合这样封装对象。比如定义一个AjxxConst对象,该对象的属性是一些常量值,比如案件状态–已公开=3.
缺点:
不能很好的复用;
多个客户端并发访问时,数据容易被修改;
工厂方法封装对象
function createObj(name, age){
var person = new object();
person.name = name;
person.age = age;
person.printName = function(){
console.log(this.nick);
}
return person ;
}
客户端:
var p1 = createObj('权志龙', 30);
p1.printName ();
适用场合:
创建操作比较频繁,即经常创建同一类的实例时,可以使用工厂方法。
可以理解为工厂方法是对“创建object对象”这一操作的封装。
缺点:
构造出来的对象类型都是Object,没有识别度;
创建多个实例的同时,还要创建重复的行为printName;
构造函数方式封装对象
<script>
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
console.log(this.age);
}
}
function test(){
var p1 = new Person();
var p2 = new Person('权志龙');
var p3 = new Person('权志龙',30);
p1.sayName();//undefined,undefined
p2.sayName();//权志龙,undefined
p3.sayName();//权志龙,30
}
</script>
JS里万物皆对象,方法也是对象。因此可以通过声明一个方法来指定对象类型。
适用场合:
没有固定的场景,自己根据实际情况来决定是否使用吧。
构造方法封装对象,是不是有点儿类似java了呀,还有比这更类似的呢!
缺点:
创建多个实例的同时,还要创建重复的行为printName;
原型方式封装对象
function Person(){
}
Person.prototype.name = "权志龙";
Person.prototype.age = 30;
Person.prototype.printName = function(){
console.log(this.name);
}
Person.prototype.printAge = function(){
console.log(this.age);
}
客户端:
var p1 = new Person();
p1.printName();
p1.printAge();
适用场合:
实例们的属性值固定不变时,适合这样封装对象。
缺点:
参数值绑定的太死了,是不是,是不是,是不是!
构造函数+原型方式封装对象
function MyObject(otherObject){
alert("有参构造函数!");
this.otherObject = otherObject;
}
MyObject.prototype.name = "y0";
MyObject.prototype.age = "0";
MyObject.prototype.getName = function getName(){
console.log(this.name);
};
MyObject.prototype.getAge = function getAge(){
console.log(this.age);
};
MyObject.prototype.setName = function setName(name){
this.name = name;
};
MyObject.prototype.setAge = function setAge(age){
this.age = age;
};
MyObject.prototype.getOtherObject = function getOtherObject(){
console.log(this.otherObject);
};
MyObject.prototype.setOtherObject = function setOtherObject(otherObject){
this.otherObject = otherObject;
};
客户端:
var myObject1 = new MyObject();
myObject1.getName();//y0
myObject1.getAge();//0
myObject1.setName("yulq");
myObject1.setAge(18);
myObject1.getName();//yulq
myObject1.getAge();//18
myObject1.getOtherObject();//undefined
var myObject2 = new MyObject(11);
myObject2.getName();//y0
myObject2.getAge();//0
myObject2.setName("yulq2");
myObject2.setAge(20);
myObject2.getName();//yulq2
myObject2.getAge();//20
myObject2.getOtherObject();//11
适用场合:
完美。
缺点:
缺点就是太完美了!
4.定义JS变量
JS变量可以分为三种:私有变量、实例变量、静态变量。
<script>
function ClassA(){
var a = 1; //私有变量,只有函数内部可以访问
this.b = 2; //实例变量,只有实例可以访问
}
ClassA.c = 3; // 静态变量,也就是属性,类型访问
ClassA.prototype.d = 4;//实例变量,只有实例可以访问
function test(){
console.log(a); // error
console.log(ClassA.b) // undefined
console.log(ClassA.c) //3
console.log(ClassA.d) //undefined
var classa = new ClassA();
console.log(classa.a);//undefined
console.log(classa.b);// 2
console.log(classa.c);//undefined
console.log(classa.d);//4
}
</script>
5.JS实现继承
JavaScript并不提供原生的继承机制,我们自己实现的方式很多,介绍一种最为通用的。
我们如果实现了两点的话就可以说我们实现了继承:
得到一个类的属性;
得到一个类的方法;
获得父类属性
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function (){
console.log(this.name);
}
---------------------------
function SubPerson(name,age,like){
Person.call(this,name,age);
this.like = '唱歌';
}
----------------------------
function test(){
var p1 = new SubPerson('权志龙',30,'唱歌');
console.log(p1.name);//权志龙
}
获得父类属性的原理是:
在子类构造函数里,通过Function.prototype.call(obj,param1,param2…)方法装配子类对象。
call()方法,将某个对象构造方法里的this换成第一个参数指定的对象;
因此,通过调用父类的call给子类装配父类属性,实现了继承属性。
获得父类方法
我们知道类的方法都定义在了prototype里面,所以只要我们把子类的prototype改为父类的prototype的备份就好了。
SubPerson.prototype = Object.create(Person.prototype);
我们通过Object.create()方法clone了一个新的prototype而不是直接把Person.prtotype直接赋值。因为引用关系,这样会导致后续修改子类的prototype也修改了父类的prototype,因为修改的是一个值。
这样做需要注意一点就是对子类添加方法,必须在修改其prototype之后,如果在之前会被覆盖掉。
还有个问题,我们知道prototype对象有一个属性constructor指向其类型,因为我们复制的父元素的prototype,这时候constructor属性指向是不对的,导致我们判断类型出错:
SubPerson.prototype.constructor; //Person
因此我们需要再重新指定一下constructor属性到自己的类型:
var _prototype = Object.create(Person.prototype);
_prototype.constructor = SubPerson;
SubPerson.prototype = _prototype;
最终示例如下:
<script>
--------------------封装父类对象-----------------------
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function (){
console.log(this.name);
}
--------------------封装子类对象-----------------------
function SubPerson(name,age,like){
Person.call(this,name,age);
this.like = like;
}
var _prototype = Object.create(Person.prototype);
_prototype.constructor = SubPerson;
SubPerson.prototype = _prototype;
SubPerson.prototype.sayLike = function (){
console.log(this.like);
}
--------------------客户端-----------------------
function test(){
var p1 = new SubPerson('权志龙',30,'唱歌');
console.log(typeof SubPerson);
console.log(p1 instanceof SubPerson);
p1.sayName();
p1.sayLike();
}
</script>
实现要点:
1,在子类的构造方法里,通过Father.call(this,param1,param2……..)获得父类属性;
2,在扩展子类方法之前,通过Object.create(Father.prototype)克隆一个父类原型,将该原型的constructor 指向SubPerson,最后将子类原型指向克隆出来的父类原型,从而子类获得了父类方法。