JavaScript基礎(對象)

javaScript基礎(對象篇)

javaScript中的面向對象編程分為以下幾層

  • 第一層:單一對象的面向對象
  • 第二層:對象間的原型鏈
  • 第三層: 作為實例工廠的構造函數,類似于其他語言中的類
  • 第四層:子類,通過繼承已有的構造函數,創建新的構造函數

JavaScript中的所以對象都是從字符串到值的映射。一個對象中的某一項(鍵、值)稱為屬性,屬性的鍵始終是文本字符串。一個對象中的某一項(鍵、值)稱為屬性。屬性的鍵始終是文本的字符串、屬性的值可以是任何JavaScript的值,包括函數。方法是值作為函數的屬性
對象字面量
--
JavaScript的對象字面量可以直接創建簡單對象(Object 的直接實例)

var jane={
  name: 'Jane',
  describe:function(){
    return 'Person named' +this.name;
  },
};
獲取屬性
jana.name//Jane
jane.describe//[Function]


刪除對象
delete 操作符允許你從一個對象中完全移除一個屬性(整個鍵值對),刪除只影響一個對象的直接(“自有的",非繼承的)屬性。這并不涉及它的原型,如果是自有屬性,不能被刪除,delete會返回false,其他所有情況都會返回true

var obj={hello:'world'};
delete obj.hello//true
obj.hello//undefined

var obj={}
Object.definedProperty(obj,'canBeDeleted',{
   value:123,
   configurable:true
## });
OBject.definedProperty(obj,'cannotBeDeleted',{
 value:456,
 configurable:false
});

delete obj.cannotBeDeleted//false
其他所有情況刪除屬性返回true
delete obj.doesNotExist//true
delete obj.canBeDeleted///true

特殊的鍵

可以使用var 和function作為屬性的鍵,也可以使用數字作為鍵,但是他們會被解析為字符串

var obj={var :'a',function:'b'}
obj.var//a
obj.function//b

var obj={0.7:'abc'}
Object.key(obj)//['0.7']
obj['0.7']//'abc'

任意值轉對象

結構
無參數調用 {}
undefined {}
null {}
布爾值 new Boolean(bool)
數字 new Number(num)
字符串 new String(Str)
對象 new Object(obj)
Object(null) instance Object//true
Object(false) instanceOf Boolean
var obj ={}
Object(obj)===obj//true

this作為函數和方法的隱式參數

當你調用一個函數時,this總是作為一個隱式參數

  1. 寬松模式中的普通函數, 盡管普通函數中的this沒有實際用處,但它仍然作為一個特殊的變量存在,它的值總是指向全局對象
function returnThisSloopy(){return this}
returnThissloppy()===window//true
  1. 嚴格模式下的普通函數
this 總是undefined
function returnThisStrict(){
 'use strict'; ff 
 return this
}
returnThisStrict()===undefined//true
  1. 方法,this指向調用方法的對象
var obj={method:returnthisStrict};
obj.method()===obj;

在調用函數時設置this:call(),apply()和bind()
函數也是對象,因此,每個函數都有自己的方法

  • call 方法第一個參數會給被調用函數內的this,剩下的參數作為參數傳入被調函數中
  • apply 第一個參數是給被調函數內的this,第二個參數的個數組
  • bind 展示了偏函數,=意味著它創建了一個新的函數,并用接下來的范式調用bind,this是thisValue,參數不斷的作為新的參數的參數

var jane={
  name:'jane',
  sayHelloTo:function(otherName){
    'use strict':
    console.log(this.name+'says hello to'+otherName); 
  }
}

jane.sayHelloTo('Tarzan');
jane.sayHelloTo.call(jane,'Tarzan')
var func=jane.sayHello func.call(jane,'Tarzan');
三者等價


jane.sayHelloTo('Tarzan')
jane.sayHelloTo.apply(jane,['Tarzan'])
var func=jane.sayHelloTo;
func.apply(jane,['Tarzan']);
三者等價

jane.sayHelloTo('Tarzan')
var func1=jane.sayHelloTo.bind(jane)
func1('Tarzan');
var func2=jane.sayHelloTo.bind(jane,'Tarzan');
三者等價

提取方法時丟失this
原因在于我們把counter.inc 的值作為函數來調用,因此this是全局對象我們執行的是window.counter++,而window.count不存在,所以會是undefined

var counter={
  count:0
  inc:function(){
    this.count++;
  }
}

正確的提前方法

var func3=counter.inc.bind(counter);

嵌套函數覆蓋this

var obj={
   name:'Jane',
   friend:['Tarzan','Cheeta'],
   loop:function(){
    'use strict';
    this.friends.forEach(
        
       function(friend){//1
         console.log(this.name+' knows '+friend) //2
       }

    );

   }
} 
obj.loop();
//Cannot read property 'forEach' of undefined
因為1處的函數擁有自己的this,而this是undefined的

解決方案

  1. that ==this
that==this

   loop:function(){
    'use strict';
    var that=this;
    this.friends.forEach(
       function(friend){//1
         console.log(that.name+' knows '+friend) //2
       }
    );
   }
  1. bind()
loop:function(){
    'use strict';
    var that=this;
    this.friends.forEach(
       function(friend){//1
         console.log(that.name+' knows '+friend) //2
       }.bind(this)
    );
   }
  1. forEach中的提供第二個參數this
loop:function(){
    'use strict';
    var that=this;
    this.friends.forEach(
       function(friend){//1
         console.log(that.name+' knows '+friend) //2
       },this);
   }

三點操作符
(...)可以把數組轉化為實際參數

Math.max(...[13,7,30])

原型關系

對象通過內部屬性[[Prototype]]指定它的原型.每個對象都有這個屬性,而它也可以是null

var proto={
  describe:function(){
    return 'name :'+this.name
  }
}
var obj={
  [[prototype]]:proto,
  name='obj'
}

使用prototype創建對象

創建原型為proto的對象
調用方法Object.create(proto,propDescObj?)

var PersonProto={
  describe:function(){
    return 'Person named'+this.name; 
  }
}
var jane=Object.create(PersonProto,{
   name:{value:'Jane',writable:true}
})
通常只需創建空對象,然后手動添加屬性
var  jane=Object.create(PersonProto)
jane.value='Jane'

讀取對象原型
Object.getPrototypeof(obj)

Object.getPrototypeof(jane)===PersonProto//true

檢查對象是否是另一個對象的原型

Object.prototype.isPrototypeOf(obj)
var A={}
var B=Object.create(A)
var C=Object.create(B)
A.isPrototypeOf(C)//true
C.isPrototypeOf(A)//false

找到定義屬性的對象,遍歷對象obj的原型鏈。該函數返回為propKey的自由屬性的第一個對象如果沒有返回null

function getDefiningObject(obj,propKey){
  obj=Object(obj)
  while(obj&&!{}.hasOwnProperty.call(obj,propKey)){
     obj=Object.getPrototypeof(obj)
   }
   return obj;
}

特殊屬性protp,可以直接訪問[[Prototype]]

var obj={};
obj.__proto__===Object,prototype//true
obj.__proto__Array.prototype
Object.getPrototypeOf(obj)===Array.prototype//true

刪除只能刪除自有屬性,不能輸出繼承來的屬性
遍歷和檢測屬性
--
列出自有屬性

Object.getOwnPropertyNames(obj)//返回obj的所有自由屬性值
Object.key(obj)//返回obj的所以可枚舉的屬性值

getter和setter

對象字面量定義訪問權
var obj={
 get foo(){
  return 'getter';
 },
 set foo(value){
  console.log('setter'+value);
 }
}
obj.foo='bla'//setter:bla
obj.foo//;getter/

屬性描述符定義訪問權
var obj=Object.create({
    Object.prototype.{
     foo:{
        get:function(){
          return 'getter';
         },
         set:function(){
         console.log('setter'+value);
         }
     }
   }
})

屬性特性和屬性描述符

  • 屬性特性是屬性的原子構建快
  • 屬性描述符是一種數據結構,用于編程處理特性

屬于的屬性狀態,包括它的數據和元數據,都儲存在特性中它們是屬性擁有的字段,就像對象擁有的屬性。特效的鍵通常寫在雙方括號中。

  • [[value]],持有屬性的值
  • [[Writable]],是否可以被改變
  • [[Get]],讀取屬性時調用
  • [[Set]],設置調用
  • [[Enumerable]]持有布爾值。設置一個屬性不可枚舉,在某些操作會隱藏此屬性
  • [[Configurable]],持有布爾值,如果他是false,那么你不能刪除,改變屬性的任何特性,也不能把他從數據屬性轉化為訪問屬性

如屬性值123是只讀屬性

{ 
  value:123
  writable:false
  enumberable:true
  configurable:false
}
使用訪問其,也可以實現同樣的目的i
{
    get:function(){return 123},
    enumerable:true
    configurable:false
}

通過屬性描述符獲取和設置屬性的特性

Object.getOwnPropertyDescriptor(Object.prototype,'toString')

改變propKey的屬性

Object.defineProperty(Obj,propKey,propDesc)

var obj=Object.defineProperty({},'foo',{
  value:123
  enumerable:true
})

批量處理
Object.defineProperties(obj,propDescObj)
var obj=Object.defineProperties({},{
   foo:{value:123,enumerable:true},
   bar:{value:'abc',enumerable:true}
})

保護對象

  • 防止擴展
Object.preventExtensions(obj)
Object.isExtensible(obj)//檢查是否可以被擴展
  • 封閉
防止擴展,并設置所以屬性"不可配置"
object.seal(obj)
Object.isSealed(obj)//是否是封閉的
  • 凍結,
它使所有屬性不可寫,且封閉obj
Object.freeze(obj)
Object.isFrozen(obj)//查詢是否凍結

保護對象只影響自由屬性,不影響這些屬性的值

實例constructor屬性
默認函數包含一個實例原型對象

function C(){}
C.prototype.constructor===C//true

constructor屬性的用例

切換對象的構造函數
下面的catch子語句中,我們根據捕獲異常的構造函數不同,采取不同的處理

try{
....
}catch(e){
  switch(e.constructor){
    case SyntaxError;
    ...
    break;
    case CustomError;
    ...
    break;
 }
}

確定對象的構造函數名

function Foo(){}
var f=new Foo();
f.constructor.name//'foo'

創建相似對象,它和已有的對象x都有相同的構造函數: 可用于子構建函數實例的方法,且想要創建一個和this相似的新實例。這樣就不能使用一個固定的構造函數

function Constr(){}
var x=new Constr();
var y=new x.constructor();
console.log(y instanceof Constr);//true

指向父構造函數
一些繼承庫把父構造函數賦值給子構造函數的一個屬性 例如YUI框架通過Y.extend提供子類

function Super(){}
function Sub(){
  Sub.superclass.sonstructor.call(this);
}
Y.extend(Sub,Super);

對象不是Object的實例
機會所以對象都是Object的實例,因為Object.prototype在這些對象的原型鏈上,但是也有對象不屬于這種情況

Object.create(null) instancefo Object//false
Object.prototype instanceof Object//false

在Web瀏覽器中,每一幀和窗口都有自己的域,具有獨立的全局變量。這使得instanceof不可用于這些跨域的對象。
原型屬性的數據
--
對于實例屬性,避免使用帶初始值的原型屬性

    function Names(data){
            if(data){
                this.data==data;
            }
        }
        Names.prototype.data=[];
        var n1=new Names();
        var n2=new Names();
        n1.data.push("jane")
        console.log(n1.data);
        console.log(n2.data);
        //都是jane
        push改變了Names.prototype.data 的數組。因為這個數字被所以的沒有字有自有屬性的data的實例共享,所以n2也被影響了

根據需要創建實例屬性

 function Names(data){
           if(data){
              this.data=data;
           }
       }
       Names.prototype={
          constructor:Names,
          get data(){
            Object.defineProperty(this,'data',{
                value:[],
                enumerable:true,
                configurable:false,
                writable:false
            });
            return this.data;
          }
       }

保持數據的私有化

  • 構造函數環境中的私有化
  • 帶有特殊標記鍵的屬性中的私有數據
  • 具體化鍵的屬性中的私有數據

在調用構造函數時,創建了兩個東西:構造函數實例和環境。該實例有構造函數初始化,而該環境保持了構造函數的參數和局部變量。每個在構造函數內部創建的函數(包括方法)都會保存此環境(創建函數時的環境)的引用。由于保存了此環境的引用,即使在構造函數執行結束后,也仍然可以訪問這個環境。實例的三個值

  1. 公有屬性
  2. 私有值
  3. 特權方法(私有方法)

公有屬性

function Constr(...){
    this.publicData=...;
}

私有值

function Constr(...){
    ...
    var that=this;
    var privateData=...;
    function privateFunction(...){
     privateData=...;
     that.publicData=...;
     that.publicMethod(...);
    }
}

特權方法

function Constr(...){
  ...
  this.privilegedMethod=function(...){
    privateData=...;
    privateFunction(...);
    this.publicData=...;
    this.publicMethod(...);
  }
}

使用標記建保存私有數據

var KEY_BUFFER="_StringBuilder_buffer";
var StringBuilder=function(){
   var KEY_BUFFER='_StringBuilder_buffer';
   function StringBuilder(){
     this[KEY_BUFFER]=[];
   }
   StringBuilder.prototype={
   Constructor:StringBuilder,
   add function(str){
   this[KEY_BUFFER].push(str);
   },
   toString:function(){
    return this[KEY_BUFFER].join('');
   }
   return StringBuilder;
}();

通過IIFE保持全局數據私有

var obj=function(){
  var self={
    publlicMethod:function(...){
      privateData=...;
      privvateFunction(...); 
    },
    publicData:...
  };
  var privateData=...;
  function privateFunction(){
    privateData=...;
    self.publicData=...;
    self.publicMethod(...);
  }
}();

稀疏數組和密集數組

含有空缺的數組稱為稀疏數組。不含空缺的數組稱為密集

var sparse=[,,'C'];
var dense=[undefined,undefined,'C'];
sparse.length//3
dense.length//3
0 in psarse//false
0 in dense//true

for(var i=0;i<sparse.length;i++)console.log(sparse[i])//undefined,undefined,c
for(var i=0;i<sparse.length;i++)console.log(dense[i])//undefined,undefined,c
forEach會跳過空缺但不跳過undefined元素
sparse.forEach(function(x){console.log(x)})//c
dense.forEach(function(x){console.log(x)})//undefined,undefined,c

數組遍歷

  • forEach,every會跳過空缺
  • map會跳過,但是保留空缺
  • filter會去除空缺
  • join會把空缺,undefined和null轉化為空字符串
  • sort在排序時保留空缺
  • apply把空缺轉化為undefined

數組原型方法

  • Array.prototype.shift()//移除索引0處的元素并返回該元素。隨后元素的索引依次減1
  • Array.prototype.unshift(eleml?,elem2?,...)//在數組最前面增加給定元素,返回新的數組
  • Array.prototype.pop()移除最后一個元素并返回該元素
  • Array.prototype.push(...)//在數組尾部添加給定元素
  • Array.prototype.reverse()顛倒數組中的元素順序,并返回指向元數組的引用
  • Array.prototype.sort()//數組排序,并返回排序后的數組
  • Array.prototype.concat(arr1?,arr2?,...)//合并數組
  • Array.prototype.join(sperator?)//對數組元素應用toString()創建字符串,并用sperator連接字符串
  • Array.prototype.reduce(callback,initialValue)//從左到右迭代,并按照之前描述的調用回調函數。

JSON

JSON.stringify(value,replacer?,space?)
將JavaScript值value轉換為JSON字符串

function replacer(key,value){
   if(typeof value==='number'){
    value=2*value;
   }
   return value;
}
JSON.stringify({a:5,b:[2,8]},replacer)
//{a:10,b:[4,16]}
3
屬性鍵白名單,隱藏非數組對象內屬性
JSON.stringify({foo:1,bar:{foo:1,bar:1}},['bar']}//{bar:{bar:1}}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容