javascript-對象

6.1理解對象

創建方式:函數生成 和 字面量
例如:

   var a = new Object(); // new 構造函數方式
   var a = Object(); // 調用函數
   var a = {}; // 字面量

屬性類型

(1)數據屬性:[[configurable]](能否修改屬性), [[enumerable]](能否通過for in 循環獲取),[[writable]](能否修改),[[value]], 通過Object.defineProperty(obj, proper, properObj)方法修改默認屬性
例如:

  var a = {
    name: 'jiang'
  };
  console.log(Object.getOwnPropertyDescriptor(a, 'name')); // {value: "jiang", writable: true, enumerable: true, configurable: true}
  Object.defineProperty(a, 'name', { 'writable': false});
  a.name = 'zhong';
  console.log(Object.getOwnPropertyDescriptor(a, 'name')); // {value: "jiang", writable: false, enumerable: true, configurable: true} // 值沒有改變

(2)訪問器屬性:函數(getter(),setter), 特性([[Configuable]], [[Enumerable]], [[Get]], [[Set]])
例如:

var a = {
  name: 'jiang'
};
Object.defineProperty(a, 'sex', {
  get: function(){
    return 1;
  },
});
  a.name = 'zhong';
  console.log(a);
  console.log(a.sex);

(3)讀取:Object.getOwnPropertyDescriptor()

6.2創建對象

工廠模式

定義:本義是將創建相同或相似對象的過程進行封裝,只需調用封裝後的函數就可以獲取對象
解決的問題:類似的對象不用寫重複的代碼
帶來的問題:創建的對象沒有類型標識

  function factory(name){
 var o = {};
   0.name = name;
 o.action = function(){};
 return o;
  };// 在這裏factory就是工廠模式的工廠
  var instance1 = facroty('san');
  var instance2 = facroty('si');

構造函數

定義:形如:function A(){};的函數, 通過new來進行實例化
解決的問題:同一個構造函數產生的實例類型項目(可以通過instanceOf鑑定), 實例間共享原型對象的屬性
特點:構造函數內部的this指的是當前的實例對象
帶來的問題:每個方法都屬於不同的實例,就是沒創建一個實例方法就會重新創建一遍

function Factory(name){
  this.name = name;
  this.action = function(){};
};
var instance1 = new Factory('san');
var instance2 = new Factory('si');
console.log(instance1 instanceof Factory); // true
console.log(instance2 instanceof Factory); // true

原型模式

定義:一個對象中屬性和方法被所有實例所共享(共享實例都可以看成是這個複製品),這樣的對象就是原型對象
解決的問題:構造函數的方法和屬性在各個實例間是共享的

function Func(){};
Func.prototype.name = 'xiaotu';
Func.prototype.action = function(){
  console.log(this.name,'跑路');
};
var instance1 = new Func();
var instance2 = new Func();
instance1.action(); // xiaotu 跑路
instance2.action(); // xiaotu 跑路

特點:(1)通過new 構造函數產生實例對象,構造函數默認屬性prototype指向實例對象的原型對象, 原型對象的默認的constructor(constructor屬性被實例對象所共享)屬性又指向構造函數, 實例對象通過[[ProtoType]]指向實例得原型對象

function Func(){};
console.log(Func.prototype); // {constructor: ƒ}
console.log(Func.prototype.constructor); // ƒ Func(){}
var instance1 = new Func(); // instance1可以訪問原型的constructor
console.log(instance1.constructor) // ƒ Func(){}
console.log(instance1.__proto__) // {constructor: ƒ}
// 關係圖(*代表指向目標)
              constructor
      *----------------------------\
 函數(Func) ----------------------* 原型對象(Func.prototype)
      \           (prototype)      *
       \                          /
        \ (new)         (_proto_)/(Object.getPrototypeOf(instance1))
         \                      /
          \                    /
           \                  /
            \                /
             \              /
            對象實例(instance1)

(2)實例對象與原型對象之間的對應關係可以通過isProtoTypeOf()來判斷, 可以通過getProtoTypeOf()獲取對象實例的原型對象

function Func(){};
var instance1 = new Func();
console.log(Func.prototype.isPrototypeOf(instance1)); // true
console.log(Object.getPrototypeOf(instance1)); // {constructor: ƒ}

(3)實例對象與原型對象的屬性可以重複但不會覆蓋,只是搜索時優先搜索實例對象的

function Func(){
  this.name = 'jiang';
};
Func.prototype.name = 'zhong';
var instance1 = new Func();
console.log(instance1.name); // jiang
delete instance1.name;
console.log(instance1.name); // zhong

(4)hasProprtyOf():判斷對象實例中是否有此屬性, in:判斷對象實例和原型對象中是否由此屬性, for - in 循環遍歷包括原型和實例的屬性, Object.keys() 返回所有實例的屬性

function Func(){
};
Func.prototype.name = 'zhong';
var instance1 = new Func();
console.log(instance1.hasOwnProperty('name')); // false
console.log('name' in instance1); // true

(5)原型對象添加屬性的方式:'.'(增量添加) '{}'(覆蓋添加此時有默認的constructor指向Object)
帶來的問題:如果原型對象的屬性是引用類型的那麼實例對象和原型對象的這個屬性是同一個引用, 所以有了組合原型模式和構造函數,將引用屬性定義在構造中就沒這個問題了

function Func(){
  this.legs = ['left'];
};
Func.prototype.arms = ['right'];
var instance1 = new Func();
instance1.legs.push('right');
instance1.arms.push('left');
var instance2 = new Func();
console.log(instance2.legs); // ["left"]
console.log(instance2.arms); // ["right", "left"]

組合原型模式和構造函數:原型模式負責定義實例共享的屬性和方法, 構造函數定義每個實例特定的方法和屬性

如上例(5)

## 6.3繼承

只支持實現繼承(相對於接口繼承)
### 原型鏈
  定義:將一個(函數A)對象實例a賦值給某個函數B的原型B.prototype,那麼B的實例b就擁有了a的屬性,如果讓A的原型的值等於另一個實例,a也擁有了其他對象的值, 如此形成了原型鏈
  解決的問題:讓對象之間實現了繼承
function SuperFunc(){
  this.name = 'big-jiang';
};
function SubFunc(){
  this.name = 'small-jiang';
};
var superFunc = new SuperFunc();
SubFunc.prototype = superFunc;
var subFunc = new SubFunc();
console.log(subFunc.name); // 'small-jiang'
console.log(subFunc.__proto__.name); // 'big-jiang'
SuperFunc.prototype = new ...  // 繼續繼承成鏈
  特點:
     (1)所有對象都繼承了Object, 可以通過對象原型的原型(最後一層原型)的constructor是否指向Object的原型去判斷
function SuperFunc(){
  this.name = 'big-jiang';
};
function SubFunc(){
  this.name = 'small-jiang';
};
console.log(SuperFunc.prototype.constructor == Object); // false 應是SuperFunc
console.log(SuperFunc.prototype.__proto__.constructor == Object); // true
var superFunc = new SuperFunc();
SubFunc.prototype = superFunc;
console.log(SubFunc.prototype.constructor == SubFunc); // false 應是SuperFunc
console.log(SubFunc.prototype.constructor == SuperFunc); // true
console.log(SubFunc.prototype.__proto__.constructor == SuperFunc); // true
console.log(SubFunc.prototype.__proto__.__proto__.constructor == Object); // true
     (2)確定某原型是不是對應某實例間可以通過instanceOf和isPrototypeOf()
function SuperFunc(){
  this.name = 'big-jiang';
};
function SubFunc(){
  this.name = 'small-jiang';
};
var superFunc = new SuperFunc();
SubFunc.prototype = superFunc;
var subFunc = new SubFunc();
console.log(subFunc instanceof SubFunc); // true
console.log(subFunc instanceof SuperFunc); // true
   帶來的問題:父級的實例變成了子級的原型,父級的屬性是引用類型的話就會帶來所有實例共享的問題,不能向父級構造函數傳遞參數
function SuperFunc(){
  this.arms = ['left'];
};
function SubFunc(){
};
var superFunc = new SuperFunc();
SubFunc.prototype = superFunc;
var subFunc1 = new SubFunc();
subFunc1.arms.push('right');
var subFunc2 = new SubFunc();
console.log(subFunc2.arms); // ["left", "right"]

借用構造函數

   定義:在子函數中通過apply或者call將當前作用域傳給父函數來實現繼承
   解決的問題:這樣就不會有原型帶來的共享引用屬性的問題, 也可以在apply或者call中傳遞參數
function SuperFunc(name){
  this.name = name;
};
function SubFunc(){
  this.name = 'zhong';
  SuperFunc.call(this, 'jiang');
};
var subFunc = new SubFunc();
console.log(subFunc.name); // jiang
   帶來的問題:複用性差,父級原型中的屬性方法,自己都不能獲取到

組合繼承

   定義:將借用構造函數和作用域鏈兩種方式結合起來使用
   解決的問題:將前兩種繼承方式的優點結合起來, 缺點可以選擇性去避免
function SuperFunc(name){
  this.name = name;
  this.arms = ['left'];
};
function SubFunc(){
  SuperFunc.call(this, 'jiang');
};
var superFunc = new SuperFunc();
SubFunc.prototype = superFunc;
var subFunc = new SubFunc();
subFunc.arms.push('right');
var subFunc2 = new SubFunc();
console.log(subFunc2.arms); // 'left'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章