js對象(一)——建立對象

首先是對“對象”的明白:

對象是一組沒有特定屬性的值,對象的每一個屬性或要領都有一個名字,而每一個名字都映射到一個值,其中值可所以數據或函數。每一個對象都是基於一個援用範例建立的,這個援用範例可所以原生範例,也可所以開發人員自定義的範例。——高程

(好的,這裏說的比較不容易明白)

(不急,接下來再看)

JavaScript中,統統都是對象,函數也是對象,數組也是對象,然則數組是對象的子集,而關於函數來講,函數與對象之間有一種“雞生蛋蛋生雞”的關聯。

統統的對象都是由Object繼承而來,而Object對象倒是一個函數。對象都是由函數來建立的。

比方,在控制台中
輸入 typeof Object 效果是”function”,
輸入 typeof Function 效果照樣”function”.
《js對象(一)——建立對象》

(好的,是不是是更懵逼了,不急,如今先看一下如何建立對象以及種種要領的孰優孰劣)

建立對象

0. 最基本的情勢:

var box=new Object(); //建立一個 Object 對象
box.name='Lee'; //建立一個 name 屬性並賦值
box.age= 100; //建立一個 age 屬性並賦值
box.run= function(){ //建立一個run()要領並返回值 
 return this.name + this.age; 
}; 
console.log(box.run()); //輸出屬性和要領的值

優瑕玷:

  • 長處:簡樸
  • 瑕玷:發生大批代碼,封裝性差

1.工場情勢:

fuction creatPerson(name,age,job){
 var  o = new Object();  //建立對象
 o.name = name;   //增加屬性
 o.age = age;
 o.job = job;
 o.sayName = function(){  //增加要領
 console.log(this.name);
 }
  return o; //返回對象援用
}

var person1 = creatPerson("Nicholas",29,"engineer");//實例化
var person2 = creatPerson("Mike",28,"teacher");

優瑕玷:

  • 長處:處理了建立多個類似對象的題目.
  • 瑕玷:但卻沒有處理對象辨認題目,即如何曉得一個對象的範例。也就是,由於基礎沒法搞清楚他們究竟是哪一個對象的實例(這個能夠和下面的組織函數情勢刁難照)

2.組織函數情勢

function Person(name,age,job){  
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
      console.log(this.name);
   }
}

//或
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;//注重這裏不要寫括號,要完成援用地點一致
}
function sayName(){
    console.log(this.name);
    
}//這裡是在表面寫一個,但這類要領會有作用域題目,異常不引薦
 var person1 = new Person("Nicholas",29,"Engineer");//平常如許實例化
 
 var o = new Object;;
 Person.call(o,"Kkresten",25,"Nurse");//對象假裝法實例化

辨別:

  • 沒有寫出new Object,然則背景會自動 var obj = new Object,而this就相當於obj
  • 沒有 renturn 語句,在背景返回

範例

  • 函數名和實例化組織名雷同且大寫(非強迫,重要是為了和一般函數辨別開來)
  • 經由過程組織函數建立對象,必需運用 new 運算符

優瑕玷

  • 長處: 建立自定義的組織範例意味着未來能夠將它的實例標識為一種特定的範例,(能夠用instanceof 來考證),即可辨認(這裏就能夠和上面工場情勢刁難照了,這也是比工場情勢更強的處所)
  • 瑕玷:每一個要領都要在每一個實例上建立一遍,大可沒必要(當函數在內部時),

全局作用域中定義的函數只能被某個對象挪用,這讓全局作用域有點有名無實,而且,假如對象需要定義許多要領,那末就要定義許多個全局函數,因而,這個自定義的援用範例就涓滴沒有封可言了(函數定義在外部時)。(所以函數在內部和外部都有瑕玷)

(好的,學到這裏,你已大致控制了如何建立一個對象,接下來將最先進修建立對象嵬峨上的要領和觀點)

3. 原型情勢

我們建立的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,(屬性值是對象)而這個對象的用處是包括能夠由特定範例的統統實例同享的屬性和要領。:prototype 經由過程 挪用組織函數而建立的誰人對象的原型對象。運用原型的優點能夠讓統統對象實例同享它所包括的屬性和要領。也就是說,沒必要在組織函數中定義對象信息,而是能夠直接將這些信息 增加到原型中。———高程

(好的,又回到了懵逼的狀況了,不急,先經由過程例子和圖來相識一下先)

 function Person(){//組織函數
}

Person.prototype.name = "Nicholas";//增加原型屬性
Person.prototype.age = 29;
Person.prototype.job = "software Engineer";
Person.prototype.sayName = function() {//增加原型要領
   console.log(this.name);
}

var person1 = new Person(); //實例化
person1.sayName(); //“Nicholas”
var person2 = new Person(); //實例化
person2.sayName();//"Nicholas"

如下圖:
《js對象(一)——建立對象》
《js對象(一)——建立對象》

而我本身畫了個圖來加深一下熟悉(連繫高程里的那段話)
《js對象(一)——建立對象》
(是不是是有點懂了,接下來再逐一仔細分析)

1.關於[[Prototype]]

  • 每一個對象都有一個如許的隱蔽屬性,它援用了建立這個對象的函數的prototype原型對象,我們來看一張圖:

《js對象(一)——建立對象》
注重:函數也是對象,天然它也有__proto__。
在控制台中,我們發明:
《js對象(一)——建立對象》

即函數的__proto__是函數範例。(也就說函數的原型對象是函數,而函數也是對象,所以函數的原型照樣對象)(這裏聽着有點繞,然則能夠先跳過)

還要注重一個慣例,如下圖:
《js對象(一)——建立對象》

這裏,統統對象繼承自Object,而我們又曉得Object.prototype是它的原型對象,是一個對象,然則這個對象的__proto__卻為null,是不是申明構建Object對象的函數沒有原型對象,由於對象都是由函數建立的

(關於函數與對象的關聯和涉及到的原型鏈的相干學問,還挺大挺深的,將零丁作為一個話題來議論。假如這裡有點看得暈,能夠先只是曉得prototype是什麼就能夠了)

注重: __proto__這個指針沒有規範的要領接見,IE 瀏覽器在劇本接見[[Prototype]]會不能辨認,火狐和谷歌瀏覽器及其他某些瀏覽器均能辨認。雖然能夠輸出,但沒法獵取內部信息。([[Prototype]] 也可寫為__proto__)雖然沒法接見到,然則能夠經由過程: Object.isPrototypeOf(person1)推斷這個實例對象是不是指向它的原型對象 ;而我們也曉得Person.prototype就是Object範例,即一個原型對象

//承接上面的代碼
Person.prototype.isPrototypeOf(person1);//true
Person.prototype.isPrototypeOf(person2);//true

2.關於原型情勢的實行流程:

①先搜檢這個對象本身有沒有這個屬性;假如有,直接運用它。

②假如沒法在對象本身找到需要的屬性,就會繼承接見對象的[[Prototype]]鏈,找到則直接運用,不再查找下去;假如一向找不到,末了就會返回undefined

3.能夠經由過程 hasOwnProperty()要領檢測屬性是不是存在實例中,也能夠經由過程 in 來推斷 實例或原型中是不是存在屬性;能夠經由過程Object.keys()要領或Object.getOwnPropertyNames()來獲得實例屬性,詳細見高程。

4.優瑕玷:每增加一個屬性和要領就要敲一遍Person.prototype,而且視覺上說封裝性不夠好。固然長處就是處理了上面組織函數的題目。

5.更簡樸的原型情勢

 function Person(){
}
 Person.prototype = {  //將 Person.prototype 設置為即是一個以對象字面量情勢建立的新對象
    name : "Nicholas",
    age:  29,
    job:  "software Engineer",
    sayName : function() {
       console.log(this.name);
    }
 }
//(但constructor屬性不再指向Person了,而是指向Object組織函數)
//但能夠如許手動設置:
 function Person(){
}
 Person.prototype = {  
    constructor : Person,//手動設置
    name : "Nicholas",
    age: 29,
    job:  "software Engineer",
    sayName : function() {
       console.log(this.name);
    }
 }
//由於按上面的體式格局會致使它的[[Enumerable]]特徵被設置為true,所以還能夠像下面如許
 function Person(){
}
 Person.prototype = {  
    name : "Nicholas",
    age: 29,
    job:  "software Engineer",
    sayName : function() {
       console.log(this.name);
    }
 }
Object.definePrototype(Person.prototype,"constructor"),{
   enumerable :  false;
   value : Person
  }
}

6.原型的動態性:

//承接上面的Person組織函數
var friend = new Person();
Person.prototype.sayhi = function(){
    alert("hi");
};
friend.sayhi(); //"hi"沒有題目,雖然是在實例以後增加的屬性,然則依據原型情勢的搜刮機制,會找到原型中的這個要領,緣由:實例與原型是鬆懈銜接的
//然則:假如是如許:
 function Person(){
}
 var friend = new Person();
 Person.prototype = {  
    name : "Nicholas",
    age:  29,
    job:  "software Engineer",
     sayName : function() {
       console.log(this.name);
    }
 }
 friend.sayName();//Uncaught TypeError: friend.sayName is not a function,雖然有將重寫的原型的指針指向Person原型對象,然則很實際上卻如下圖:

《js對象(一)——建立對象》

6.優瑕玷:

  • 長處:處理了組織函數湧現的題目(壯大的範例辨認)
  • 瑕玷:同享了援用範例的值,這個就是很少有人零丁運用原型情勢的緣由。比方下面:
 function Person(){
}
 Person.prototype = {  
    constructor : Person,
    name : "Nicholas",
    age:  29,
    job:  "software Engineer",
    friend:["Mike","Jeny"],
    sayName : function() {
       console.log(this.name);
     }
}
var person1 = new Person();
var person2 = new Person();
person1.friend.push("Van");
console.log(person1.friend);//"Mike,Jeny,Van"
console.log(person2.friend);//"Mike,Jeny,Van"

4.組合運用組織函數和原型情勢

 function Perosn(name,age,job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.friends = ["Shelby","Court'];
}
Person.prototype = {
 constructor : Person,
 sayName : function(){
    console.log(this.name);
  }
}
var person1 = new Person("Nicholas",29," Engineer");

優瑕玷:

  • 長處:處理了援用範例實例同享的題目
  • 瑕玷:封裝性不夠好

## 5.動態原型情勢 ##

function Person(name,age,job){
//屬性
    this.name = name; 
    this.age = age;
    this.job = job;
//要領
if(typeof this.sayname != "function"){
  Person.prototype.sayname = function(){
   console.log(this.name);//只要在sayName要領不存在的狀況下才會被增加到原型中
  }
}
//這段代碼在首次挪用組織函數時才會實行,今後,原型已初始化
var friend  = new Person("Nicholas",29,"Engineer");

優瑕玷:

  • 長處:既獲得了封裝,又完成了原型要領同享,而且屬性都堅持自力。能夠說是異常完美了,實在說白了這類要領就是處理上面組織函數的要領不需要每次都建立一遍的題目。
  • 瑕玷:不能運用對象字面量重寫原型,會使之前定義的原型對象的要領失效。

(好了,學到這裏,也許經常使用的建立對象的要領就已控制了,接下來另有兩種不經常使用的要領能夠相識一下)

6.寄生組織函數情勢

function Person(name,age,job){
 var o  = new Object();
 o.name = name;
 o.age = age;
 o.job = job;
 o.sayName = function(){
    console.log(this.name);
  }
  return o;
}
var friend = new Person("Nicholas",29,"Software Engineer");

function SpecialArray(){
//建立數組
var values = new Array();
//用push要領初始化數組的值
values.push.apply(values,arguments);
//增加要領
values.toPipedString = function(){
 return this.join("|");
}
//返回數組
 return values;
}
var colors = new SpecialArray("red","blue","green");
console.log(colors.toPipedString()); //"red|blue|green"

優瑕玷:

  • 組織函數返回的對象與在組織函數外部建立的對象沒有什麼差別,為此不能依靠instanceof操作符來肯定對象的範例:
console.log(friend instanceof Person) // false

因而,能夠運用其他情勢的狀況下不運用此範例

7.穩妥組織函數情勢

function Person(name,age,job){
 //建立要返回的對象
 var o = new Object();
//能夠在這裏定義私有變量和函數
//增加要領
 o.sayName = function(){
 console.log(name);
 }
//返回對象
  return o;
}
var friend =  Person("Nicholas",29,"Software Engineer");
friend.sayName();

辨別:

  • 不援用this的對象
  • 不運用new操作符

長處:平安

(好了,js對象的建立就也許有這幾種要領,實在最經常使用的貌似照樣組織函數的情勢,然則原型相干的東西也是必需要控制的)

末了,迎接人人圍觀斧正!

參考:《javascript高等程序設計》

    原文作者:Rimin
    原文地址: https://segmentfault.com/a/1190000014958715
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞