js

建立函數,3種:
1 聲明:只有聲明方式建立的函數才能被聲明提早
function fun(arg1, arg2, ...){ statement; return value;}
2 函數直接量:沒法被聲明提早
var fun = function(arg1, arg2, ...){ statement; return value;};
揭示:函數實際上是一個對象,函數名僅僅是一個引用函數對象的普通變量。
3 用new:
var fun = new Function("arg1", "arg2", ..., "statement; return value;");javascript

重載(overload):相同函數名,不一樣參數列表的多個函數,在調用時,根據傳入參數的不一樣,自動選擇匹配的函數執行
目的目的:減小API的數量,減輕調用者的負擔java

when:若是多個函數只是流程不一樣,其實都是一類事,就能夠將多個函數命名爲同名函數,不一樣參數
how:js語法不支持重載!js中後定義的同名函數會覆蓋先定義的。
arguments:函數中自動接收全部傳入函數的參數值的類數組對象。
類數組對象:長得像數組的對象
類數組對象和數組的相同點:都用[i]方式訪問每一個元素;length屬性記錄元素的個數;for循環遍歷每一個元素。數組

對象的建立,3種:
1 對象直接量:
var obj = {
屬性名: 屬性值;
...,
方法名: function(){},
...
};
注意:每一個屬性名和方法名不用加引號,可是底層都是用字符串存儲。瀏覽器

this:引用當前正在調用函數的對象!app

  和定義在哪一個對象中無關!只和調用時   .  前的對象有關!ide

  固定場景:a.在對象本身的方法中,訪問本身的屬性函數

       b.在構造函數中,指代正在建立的新對象性能

       c.在原型對象的共有方法中,指代未來調用共有方法的子對象this

  注意:不是任何對象直接調用的函數中this默認指window對象。
when:對象本身的方法中,想訪問對象本身的屬性必須用 this.屬性名
2 使用new:
var obj = new Object();//建立一個Object類型的空對象
obj.屬性名 = 屬性值;//等效於 obj["屬性名"] = 屬性值;
...
obj.方法名 = function(){... this.屬性名 ...};
when:若是在建立對象時,暫時不知道包含哪些屬性,就先建立一個對象,再添加屬性spa

注意:js中的對象,能夠隨時添加新屬性,只要給不存在的屬性賦值,就自動添加

本質:js中一切對象都是hash數組:

  a.均可以隨時添加新的屬性和方法

  b.訪問對象中一個不存在的屬性,返回undefined

  c.屬性名和方法名其實至關於hash數組中的key

  d.均可用for in遍歷每一個屬性
3 反覆建立多個相同類型和結構的對象;
a.定義構造函數,描述一類對象的統一結構
構造函數:描述一類對象的統一結構德函數
when:只要反覆建立相同結構的多個對象前,都須要先定義構造函數,再建立對象。
how:
function 類型名/構造函數名(屬性參數列表){
this.屬性名 = 屬性參數值;
...
this.方法名 = function(){
... this.屬性名...
}
}
b.使用new調用構造函數建立對象並添加屬性
var obj = new 構造函數名(屬性值列表);
構造函數中的this,指new正在建立的對象

面向對象:
原型和原型鏈:
原型:保存全部子對象的公共成員的父級對象

每一個構造函數,都有一個prototype屬性,引用本身的原型對象
每一個子對象,都有一個 __proto__ 屬性,繼承自構造函數的原型對象

繼承:父對象的成員,自對象無需建立,可直接使用!

對象建立:
a.建立空對象
b.設置新對象的 __proto__ 屬性繼承構造函數的原型對象
c.調用構造函數,添加成員
d.返回地址
when:同一類型的子對象共享的屬性和方法,都要放在構造函數的原型對象中。
優勢:代碼重用,節約內存!

刪除屬性:
a.自有屬性: delete 對象.屬性名;
b.共有屬性:只能經過構造函數的原型對象刪除 delete 構造函數.prototype.屬性名

判斷自有屬性與共有屬性:
a.判斷自有屬性:判斷指定屬性是否直接保存在當前對象本地
var isSelf = obj.hasOwnProperty("屬性名");
true:是自有屬性
false:沒法肯定是否爲共有
b.判斷共有屬性:同時知足兩條件:
不是自有: obj.hasOwnProperty("屬性名") == false;
可是在原型中有: obj.屬性名 !== undefined

<script type="text/javascript">
    
//String類型支持trim(),去掉先後的空格
//若是當前瀏覽器不支持trim
if(String.prototype.trim === undefined){
    console.log("當前瀏覽器不支持trim(),自定義trim()");
    String.prototype.trim = function(){
        return this.replace(/^\s+|\s+$/g, "");
    };
}

var str = "    hello js,  I like  ";
console.log(":" + str + ":");
str = str.trim();
console.log(":" + str + ":");

</script>

總結:不使用 obj. 方式訪問對象,都去做用域鏈找,只要使用 obj. 訪問成員,都去原型鏈找。

原型相關API:

1. 獲取原型對象,2種:

  a. 構造函數.prototype

  b. 子對象.__proto__  :內部屬性,可能被禁用

    儘可能使用Object.getPrototypeOf(子對象);

2. 判斷對象間是否有繼承關係:

  var hasInherit = 父對象.isPrototypeOf(子對象); 

3. instanceof:判斷一個對象是不是指定構造函數的實例

  function Student(){};

  var jack = new Student();

  jack instanceof Student -> true

 

多態:同一事物,在不一樣狀況下表現出不一樣樣子

  重寫:override:若是子對象以爲父對象的成員很差用,可在本地定義同名成員,覆蓋父對象的。

在原型對象中

  如何添加共有屬性:只能經過原型對象

    構造函數.prototype.屬性名 = 值;

  原型鏈:由各級對象的 __proto__ 逐級繼承造成的鏈式關係

  規則:在訪問對象屬性時,只要本身有,就不去父級找,若是本身沒有,纔去父級找,若是到Object.prototype都沒找到,就返回undefined。

  和做用域鏈的比較:

    做用域鏈:控制變量的使用順序:全部不帶.的變量,默認都去做用域找

    原型鏈:控制對象的屬性的使用順序:全部用.訪問的對象屬性,都去原型鏈找

  

每一個對象內部有一個屬性: class 記錄了建立對象時使用的類型名
訪問對象內部的class: 只能調用原生的toString()
Object.prototype.toString();//"[object Object]"
                                                對象 class

強行調用原生toString():

原生toString.call(替代this的對象)

  call作兩件事:a.執行函數;b.替換this

  Object.prototype.toString();     this->Object.prototype

  Object.prototype.toString.call(obj);  this->obj->在執行時,至關於obj.toString()

 

<script type="text/javascript">
    
//判斷一個對象是不是數組
var obj1 = {};//Object
var obj2 = [];//Array
var obj3 = function(){};//Function
var obj4 = {}; obj4.__proto__ = [];

//typeof沒法區分數組和對象
console.log(typeof obj1);//object
console.log(typeof obj2);//object
console.log(typeof obj3);//function
console.log(typeof obj4);//object
console.log("==================");

//1. isPrototypeOf 不但檢查直接父對象,並且檢查整個原型鏈
console.log(Array.prototype.isPrototypeOf(obj1));//false
console.log(Array.prototype.isPrototypeOf(obj2));//true
console.log(Array.prototype.isPrototypeOf(obj3));//false
console.log(Array.prototype.isPrototypeOf(obj4));//true
console.log("==================");

//2. constructor 也可檢查整個原型鏈
console.log(obj1.constructor == Array);//false
console.log(obj2.constructor == Array);//true
console.log(obj3.constructor == Array);//false
console.log(obj4.constructor == Array);//true
console.log("==================");

//3. instanceof 也可檢查整個原型鏈
console.log(obj1 instanceof Array);//false
console.log(obj2 instanceof Array);//true
console.log(obj3 instanceof Array);//false
console.log(obj4 instanceof Array);//true
console.log("==================");

//4. 每一個對象內部有一個屬性: class 記錄了建立對象時使用的類型名
console.log(Object.prototype.toString.call(obj1) == "[object Array]");//false
console.log(Object.prototype.toString.call(obj2) == "[object Array]");//true
console.log(Object.prototype.toString.call(obj3) == "[object Array]");//false
console.log(Object.prototype.toString.call(obj4) == "[object Array]");//false
console.log("==================");

//5. ES5: isArray
if(Array.isArray === undefined){
    console.log("Array.prototype.isArray not exsit.");
    Array.isArray = function(obj){
        return (Object.prototype.toString.call(obj) == "[object Array]");
    };
}
console.log(Array.isArray(obj1));//false
console.log(Array.isArray(obj2));//true
console.log(Array.isArray(obj3));//false
console.log(Array.isArray(obj4));//false

</script>

 

自定義繼承:

  a.僅修改一個對象的父對象:

    子對象.__proto__ = 父對象;

    Object.setPrototypeOf(子對象, 父對象);

  b.直接修改構造函數的原型對象,可同時修改以後建立的全部子對象的父對象:

    時機:必須在建立第一個對象以前完成,才能保證對象間的一致性。

  c.兩種類型間的繼承:即擴展結構(extends),又繼承原型(inherit)

    抽象:將多個子類型的相同屬性和方法,集中提取到一個公共的父類型中定義。

    how:3步:

      c1. 將多個子類型的相同屬性和方法,抽象到一個公共的父類型中集中定義

      c2. 借用構造函數:在子類型構造函數中調用父類型構造函數

        問題:若是直接調用父類型構造函數:this->window

        解決:強行調用,更換this:父類型構造函數.call(this, 參數1, 參數2, ...);

        問題:call要求每一個參數都要重複寫一遍

        解決:使用apply傳入arguments,apply可打散arguments,再單獨傳入:父類型構造函數.apply(this, arguments);

        總結:只有兩個API可打散數組參數: 

          arr1.concat(arr2); -> arr1.concat(arr2[0], arr2[1], ...);

          fun.apply(obj, arr); -> obj.fun(arr[0], arr[1], ...);

      c3. 讓子類型的原型繼承父類型的原型:Object.setPrototypeOf(子類型的原型, 父類型的原型);

call和apply:

  相同:都是強行調用一個函數,並替換this

  差異:傳入參數的方式:

    call:要求每一個參數必須單獨傳入

    apply:要求全部參數以一個數組的方式總體傳入

 

<script type="text/javascript">
    
function Flyer(fname, speed){
    this.fname = fname;
    this.speed = speed;
}
Flyer.prototype.fly = function(){
    console.log(this.fname + " is flying, on speed " + this.speed);
};

function Enemy(fname, speed, score){
    Flyer.call(this, fname, speed);
    this.score = score;
}
Enemy.prototype.getScore = function(){
    console.log(this.fname + " score is " + this.score);
};
Object.setPrototypeOf(Enemy.prototype, Flyer.prototype);

function Bee(fname, speed, award){
    Flyer.apply(this, arguments);
    this.award = award;
}
Bee.prototype.getAward = function(){
    console.log(this.fname + " award is " + this.award);
};
Object.setPrototypeOf(Bee.prototype, Flyer.prototype);

var e = new Enemy("enemy001", 50, 20);
e.fly();
e.getScore();

var b = new Bee("bee001", 5, 2);
b.fly();
b.getAward();

</script>

 

*****ES5

對象的屬性:

對象:屬性的集合

2大類:

  a. 命名屬性:自定義的可用,直接訪問的屬性

    a1. 數據屬性:直接保存一個數據的屬性

    a2. 訪問器屬性:專門保護另一個數據屬性的特殊屬性,不直接保存數據

  b.內部屬性:對象內部自動包含的,沒法用.訪問到的屬性,好比:class

***數據屬性:

  ES5中規定,每一個數據屬性都包含4大特性:

    value:時機存儲屬性值的特性

    writable:控制當前屬性是否可修改 bool

    enumerable:控制當前屬性可否被 for in 遍歷到 bool

    configurable:控制當前屬性可否被刪除,或可否修改其餘特性

  如何訪問屬性的特性:

    查看屬性的特性: var attrs = Object.getOwnPropertyDescriptor(obj, "屬性名");

    設置屬性的特性: Object.defineProperty(obj, "屬性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});

    注意:通常修改特性時,都要將configurable設置爲false:不許修改其餘特性;不可逆。

  添加一個新屬性,並設置四大屬性:

    Object.defineProperty(obj, "屬性名", {value: 值, writable: true/false, enumerable: true/false, configurable: true/false});

    注意:使用defineProperty添加的新屬性,四大特性默認值爲false!

      對象直接量中的屬性:四大特性默認值爲true

  同時定義或添加多個屬性,並設置四大特性:

    Object.defineProperty(obj, {

      "屬性名": {value: 值, writable: true/false, enumerable: true/false, configurable: true/false},

      ...

      });

 

<script type="text/javascript">
    
var emp = {id:1001, name: "jack", salary: 10000};
console.log(Object.getOwnPropertyDescriptor(emp, "id"));//Object {value: 1001, writable: true, enumerable: true, configurable: true}
Object.defineProperty(emp, "id", {writable: false});//修改emp的id屬性爲只讀
emp.id = 1002;
Object.defineProperty(emp, "salary", {enumerable: false});//修改emp的salary屬性爲不可遍歷
for(var key in emp){
    console.log(key + ":" + emp[key]);//id:1001   name:jack
}

</script>

 

靜態方法:不須要實例化對象,就直接調用的方法。

方法定義在原型對象中,仍是定義在構造函數上:

  若是隻但願當前類型的子對象才能用,就放在原型對象中;

  若是不但願實例化任何對象,就能夠直接調用,就放在構造函數上。

相關文章
相關標籤/搜索