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,最後將子類原型指向克隆出來的父類原型,從而子類獲得了父類方法。