javascript - 如何建立一個對象

記錄一些前端知識。前端

對象的定義

無序屬性的集合,其屬性能夠包含基本值、對象或者函數,。對象的每一個屬性或方 法都有一個名字,而每一個名字都映射到一個值,每一個對象都是基於一個引用類型建立的。數組

數據類型

基本類型值:Undefined、Null、Boolean、Number、String。app

引用類型值:Obejct函數

理解對象

建立自定義對象的一個最簡單的方式就是建立一個Object的實例,而後給它添加屬性和方法。ui

//方式(1)
let a = new Object();
//屬性
a.name = "ssssslf";
a.age = 24;
//方法
a.getName = function(){
    console.log(this.name) 
}

//方式(2)
let a = {
    name:"ssssslf",
    age:24,
    getName:function(){
        console.log(this.name)
    }
}

複製代碼

屬性

數據屬性和訪問器屬性this

數據屬性:數據屬性包含一個數據值的位置。在這個位置能夠讀取和寫入值spa

  • Configurable:默認爲true,表示是否能夠刪除屬性修改屬性。
  • Enumerable:默認爲true,表示是否能夠經過 for-in 循環返回屬性。
  • Writable:默認爲true,表示可否修改屬性的值。
  • Value:默認爲undefined,包含中國屬性的值。

要修改屬性的默認特性,必須使用Object.defineProperty()方法prototype

例子:指針

//參數:屬性所在對象,屬性名稱,描述符對象
Object.defineProperty(a,"name",{
    writable:false,//不能修改屬性值,只讀
    value:"slf",
})
console.log(a.name);//slf
a.name = "sslf";
console.log(a.name);//slf


Object.defineProperty(a,"name",{
    writable:true,//能修改屬性值
    value:"slf",
})
console.log(a.name);//slf
a.name = "sslf";
console.log(a.name);//sslf
複製代碼

其他方式相似。code

注意:若是修改Configurable,講其改成false,再將其改成true,會報錯。

訪問器屬性:沒有數據值,可是有getter,setter函數

  • Configurable:同上
  • Enumerable:同上
  • get:默認值undefined,讀取屬性時調用的函數
  • set:默認值undefined,寫入屬性時調用的函數

例子:

let a = {
    name:"ssssslf",
    age:24,
    getName:function(){
        console.log(this.name)
    }
}
Object.defineProperty(a,"_name",{
    get:function(){
        return this.name;
    },
    set:function(newValue){
        if(newValue === "ssslf"){
            this.name = newValue;
        }
    }
})
a._name = "sslf";
console.log(a);//{name: "ssssslf", age: 24, getName: ƒ}
a._name = "ssslf";
console.log(a);//{name: "ssslf", age: 24, getName: ƒ}
複製代碼

以上例子是ECMScript5,舊有方法用: defineGetter , defineSetter.

a.__defineGetter__("_name",function(){
    return this.name
})
a.__defineSetter__("_name",function(){
  if(newValue === "ssslf"){
        this.name = newValue;
    }
})
複製代碼

Object.defineProperty 設置單個屬性,Object.defineProperties設置多個屬性

let a = {};
Object.defineProperties(a,{
    //數據屬性
    name:{
        value:"slf"
    },
    age:{
        value:"24",
    },
    //訪問器屬性
    _name:{
        get:function(){
            return this.name
        },
        set:function(newValue){
            if(newValue === "ssslf"){
                this.name = newValue;
            }
        }
    }
})
複製代碼

讀取屬性:Object.getOwnPropertyDescriptor

var descriptor = Object.getOwnPropertyDescriptor(a,"name")
console.log(descriptor.value)//slf
console.log(descriptor.configurable)//false
複製代碼

建立對象

工廠模式

function createPerson(name,age){
    //顯示建立對象
    var o = new Object();
    o.name = name;
    o.age = age;
    o.getName = function(){
        return this.name
    }
    return o;
}
var slf = createPerson("slf",24);
複製代碼
  • 優勢:解決建立多個類似對象的問題
  • 缺點:沒有解決對象識別問題,不知道對象類型

構造函數模式

//沒有顯示建立對象,直接將屬性方法賦值給this,沒有return語句
//構造函數,函數名稱大寫
function Person(name,age){
    //屬性
    this.name = name;
    this.age = age;
    //方法
    this.getName = function(){
        return this.name;
    }
}
//建立Person實例,必須使用new操做符
var slf = new Person("slf",24);
複製代碼

打印slf

slf是Person的一個實例,slf有一個constructor(構造函數)屬性,該屬性指向Person 即console.log(slf.constructor == Person) //true
在工廠模式中是沒法知道對象類型的,但在這裏是能夠知道對象類型的。判斷對象類型的方式能夠用instanceof

console.log(slf instanceof Object) //true 全部的對象都繼承Object
console.log(slf instanceof Person)//true
複製代碼
構造函數的調用方式

(1) 當作構造函數使用 (2) 當作普通函數調用 (3) 在另外一個對象的做用域中調用

//(1)
var person = new Person("slf",24);
person.getName();
//(2)
Person("slf1",25);
window.geName();
//(3)
var other = new Object();
Person.call(other,"slf2",26);
other.getName();
複製代碼
  • 缺點:每個方法都要在每個實力上創新建立一遍
var slf1 = new Person("slf1",24);
var slf2 = new Person("slf2",24);
複製代碼

上訴代碼 slf1,slf2都有getName()方法,可是兩個對象的getName()並非同一個Function對象。能夠將getName()提取出來到構造函數外部。

function Person(name,age){
    this.name = name;
    this.age = age;
    this.getName = getName;
}
function getName(){
    console.log(this.name)
}
//問題:做爲全局做用域的函數卻只有只被某個對象調用
複製代碼

原型模式

每建立的一個函數都有一個prototype屬性,該屬性爲指針,指向一個對象,該對象有一個constructor屬性,即

console.log(Person.prototype.constructor==Person)//true
複製代碼

而建立的函數又是Function的實例,也就是

console.log(Person._proto_==Function.prototype)//true
複製代碼

_proto_個人理解就是至關於找他們的爸爸

普通類型有_proto_屬性,引用類型有_proto_和prototype屬性,即

var abc = new Person("slf",24)
console.log(abc.__proto__ == Person.prototype)//true
console.log(abc.prototype) //undefined
複製代碼

原型模式和構造函數模式的不一樣在於不用在構造函數中定義對象實例的信息,能夠直接將這些信息添加到原型對象當中,即prototype中

function Person(){}
//這些屬性和方法被全部的實例共享
Person.prototype.name = "slf";
Person.prototype.age = 24;
Person.prototype.getName = function(){
    console.log(this.name);
}
var p1 = new Person();
p1.getName();//slf
var p2 = new Person();
console.log(p1.getName == p2.getName)//true
複製代碼

查找p1.getName()時候,先查找P1中是否有getName()方法,沒有,而後找p1.proto.getName
實例能夠訪問原型中的值,卻沒法改變原型當中的值,只能改寫原型當中的值,即

function Person(){}
//這些屬性和方法被全部的實例共享
Person.prototype.name = "slf";
Person.prototype.age = 24;
Person.prototype.getName = function(){
    console.log(this.name);
}
var p1 = new Person();
p1.getName();//slf
var p2 = new Person();
p2.name = "slf1"
p2.getName();//slf1
複製代碼

hasOwnProperty() 能夠檢驗一個屬性是存在原型中仍是實例中

p1.hasOwnProperty("name") //false
p2.hasOwnProperty("name") //true
複製代碼

in 不能夠檢驗一個屬性是存在原型中仍是實例中

("name" in p1) //true
("name" in p2) //true
複製代碼

判斷一個屬性存在對象中仍是原型中

function hasPrototypeProperty(object,name){
    return !object.hasOwnProperty(name)&&(name in object)
}
hasPrototypeProperty(p1,"name")//true 
hasPrototypeProperty(p2,"name")//false //存在實例中
複製代碼
  • 另一種原型語法
    至關於重寫整個原型對象,這個時候constructor再也不指向Person,instanceof 沒法肯定對象類型
function Person(){}
Person.prototype={
    name:"slf",
    age:24,
    getName:function(){
    console.log(this.name)
    }
}
複製代碼

若是要使用constructor

function Person(){}
Person.prototype={
    constructor:Person,
    name:"slf",
    age:24,
    getName:function(){
    console.log(this.name)
    }
}
複製代碼

這種方式會形成constructor能夠枚舉,enumerable=true

var p3 = new Person();
for(let i in p3){console.log(i)}
//constructor name age getName
複製代碼

可是原生的constructor不可枚舉

Object.defineProperty(Person.prototype,"constructor",{
    enumerable:false,
    value:Person
})
複製代碼
原型的動態

咱們對原型對象所作的任何修改都可以當即在實例中體現,即便先建立實例再修改原型。 可是若是重寫Person.prototype就不會了

  • 缺點:對於引用類型,由於屬性值共享,當某個實例修改屬性,全部實例的該屬性值都會被改變。
function Person(){}
Person.prototype={
    constructor:Person,
    name:"slf",
    friends:["s","l"],
    age:24,
    getName:function(){
    console.log(this.name)
    }
}
var p1 = new Person();
var p2 = new Person();
p1.friends.push("f");
p1.friends//["s","l","f"]
p2.friends//["s","l","f"]
複製代碼

組合使用構造函數模式和原型模式

構造模式用於定義屬性,原型模式用於定義方法和共享屬性,這樣每一個實例屬性都有本身的一份實例屬性副本,但又能夠共享方法的引用,節約內存
複製代碼
function Person(name,age){
    //屬性
    this.name = name;
    this.age = age;
    this.friends = ["s","l"],
}
Person.prototype={
constructor:Person,
getName : function(){
        return this.name;
    }
}
var p1 = new Person("slf1",22);
var p2 = new Person("slf2",23);
p1.friends.push("f");
p1.friends//["s","l","f"]
p2.friends//["s","l"]
p1.getName == p2.getName //true
複製代碼

動態原型模式

經過判斷某個方法是否有效,決定是否要初始化原型
複製代碼
function Person(name,age){
    //屬性
    this.name = name;
    this.age = age;
    this.friends = ["s","l"],
    //只有初次調用構造函數纔會執行
    if(typeof this.getName !='function'){
        Person.prototype.getName= function(){
            return this.name;
        }
    }
}
複製代碼

寄生構造函數模式

建立一個封裝建立對象,返回新建立對象的函數
複製代碼
function Person(name,age){
    var  o = new Object();
    o.name = name;
    o.age = age;
    o.getName =  function(){
    return this.name;
    }
    return o;
}
var p1 = new Person("slf",24);
複製代碼

這個模式的用法,建立一個具備額外方法的特殊數組,但不直接修改Array函數

function SpecialArray(){
    var values = new Array();
    //添加值
    values.push.apply(values,arguments);
    //添加方法
    values.toPipedString = function(){
        return this.join("|");
    };
    return values
}
var names = new SpecialArray("s","l","f");
names.toPipedString();//s|l|f
複製代碼

構造函數返回的對象與構造函數外部建立的對象沒有什麼不一樣,不能用instanceof肯定對象類型

穩妥構造函數模式

1.建立對象實例不用this. 
2.不能使用new操做符調用構造函數
複製代碼
function Person(name,age){
    var  o = new Object(); 
    o.getName =  function(){
    return name;
    }
    return o;
}
var p1 = Person("slf",24);
複製代碼
相關文章
相關標籤/搜索