精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
筆記:《JavaScript面向對象精要》

第3章 理解對象

3.1 定義屬性

當一個屬性第一次被添加給對象時,JavaScript在對象上調用一個名為[[Put]]的內部方法。這個操作不僅指定了初始的值,也定義了屬性的一些特征。
當一個已有的屬性被賦予一個新值時,調用的是一個名為[[Set]]的方法。
//Object實例化
var person1 = new Object();
person1.name = 'liang';   //調用[[Put]]的內部方法

//對象字面形式
var person2 = {
     name: 'liang'
};

person2.name = 'zhu';   //調用[[Set]]方法

3.2 屬性探測

in 操作符在給定對象中查找一個給定名稱的屬性,如果找到則返回true。
in操作符會檢測自有屬性和原型屬性,如果只要檢測自有屬性,使用hasOwnProperty()方法。
var person1 = {
   name: 'liang',
   age: 26
};

console.log('name' in person1);   //true
console.log(person1.hasOwnProperty('name'));   //true

//tostring是原型屬性,所以用hasOwnProperty檢測結果為false
console.log('toString' in person1);   //true
console.log(person1.hasOwnProperty('toString'));   //false

//可用這樣一個函數來鑒別原型屬性,結果為true則是原型屬性
function check(object, name){
     return (name in object) && !object.hasOwnProperty(name);
}
console.log(check(person1,'age'));   //false
console.log(check(person1,'toString'));  //true

3.3 刪除屬性

delete 操作符針對單個對象屬性調用名為[[Delete]]的內部方法。操作成功時,它返回true。
var person1 = {
   name: 'liang',
   age: 26
};

delete person1.age;
'age' in person1;   //false

同名的自有屬性會覆蓋原型屬性的值。delete 可以刪除自有屬性,不能刪除原型屬性。

3.4 屬性枚舉

[[Enumerable]]是屬性的一個內部特征,指示屬性是否可枚舉,默認為true(可枚舉的)。
for-in 循環會枚舉一個對象所有的可枚舉屬性,并將屬性賦給一個變量。
var person1 = {
   name: 'liang',
   age: 26
};

var property;
for (property in person1){
    console.log('Name' + ': ' + property);    //枚舉屬性
    console.log('Value' + ': ' + person1[property]);    //枚舉屬性的值
}   
//Name: name   Value: liang   Name: age   Value: 26

Object.keys() 方法,獲取可枚舉屬性的名字的數組。
for-in 循環會遍歷原型屬性,而Object.keys()只返回自有屬性。
var person1 = {
   name: 'liang',
   age: 26
};

//獲取數組
var propertys = Object.keys(person1);
propertys;    //['name', 'age']

//輸出屬性和屬性值
var i, len;
for(i=0, len=propertys.length; i<len; i++){
      console.log('Name' + ': ' + propertys[i]);
      console.log('Value' + ': ' + person1[propertys[i]]);
}     //Name: name   Value: liang   Name: age   Value: 26

3.5 屬性類型

對象的屬性有兩種類型:數據屬性和訪問器屬性。
數據屬性只包含一個值。
訪問器屬性不包含值,而是定義了一個當屬性被讀取時調用的函數(稱為getter),和一個當屬性被寫入時調用的函數(稱為setter)。
訪問器屬性僅需要getter或setter兩者中的任意一個,也可以兩者都有。
特殊關鍵字get和set被用在訪問器屬性名字的前面,后面跟著小括號和函數體。getter被期望返回一個值,而setter則接受一個需要被賦給屬性的值作為參數。
var person1 = {
     _name: 'liang',    //命名規范:下劃線表示該屬性被認為是私有的

    get name(){
        console.log('the name is ');
        return this._name;
    },    //此處加逗號

    set name(value){
        console.log('set name to',value);
        this._name = value;
    }
};

//注意:使用的是person1.name,而不是person1._name
console.log(person1.name);   //the name is 'liang'
console.log(person1._name);    //liang

person1.name = 'zhu';    //set name to zhu 'zhu'
console.log(person1.name);   //the name is 'zhu'

console.log(Object.keys(person1));  //['_name', 'name']
通常情況下不使用訪問器屬性,但當你希望賦值操作會觸發一些行為,或讀取的值需要通過計算所需的返回值,可使用訪問器屬性。
如果只定義getter,該屬性就變成只讀。
如果只定義setter,該屬性就變成只寫。

3.6 屬性特征

3.6.1 通用特征

有兩個屬性特征是數據和訪問器屬性都具有的。
[[Enumerable]],決定了是否可以遍歷該屬性。
[[Configurable]],決定了該屬性是否可配置。delete可以刪除可配置的屬性。

Object.definedProperty() 方法,可用來改變屬性特征。有3個參數:擁有該屬性的對象、屬性名、包含需要設置特征的屬性描述對象。
var person1 = {
    name: 'liang'
};

Object.defineProperty(person1,'name',{
    enumerable: false
});

console.log('name' in person1);   //true
console.log(Object.keys(person1));   // []

3.6.2 數據屬性特征

數據屬性額外擁有兩個特征:
[[Value]] 包含屬性的值。
[[Writable]] 指示該屬性是否可以寫入。
var person1 = {};

Object.defineProperty(person1,'name',{
    value: 'liang',
    writable: true,
    enumerable: true,
    configurable: true
});
Object.defineProperty() 方法調用時,會首先檢查該屬性是否存在,如果不存在,將根據屬性描述對象指定的特征創建。調用這個方法,如果不指定特征的布爾值,它會默認設置為false。

3.6.2 訪問器屬性特征

訪問器屬性不需要存儲值,因此沒有[[Value]]和[[Writable]]。
有另外兩個額外特征:[[Get]]和[[Set]]
之前的例子:

var person1 = {
     _name: 'liang',    //命名規范:下劃線表示該屬性被認為是私有的,實際上還是公有的

    get name(){
        console.log('the name is ');
        return this._name;
    },     //此處加逗號

    set name(value){
        console.log('set name to',value);
        this._name = value;
    }
};
改寫成如下形式:
var person1 = {
     _name: 'liang'
};

Object.defineProperty(person1,'name',{   //注意這里的name,不是_name,也可以用別的字符串來定義訪問器屬性
    get:function(){
        console.log('Reading name');
        return this._name;
    },
    set:function(value){
        console.log('Setting name to ',value);
        this._name=value;
    },
    enumerable:true,
    configurable:true
});
person1.name = 'zhang';  //setting name to zhang   'zhang' 

3.6.4 定義多重屬性

Object.defineProperties() 可以為一個對象同時定義多個屬性。
接受兩個參數:需要改變的對象、一個包含所有屬性信息的對象。
var person1 = {};

Object.defineProperties(person1,{
     _name: {
        value: 'liang',
        enumerable: true,
        configurable: true,
        writable: true
    },

    name: {
        get:function(){
            console.log('reading name');
            return this._name;
        },
       set: function(value){
            console.log('setting name to %s',value);
            this._name=value;
        },
       enumerable: true,
       configurable: true
    }
});

person1.name;   //reading name  'liang'
person1._name;   //'liang'

3.6.5 獲取屬性特征

Object.getOwnPropertyDescriptor() 方法獲取屬性的特征。
這個方法只適用于自有屬性。接受兩個參數:對象、屬性名。
var person1 = {
   name: 'liang'
};

var descriptor = Object.getOwnPropertyDescriptor(person,'name');
descriptor;   //{value: 'liang', writable: true, enumerable: true, configurable: true}

3.7 禁止修改對象

[[Extensible]] 指明該對象是否可以被修改。有3種方法來鎖定對象屬性。
Object.preventExtensible() 禁止擴展,對象不能繼續添加新的屬性。 Object.isExtensible() 判斷是否為可擴展的。
Object.seal() 封印對象,對象不能繼續添加新的屬性,且不能刪除和改變屬性類型。 Object.isSealed() 判斷是否被封印的
Object.freeze() 凍結對象,對象不能繼續添加新的屬性,且不能刪除和改變屬性類型,還不能寫入任何數據屬性。 Object.isFrozen() 判斷是否被凍結。
var person1 = {
    name: 'liang'
}

Object.seal(person1);
delete person1.name;    //將無法刪除
console.log(Object.isExtensible(person1));   //false
console.log(Object.isSealed(person1));   //true

第4章 構造函數和原型對象

4.1 構造函數

構造函數名的首字母要大寫。
function Person(){
   //statement
}

構造函數接受一個命名參數name并將其賦給this對象的name屬性。
function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name);
    };
}

var person1 = new Person('liang');

person1.sayName();  //'liang'
構造函數中還能用Object.defineProperty() 方法來幫助我們初始化。
function Person(name){
    Object.defineProperty(this,'name',{
        get:function(){
            return name;
        },
        set:function(newName){
            name = newName;
       },
        enumerable:true,
        configurable:true
    });
}

4.2 原型對象

幾乎所有的函數(除了一些內建函數)都有一個名為prototype的屬性,該屬性是一個原型對象,用來創建新的對象實例。
所有創建的對象實例共享該原型對象,且這些對象實例可以訪問原型對象的屬性。
當你試圖訪問一個對象的某個屬性時,JavaScript首先在自有屬性里查找該名字,如果在自有屬性里沒有找到則查找原型屬性。

4.2.1 [[Prototype]] 屬性

對象實例通過內部屬性[[Prototype]]跟蹤其原型對象。該屬性是對象實例指向原型對象的指針。
Object.getPrototypeOf() 方法讀取[[Prototype]]屬性的值。
var obj = {};

console.log(Object.getPrototypeOf(obj) === Object.prototype);   // true
//任何一個泛用對象,其[[Prototype]]屬性始終指向Object.prototype

isPrototypeOf() 方法檢測某個對象(Object)是否是另一個對象(obj)的原型對象。
var obj = {};

console.log(Object.prototype.isPrototypeOf(obj));   //true
或者說isPrototypeOf() 是檢測一個對象(person1)是否是另一個對象(Person)的對象實例。
function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name);
    };
}

var person1 = new Person('liang');

Person.prototype.isPrototypeOf(person1);   //true

Object.getPrototypeOf(person1) === Person.prototype;   //true

4.2.2 在構造函數中使用原型對象

function Person(name){
    this.name = name;
}

console.log(Person.prototype);   //{constructor: ?}

Person.prototype.sayName = function(){
  return this.name;
};

console.log(Person.prototype);   //{sayName: ?, constructor: ?}

var person1 = new Person('liang1');

person1.sayName();    //'liang1'
上例中,sayName() 現在是一個原型屬性而不是自有屬性。
如下的構造函數,sayName是一個自有屬性,區分這兩種創建方式。
function Person(name){
    this.name = name;
    this.sayName = function(){
    return this.name;
    }
}

console.log(Person.prototype);   //{constructor: ?}

原型對象上存儲其他類型的數據,存儲引用值時要注意,這些引用值會被多個實例共享。
function Person(name){
    this.name = name;
}

Person.prototype.favorites= [];

var person1 = new Person('liang');
var person2 = new Person('zhu');

person1.favorites.push('pizza');
person2.favorites.push('quinoa');

person1.favorites;   //['pizza', 'quinoa']

通過一個對象字面形式替換原型對象,來設置多個原型屬性。
function Person(name){
    this.name = name;
}

Person.prototype={
    sayName: function(){
        return this.name;
    },
    toString: function(){
        return '[Person ' + this.name + ']';
    }
};

var person1 = new Person('liang');
console.log(person1.sayName());    //'liang'
console.log(person1.toString());    //'[Person liang]'
使用對象字面形式改寫原型對象改變了構造函數的屬性,因此它現在指向Object而不是Person。
console.log(person1.constructor === Person);    //false
console.log(person1.constructor === Object);    //true
這是因為原型對象具有一個constructor屬性,這是對象實例所沒有的。當一個函數被創建時,它的prototype屬性也被創建,且該原型對象的constructor屬性指向該函數。當使用對象字面形式改寫原型對象Person.prototype時,其contructor屬性將被置為泛用對象Object。
為避免這一點,手動重置constructor屬性
function Person(name){
    this.name = name;
}

Person.prototype={
    constructor:Person,
    sayName: function(){
        return this.name;
    },
    toString: function(){
        return '[Person ' + this.name + ']';
    }
};

構造函數、原型對象、對象實例,這三者的關系:
對于構造函數來說,prototype是作為構造函數的屬性;對于對象實例來說,prototype是對象實例的原型對象。所以prototype即是屬性,又是對象。
所有一切對象的原型頂端,都是Object.prototype。

4.2.3 改變原型對象

給定類型的所有對象實例共享一個原型對象。[[Prototype]]屬性只是一個指向原型對象的指針,任何對原型對象的改變都立即反應到所有引用它的對象實例上。
使用Object.seal()或Object.freeze()方法,將無法添加自有屬性或改變凍結對象的自有屬性,但可以通過在原型對象上添加屬性來擴展這些對象實例。
var person1 = new Person('liang');
var person2 = new Person('zhu');

Object.freeze(person1);

Person.prototype.sayHi = function(){
    console.log('Hi');
};

person1.sayHi();
person2.sayHi();

4.2.4 內建對象的原型對象

所有內建對象都有構造函數,因此也都有原型對象可改變。
Array.prototype.sum = function(){
    return this.reduce(function(previous,current){    //reduce()是數組方法
        return previous + current;
    });
};

var numbers = [1,2,3,4,5];
numbers.sum();   //15
在sum() 內部,this指向數組的對象實例numbers,于是該方法也可以自由使用數組的其他方法,比如reduce()。
內建對象的原型對象雖然可以改變,但不建議在生產環境中使用。可以用來做實驗和驗證新功能。
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JavaScript 的面向對象
詳解Javascript中的Object對象
鑒別一個人是否 js 入門的標準竟然是?!
JS面向對象設計-創建對象
object取key,object取value,object刪除鍵值對,object添加屬性
JavaScript是如何面向對象的
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 郯城县| 岳普湖县| 三台县| 兴海县| 辽阳县| 都江堰市| 江川县| 合肥市| 弥勒县| 家居| 化德县| 莱芜市| 阜阳市| 大余县| 封开县| 古蔺县| 汶川县| 广安市| 泸西县| 武冈市| 仁怀市| 郑州市| 安阳县| 池州市| 宿松县| 桐柏县| 德化县| 四子王旗| 玛沁县| 邵武市| 芦溪县| 达拉特旗| 拉萨市| 惠东县| 教育| 衡东县| 台南市| 雷州市| 滁州市| 纳雍县| 密云县|