JS中的對象和方法簡單剖析


眾所周知,在js中對象就是精髓,不理解對象就是不理解js。

那么什么事js中的對象呢?

在js中,幾乎一切皆對象:

  1. Boolean ,String,Number可以是對象(或者說原生數據被認作對象);
  2. Dates ,Maths,Regexps,Arrays,Funcitons,當然Objects,這些都是對象;

JS中,所有值,除了原生值,都是對象;這些原生值包括:strings,numbers('3.14'),true,false,null和undefined

對象是包含變量的變量,js變量可以包含單個值,比如:

var person = "John Doe";

 同樣,對象也是變量,但它可以包含很多的值,只不過這些值是以鍵值對的形式表現的(name and value separated by a colon),一個js對象就是命名值的集合。

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

  對象屬性

被命名的值,在js對象中被稱為屬性;這種以命名值而寫的對象的寫法類似於:

Property	Value
firstName	John
lastName	Doe
age	50
eyeColor	blue
  • php的Associate Arrays
  • python中的Dictionaries
  • C中的Hash表
  • Java中的hash maps
  • Ruby和Perl中的Hashes

對象方法

方法是表現在對象上的行為或動作,對象屬性可以是原生值,別的對象,或者函數。一個對象的方法是一個對象包含一個函數定義的屬性。

fullName	function() {return this.firstName + " " + this.lastName;}

js對象是一個包含所謂屬性的名值對和方法的容器。

創造一個js對象

在js中你可以定義和創造自己的對象,有不同的方法去創造對象:

  • 利用對象字面量
  • 利用new 關鍵字
  • 定義一個構造器,然后實例化
  • 在es5中,也可以利用Object.create()函數創造對象

對象字面量方法:最簡單,一句話定義並創造一個對象。對象字面量是鍵值對用大括號抱起來的系列。

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

  new關鍵字方法:

var person = new Object();
person.firstName = "John";
person.lastName = "Doe";
person.age = 50;
person.eyeColor = "blue";

  以上兩種例子幾乎類似,沒必要用new Object()。為了簡潔,可讀性及執行性能,首選第一種(對象字面量方法)。

對象構造器

以上兩種方法在很多情境中有局限,它們只是創造一個單一對象。有時候,我們喜歡擁有一個可以創造很多一種類型對象的”對象類型“,此時利用對象構造函數創造一個對象類型的標准方式應運而生。

function person(first, last, age, eye) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eye;
}
var myFather = new person("John", "Doe", 50, "blue");
var myMother = new person("Sally", "Rally", 48, "green");

  以上方法是一個對象構造器,一旦擁有了它,你可以創造同類的對象

var myFather = new person("John", "Doe", 50, "blue");
var myMother = new person("Sally", "Rally", 48, "green");

This關鍵字

在js中,被稱作this的東西,是一個“擁有”js代碼的對象。this的值,當用在一個函數里,是一個”擁有“函數的對象;當用在一個對象里,是對象本身。this關鍵字,在一個對象構造器里邊沒本身有值,僅僅是新對象的替代品。當構造器被用於構造對象時this的值會變成新對象。

注意:this不是一個變量,它是關鍵字,你不能改變this值。

js用於內置的原生對象的構造器

var x1 = new Object();    // A new Object object
var x2 = new String();    // A new String object
var x3 = new Number();    // A new Number object
var x4 = new Boolean();   // A new Boolean object
var x5 = new Array();     // A new Array object
var	x6 = new RegExp();    // A new RegExp object
var x7 = new Function();  // A new Function object
var x8 = new Date();      // A new Date object

  Math()對象不在列表中,因為Math是一個全局對象,new關鍵字不能用在Math中。

並且,眾所周知,js擁有原生數據類型String,Number,和Boolean的對象版本。沒理由創造浮躁對象,原生值執行的更快

var x1 = {};            // new object
var x2 = "";            // new primitive string
var x3 = 0;             // new primitive number
var x4 = false;         // new primitive boolean
var x5 = [];            // new array	object
var	x6 = /()/           // new regexp object
var x7 = function(){};  // new function object

  JS對象是可變的

對象可變,他們靠索引定位而非值。如果一個person是一個對象,那么以下語句不會創造person的副本。

var x = person;  // This will not create a copy of person.

  對象x不是person的副本,它是person本身,因此任何x的改變都很改變person。

js變量不可變,可變(Mutable)的只是js對象,如下實例。

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}

var x = person;
x.age = 10;           // This will change both x.age and person.age

  對象屬性

屬性是js對象中最重要的部分

  • 屬性是js對象所關聯的值
  • js對象是無序屬性的集合
  • 屬性可以增刪改查,有些是只讀

訪問js屬性語法:

objectName.property          // person.age

objectName["property"]       // person["age"]

objectName[expression]       // x = "age"; person[x],表達式必須等於屬性名

person.firstname + " is " + person.age + " years old.";
person["firstname"] + " is " + person["age"] + " years old.";

for-in循環遍歷對象屬性語法:

for (variable in object) {
    code to be executed
}

 添加屬性

person.nationality = "English";

  但你不能用保留字作為屬性名,利用js命名規則。

刪除屬性

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};
delete person.age;   // or delete person["age"]; 

  刪除關鍵字刪除了屬性值和其本身,刪除后屬性在其被再添加之前不能再用。刪除操作符被用於對象屬性的操作,對於變量或者方法無效。但謹記,delete操作符不應用於預定義js對象的屬性,這樣會阻塞應用。

屬性的屬性(property attributes)

屬性有個name,也有一個value。value是屬性的屬性之一,其它屬性是:enumerable,configurable,writable。這些屬性定義了屬性是如何被訪問的(是否可讀可寫)

在js中,所有屬性是可讀的但只有value的屬性可以被改變(當且僅當屬性是可寫的)。ES5中有針對getting和setting所有屬性的屬性的方法。

原型屬性

js對象繼承它們原型的屬性,delete關鍵字不刪除所繼承的屬性,但是如果你刪除了原型的屬性,這將影響所繼承原型的所有對象。

對象方法

如前所述,js方法是對象中表現的行為。js方法是包含函數定義的屬性,即方法是存做對象屬性的函數。

訪問對象方法:

methodName : function() { code lines }//創造一個對象方法

objectName.methodName();//訪問
name = person.fullName();//fullName屬性當以()調用時將執行
name = person.fullName;//fullName當么有()調用時將返回函數定義

  利用內置方法

var message = "Hello world!";
var x = message.toUpperCase();//HELLO WORLD!

  添加方法(類似於添加屬性)

function person(firstName, lastName, age, eyeColor) {
    this.firstName = firstName;  
    this.lastName = lastName;
    this.age = age;
    this.eyeColor = eyeColor;
    this.changeName = function (name) {
        this.lastName = name;
    };
}

  對象屬性

所有js對象擁有一個原型(prototype),原型也是對象。所有js對象繼承其原型的屬性和方法。

利用字面量或者newObject 構造的對象,繼承所謂的Object.prototype的原型;

利用new Date()構造的對象繼承Date.prototype.Object.prototype 出於原型鏈的頂端(top)

因此所有的js對象繼承自Object.prototype。

創造一個原型

標准方法是利用一個構造函數去創造一個對象原型:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
}

  有了構造函數,你可以利用new關鍵字去從同樣原型中創造新對象。

var myFather = new Person("John", "Doe", 50, "blue");
var myMother = new Person("Sally", "Rally", 48, "green");
//構造函數是Person對象的原型,首字母大寫去命名構造函數是一個好慣例

  給對象添加屬性和方法

有時你想添加新屬性或方法給一個存在的對象,給所有給定類型的存在對象,或者給一個對象原型。

myFather.nationality = "English";//給一個存在的對象,僅僅對此對象

myFather.name = function () {
    return this.firstName + " " + this.lastName;
};//添加一個方法,僅僅對此對象

  給原型添加屬性

Person.nationality = "English";//不能像給已存在對象添加新屬性那樣給原型添加,因為原型不是一個存在的對象。

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.nationality = "English"
}//給原型添加屬性,必須添加在構造函數里邊。原型屬性可以擁有原型值(默認值)
function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.name = function() {return this.firstName + " " + this.lastName;};
}//添加方法

  利用原型屬性

js原型屬性允許你去給存在的原型添加新屬性和新方法,但要記住:只改變你所擁有的屬性,別去動標准js對象的屬性。

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
Person.prototype.name = function() {
    return this.firstName + " " + this.lastName;
};

  js函數定義

js函數可以function關鍵字定義,你也可以用函數聲明(declaration)和函數表達式( expression)去定義一個函數。

函數聲明

function functionName(parameters) {
  code to be executed
}
//分號被用於分離js執行語句,由於函數聲明不是一個可執行語句,因此以分號結束一個函數聲明並不常見

  函數聲明不被立即執行,他們是“備用”,並且當調用時稍后執行。

函數表達式

var x = function (a, b) {return a * b};//函數表達式可以存儲在一個變量里
var z = x(4, 3);//此時,這個變量可被用作一個函數
//事實上,上述函數是一個匿名函數,存儲在變量中的函數不必擁有名字,他們用變量名調用;並且以分號結束是因為是可執行語句的一部分

函數構造器

函數可以利用js內嵌的函數構造器Function()定義

var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);

  事實上你不必如此,在js中很不必用到new關鍵字。

函數提升

提升是js移動聲明到當前作用域頂端的默認行為,提升用於變量聲明和函數聲明,因此函數可以先調用后聲明。但是,函數表達式定義的函數不會被提升。

myFunction(5);//25

function myFunction(y) {
    return y * y;
}
foo();//VM747:1 Uncaught TypeError: foo is not a function(…)
var foo=function(){}

自執行函數

(function () {
    var x = "Hello!!";      // I will invoke myself
})();

  事實上,上述函數是一個匿名的自執行函數

函數可被用在值中,也可用在表達式中

function myFunction(a, b) {
    return a * b;
}

var x = myFunction(4, 3);
var y= myFunction(4, 3) * 2;

  函數皆對象

typeof操作符在js中對於functions返回為‘function’,但是函數最好是被描述為對象,js函數擁有屬性和方法。

function myFunction(a, b) {
    return arguments.length;
}//但函數被調用時返回參數個數
var txt = myFunction.toString();//頭String()方法返回一個字符串

  函數作為一個對象的屬性定義,被稱作一個對象的方法;

函數作為創造對象的定義,被稱作一個對象構造器。

函數形參(parameters)

js函數對形參值不做任何檢查。

js形參和實參:形參是函數定義中的名(names),實參是傳給(或接收)函數的真實值(real values)

functionName(parameter1, parameter2, parameter3) {
    code to be executed
}

  形參規則:js針對形參的函數定義不區分數據類型,對傳來的實參不做類型檢查,對接收的實參數目不做檢查。

形參默認:如果函數丟失實參(少於聲明的)時調用,缺失的值被設置為:undefined。有時候可以接受,但最好對形參設置一個默認值。

function myFunction(x, y) {
    if (y === undefined) {
          y = 0;
    } 
}//如果函數被過多實參(多余聲明的)調用。這些實參可以利用實參對象獲取

  實參對象

js擁有被稱作實參對象的內置對象,它們包含一個實參數組,當函數被調用時。此時可以簡單利用函數去在一個數據列表中尋找最值。

x = findMax(1, 123, 500, 115, 44, 88);

function findMax() {
    var i;
    var max = -Infinity;
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}
//統計輸入值之和
x = sumAll(1, 123, 500, 115, 44, 88);

function sumAll() {
    var i, sum = 0;
    for (i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}

  按值傳遞的實參

形參,在函數調用中,就是函數實參;js實參按值傳遞,函數僅僅去知道值,而非實參地址。

如果一個函數改變了實參值,不會改變形參的原始值。形參的改變在函數外部不可見(不反映)。

對象按引用傳遞,js中對象索引是值,因此,對象表現為按索引傳遞:如果一個函數改變一個對象的屬性,這就改變了原始值。對象屬性的改變在函數外部可見(反映)

js函數調用

四種方式,每種方式以this如何初始化為區分。

函數調用:函數代碼當定義時不執行,僅當調用時執行。(a JavaScript function can be invoked without being called.)

作為函數調用函數

function myFunction(a, b) {
    return a * b;
}
myFunction(10, 2);           // myFunction(10, 2) will return 20

  上述函數不屬於任何對象,但js中有一個默認的全局對象。在html中默認的全局對象是html頁面本身,因此上述函數”屬於“html頁面。在瀏覽器頁面對象是瀏覽器窗口,上述函數自動變成window 函數,木Function和window.沒有Function是一樣的

這是一個常用的調用函數的方式,但並不是好習慣。全局變量,方法,或者函數在全局對象中很容易造成命名沖突和bug。

全局對象

當一個函數沒有擁有者對象而被調用時,this值變成全局對象。在web瀏覽器中全局對象是browser window。

function myFunction() {
    return this;
}
myFunction();                // Will return the window object

  調用一個作為全局對象的函數,引起讓this值變為全局對象的后果。因此,用window對象作為變量很容易阻塞你的編程。

作為方法調用

作為方法調用

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}
myObject.fullName();         // Will return "John Doe"

  fullName方法是一個函數,這個函數屬於對象,沒有Object是該函數的擁有者。被稱作this的東西,是一個擁有js代碼的對象,此時的this值指向myObject。

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this;
    }
}
myObject.fullName();          // Will return [object Object] (the owner object);將函數作為對象的方法來調用,使得this指向對象本身

  作為構造函數調用

如果一個函數以前置new關鍵字調用,他就是一個構造器的調用。看起來像創造一個新函數,但是由於js函數皆對象,你事實上創造了一個新對象。

// This is a function constructor:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}

// This	creates a new object
var x = new myFunction("John","Doe");
x.firstName;                             // Will return "John"

  構造器的調用創造了一個新對象,這個新對象繼承他的構造器的屬性和方法。this關鍵字在構造器中沒有一個值,但是在構造器被調用時,this值將是所創造的那個新的對象。

以函數的方法調用

js中函數皆對象,js函數擁有屬性和方法。call()和apply()是js的預定義函數方法,都可以調用函數,並且都必須將擁有者對象作為首個形參(調用時)。

function myFunction(a, b) {
    return a * b;
}
myObject = myFunction.call(myObject, 10, 2);     // Will return 20
function myFunction(a, b) {
    return a * b;
}
myArray = [10, 2];
myObject = myFunction.apply(myObject, myArray);  // Will also return 20

  兩種方式均那擁有者對象(owner object)作為首個實參,唯一的區別是call分散地取函數實參,apply將函數實參作為一個數組來取。在js嚴格模式中,被調用的函數中首個實參是this的值,即使這個實參不是一個對象。在非嚴格模式中,如果首個實參是null或者undefined,它將被全局對象取代。利用call和apply你可以設置this值,並且將函數作為一個現有對象的方法調用。

js閉包

js變量可以屬於全局的或者局部的作用域,局部變量可利用閉包構造。

全局變量

一個函數可以訪問定義在其中的所有變量:

function myFunction() {
    var a = 4;
    return a * a;
}

  並且,一個函數也可以訪問在其外層的函數,像這樣:

var a = 4;
function myFunction() {
    return a * a;
}

  此時a是一個全局變量,在頁面中全局變量屬於window對象,全局變量可被所有頁面中腳本利用和改變;第一個例子中a是局部變量,局部變量僅能在其所定義的函數內部用,對其他函數和腳本代碼隱藏。同名的全局和局部變量是不同的變量,改變一個不影響另一個,變量不以var關鍵字聲明的通常是全局的,即使在函數內部。

變量生命周期

全局變量和你的應用程序,你的window,你的webpage同生,局部變量短命,當函數調用時被造就,當調用結束被刪除。

看以下例子

var counter = 0;

function add() {
    counter += 1;
}

add();
add();
add();

// the counter is now equal to 3
function add() {
    var counter = 0;
    counter += 1;
}

add();
add();
add();

// the counter should now be 3, but it does not work !
function add() {
    var counter = 0;
    function plus() {counter += 1;}
    plus();    
    return counter; 
}//solve this problem

  js閉包(closure)

還記得自我調用函數嗎?這個函數干嘛的?

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

// the counter is now 3

  解釋:變量add作為一個自我調用函數的返回值聲明,自執行函數僅運行一次,設置counter為0,返回表達式。這種方式的add變成一個函數,完美的部分是它可以訪問父級作用域內的counter.這就是所謂的js閉包,它讓函數擁有私有變量成為可能。counter被匿名函數的作用域所保護,並且只能利用add函數去改變。

總之:閉包是一個即使父級函數關閉,仍可以訪問父級作用域的函數。

參考文獻:http://www.w3schools.com/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM