搜尋
首頁web前端js教程Javascript基礎回顧之(三) js面向對象

本來是要繼續由淺入深表達式系列最後一篇的,但是最近團隊突然就忙起來了,從來沒有過的忙!不過喜歡表達式的朋友請放心,已經在寫了:) 在工作當中發現大家對Javascript的一些基本原理普遍存在這裡或者那裡的一知半解,所以決定先花一些時間整理一下這些基礎知識和大家分享。 後面會附上培訓用的PPT。剛開始打算寫一篇的,但後來寫著寫著就發現越來越多,所以決定還是寫一個系列吧。這個系列所有內容都是涉及Javascript基礎的,沒有時髦的玩意兒,但是我相信這些基礎的東西會有助於你理解那些有趣的東西的。

  本篇是你必須知道的Javascript系列第三篇,我們主要來看看Javascript是如何面向對象的程式設計的。主要涉及以下內容:

Javascript中的物件

什麼是物件

遍歷屬性

創建物件

工廠模式

構造函數

創建物件

工廠模式

構造函數在構造函數中

在call和apply中

在bind中

在dom元素事件處理函數中

詳解prototype

什麼是原型

鏈是原型繼承鏈是原型鏈鏈中的問題

Javascript中的物件

什麼是物件

我們可以把Javascript中物件理解為一組無序的鍵值對,就好像C#中的Dictionary一樣。 Key是屬性的名稱,而value可以是以下3種類型:

基本值(string, number, boolean, null, undefined)

物件

函數

var o = new Object();
o["name"] = "jesse"; //基本值作为对象属性
o["location"] = {   //对象作为对象属性
  "city": "Shanghai",
  "district":"minhang"
};
 
// 函数 作为对象属性
o["sayHello"] = function () {
  alert("Hello, I am "+ this.name + " from " + this.location.city);
}
 
o.sayHello();

㟎可以用foreach對Dictionary進行遍歷的,如果說物件在Javascript中是一組鍵值對的話,那我們要如何進行遍歷呢?

for (var p in o) {
  alert('name:'+ p +
     ' type:' + typeof o[p]
    );
}
// name:name type:string
// name:location type:object
// name:sayHello type:function

上面的這種遍歷方式會把原型中的屬性也包括進來,關於什麼是原型,以及如何區分原型和實例中的屬性我們下面會講到。

創建對象

  其實在上面我們已經創建了一個對象,並且使用了以下兩種創建對象的方式。

利用new建立一個Object的實例。

字面量

我們上面的o是用第一種方式創建的,而o中的location屬性則是用字面量的方式創建的。而第一種方式其實也有一個名字叫做建構子模式,因為Object其實就是一個建構函數,為我們產生了一個Object的實例。如果對於建構函式這一塊還有不清楚的話,趕快去看我的第一篇 型別基礎Object與object吧。

  除了以上兩種方式以外,我們一些創建對象的方式,我們也來一起看一下:

工廠模式

function createPerson(name, age, job){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
    alert(this.name);
  };
  return o;
}
var person1 = createPerson('Jesse', 29, 'Software Engineer');
var person2 = createPerson('Carol', 27, 'Designer');

這種模式創建的對像有一個問題,那就是它在函數的內部為我建立了一個Object的實例,這個實例跟我們的建構子createPerson是沒有任何關係的。

因為我在內部用new Object()來創建了這個對象,所以它是Object的實例。所以如果我們想知道它是具體哪個function的實例,那就不可能了。

建構函數模式

  工廠模式沒有解決物件辨識的問題,但是我們可以想一下,Object()其實也是一個函數,只不過當我在它前面加上一個new的時候,它就變成了一個建構函式為我們產生一個Object的實例。那我同樣也可以在其它函數前面加上new這樣就可以產生這個函數的實例了,這就是所謂的建構子模式。

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function(){
    alert(this.name);
  };
}
 
var p1 = new Person('Jesse', 18, 'coder');
alert(p1 instanceof Person); // true

詳解thisJavascript基础回顾之(三) js面向对象  this在Javascript中也可以算是一個很神奇對象,沒錯this是一個對象。我們在上一篇作用域和作用域鏈中講到了變數對象,變數對象決定了在當前的執行環境中有哪些屬性和函數是可以被存取的,從某種程度上來說我們就可以把this看作是這個變數物件。我們之前提到了最大的執行環境是全域執行環境,而window就是全域執行環境中的變數對象,那麼我們在全域環境中this===window是會回傳true的。

除了全域執行環境以外,我們也提到了另一個執行環境,也就是函數。每一個函數都有一個this對象,但有時候他們所代表的值是不一樣的,主要是由這個函數的呼叫者來決定的。讓我們來看看以下幾個場景:

函數

function f1(){
 return this;
}
 
f1() === window; // global object

因为当前的函数在全局函数中运行,所以函数中的this对象指向了全局变量对象,也就是window。这种方式在严格模式下会返回undefined。

对象方法

var o = {
 prop: 37,
 f: function() {
  return this.prop;
 }
};
 
console.log(o.f()); // logs 37

在对象方法中,this对象指向了当前这个实例对象。注意: 不管这个函数在哪里什么时候或者怎么样定义,只要它是一个对象实例的方法,那么它的this都是指向这个对象实例的。

var o = { prop: 37 };
var prop = 15;
 
function independent() {
  return this.prop;
}
 
o.f = independent;
console.log(independent()); // logs 15
console.log(o.f()); // logs 37

区别:上面的函数independent如果直接执行,this是指向全局执行环境,那么this.prop是指向我们的全局变量prop的。但是如果将independent设为对象o的一个属性,那么independent中的this就指向了这个实例,同理this.prop就变成了对象o的prop属性。

构造函数

  我们上面讲到了用构造函数创建对象,其实是利用了this的这种特性。在构造函数中,this对象是指向这个构造函数实例化出来的对象。

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    alert(this.name);
  };
}
 
var p1 = new Person('Jesse', 18, 'coder');
var p2 = new Person('Carol',16,'designer');

当我们实例化Person得到p1的时候,this指向p1。而当我们实例化Person得到p2的时候,this是指向p2的。

利用call和apply

  当我们用call和apply去调用某一个函数的时候,这个函数中的this对象会被绑定到我们指定的对象上。而call和apply的主要区别就是apply要求传入一个数组作为参数列表。

function add(c, d) {
  return this.a + this.b + c + d;
}
 
var o = { a: 1, b: 3 };
 
// 第一个参数会被绑定成函数add的this对象
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
 
// 第二个参数是数组作为arguments传入方法add
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

在bind方法中

  bind方法是 存在于function的原型中的 Function.prototype.bind,也就是说所有的function都会有这个方法。但我们调用某一个方法的bind的时候,会产生一个和原来那个方法一样的新方法,只不过this是指向我们传得bind的第一个参数。

function f() {
  return this.a;
}
 
var g = f.bind({ a: "azerty" });
console.log(g()); // azerty
 
var o = { a: 37, f: f, g: g };
console.log(o.f(), o.g()); // 37, azerty

在dom元素事件处理器中

  在事件处理函数中,我们的this是指向触发这个事件的dom元素的。

HTML代码

<html>
<body>
  <div id="mydiv" style="width:400px; height:400px; border:1px solid red;"></div>
  <script type="text/javascript" src="essence.js"></script>
</body>
</html>

JavaScript代码

function click(e) {
  alert(this.nodeName);
}
 
var myDiv = document.getElementById("mydiv");
myDiv.addEventListener(&#39;click&#39;, click, false);

当我们点击页面那个div的时候,毫无疑问,它是会显示DIV的。

Javascript基础回顾之(三) js面向对象

详解prototype
  prototype即原型,也是Javascrip中一个比较重要的概念。在说原型之前呢,我们需要回顾一下之前的构造函数模式。在我们用构造函数去创建对象的时候主要是利用了this的特性。

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    alert(this.name);
  };
}
 
var p1 = new Person(&#39;Jesse&#39;, 18, &#39;coder&#39;);
var p2 = new Person(&#39;Carol&#39;, 17, &#39;designer&#39;);

我们上面还讲到了当用Person实例化p1的时候Person中的this是指向p1的,当实例化p2的时候呢,this是指向p2的。那也就是说,p1和p2中的sayName虽然起到了同样的作用,但是实际上他们并非是一个函数。

Javascript基础回顾之(三) js面向对象

也就是说他们内存堆中是存在多份拷贝的,而不是在栈中引用地址的拷贝。先不说这符不符合面向对象的思想,至少这对于内存来说也是一种浪费。而解决办法就是我们要讨论的原型。

什么是原型

  在Javascript中的每一个函数,都会有一个原型对象,这个原型对象和我们普通的对象没有区别。只不过默认会有一个constructor属性指向这个函数。 同时,所有这个函数的实例都会有一个引用指向这个原型对象。如果不太清楚,那就看看下面这张图吧:

Javascript基础回顾之(三) js面向对象

以上就是构造函数,构造函数原型,以及实例之间的关系。以我们的Person构造函数为例,所有Person的实例(p1,p2)都舒服一个prototype属性指向了Person构造函数prototype对象。如此一来,我们就可以把方法写在原型上,那么我们所有的实例就会访问同一个方法了。

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
 
  Person.prototype.sayName = function () {
    alert(this.name);
  }
}
var p1 = new Person(&#39;Jesse&#39;, 18, &#39;coder&#39;);
var p2 = new Person(&#39;Carol&#39;, 17, &#39;designer&#39;);
 
alert(p1.sayName == p2.sayName); // true

   

什么是原型链

  大家还记得作用域链么?如果不记得,请自觉到第二篇中去复习(作用域和作用域链)。简单的来说,我们在一个执行环境中访问某个变量的时候如果当前这个执行环境中不存在这个变量,那么会到这个执行环境的包含环境也就是它的外层去找这个变量,外层还找不到那就再外一层,一直找到全局执行环境为止,这就是作用域链。而原型链有点类型,只不过场景换到了我们的对象实例中,如果我在一个实例中找某一个属性,这个实例中没有,那就会到它的原型中去找。记住,我们上面说了,原型也是一个对象,它也有自己的原型对象,所以就行成了一个链,实例自己的原型中找不到,那就到原型的原型对象中去找,一直向上延伸到Object的原型对象,默认我们创建的函数的原型对象它自己的原型对象是指向Object的原型对象的,所以这就是为什么我们可以在我们的自定义构造函数的实例上调用Object的方法(toString, valueOf)。

Javascript基础回顾之(三) js面向对象

利用原型实现继承

  其实我们上面已经讲了继承在Javascript中的实现,主要就是依靠原型链来实现的。所有的实例是继承自object就是因为在默认情况下,我们所有创建函数的原型对象的原型都指向了object对象。同理,我们可以定义自己的继承关系。

function Person(name, age, job) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function () {
  alert(this.name);
}
 
function Coder(language){
  this.language = language;
}
Coder.prototype = new Person(); //将 Coder 的原型指向一个Person实例实现继Person
Coder.prototype.code = function () {
  alert(&#39;I am a &#39;+ this.language +&#39; developer, Hello World!&#39;);
}
 
function Designer() {
}
Designer.prototype = new Person(); //将 Desiger 的原型指向一个Person实例实现继Person
Designer.prototype.design = function () {
  alert(&#39;其实我只是一个抠图工而已。。。。&#39;);
}
 
var coder = new Coder(&#39;C#&#39;);
coder.name = &#39;Jesse&#39;;
coder.sayName(); //Jesse
coder.code();   // I am a C# developer, Hello World!
 
var designer = new Designer();
designer.name = &#39;Carol&#39;;
designer.sayName(); // Carol
designer.design();  // 其实我只是一个抠图工而已。。。。

   

原型链中的问题

  由于原型对象是以引用的方式保存的,所以我们在赋值的时候要特别注意,一不小心就有可能把之前赋的值给赋盖了。比如上面的代码中,我们先写原型方法,再实现继承,那我们的原型方法就没有了。

function Coder(language){
  this.language = language;
}
Coder.prototype.code = function () {
  alert(&#39;I am a &#39;+ this.language +&#39; developer, Hello World!&#39;);
}
Coder.prototype = new Person(); //这里会覆盖上面所有的原型属性和方法
var coder = new Coder(&#39;C#&#39;);
coder.name = &#39;Jesse&#39;;
coder.sayName();
coder.code();   // 这里会报错,找不到code方法。

这样三篇文章都完成了

更多Javascript基础回顾之(三) js面向对象相关文章请关注PHP中文网!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。