您好,登錄后才能下訂單哦!
這篇“JavaScript面向對象的思維特點是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript面向對象的思維特點是什么”文章吧。
面向對象更貼近我們的實際生活, 可以使用面向對象描述現實世界事物. 但是事物分為具體的事物和抽象的事物
面向對象的思維特點:
抽取(抽象)對象共用的屬性和行為組織(封裝)成一個類(模板)
對類進行實例化, 獲取類的對象
在 JavaScript 中,對象是一組無序的相關屬性和方法的集合,所有的事物都是對象,例如字符串、數值、數組、函數等。
對象是由屬性和方法組成的
屬性:事物的特征,在對象中用屬性來表示
方法:事物的行為,在對象中用方法來表示
在 ES6 中新增加了類的概念,可以使用 class 關鍵字聲明一個類,之后以這個類來實例化對象。
類抽象了對象的公共部分,它泛指某一大類(class)
對象特指某一個,通過類實例化一個具體的對象
class name { // class body}
創建實例
var XX = new name();
注意:類必須使用new
實例化對象
constructor()方法是類的構造函數(默認方法),用于傳遞參數,返回實例對象,通過 new 命令生成對象實例時,自動調用該方法。如果沒有顯示定義, 類內部會自動給我們創建一個constructor()
<script> // 1. 創建類 class 創建一個 明星類 class Star { // constructor 構造器或者構造函數 constructor(uname, age) { this.uname = uname; this.age = age; } } // 2. 利用類創建對象 new var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 20); console.log(ldh); console.log(zxy);</script>
通過 class 關鍵字創建類,類名我們還是習慣性定義首字母大寫
類里面有個 constructor
函數,可以接收傳遞過來的參數,同時返回實例對象
constructor
函數只要 new 生成實例時,就會自動調用這個函數,如果我們不寫這個函數,類也會自動生成這個函數
最后注意語法規范
創建類?類名后面不要加小括號
生成實例?類名后面加小括號
構造函數不需要加 function 關鍵字
語法:
class Person { constructor(name,age) { // constructor 稱為構造器或者構造函數 this.name = name; this.age = age; } say() { console.log(this.name + '你好'); }} var ldh = new Person('劉德華', 18); ldh.say()
注意: 方法之間不能加逗號分隔,同時方法不需要添加 function 關鍵字。
<script> // 1. 創建類 class 創建一個 明星類 class Star { // 類的共有屬性放到 constructor 里面 constructor(uname, age) { this.uname = uname; this.age = age; } sing(song) { console.log(this.uname + song); } } // 2. 利用類創建對象 new var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 20); console.log(ldh); console.log(zxy); // (1) 我們類里面所有的函數不需要寫function // (2) 多個函數方法之間不需要添加逗號分隔 ldh.sing('冰雨'); zxy.sing('李香蘭');</script>
類的共有屬性放到constructor
里面
類里面的函數都不需要寫 function
關鍵字
現實中的繼承:子承父業,比如我們都繼承了父親的姓。
程序中的繼承:子類可以繼承父類的一些屬性和方法。
語法:
// 父類class Father { }// 子類繼承父類class Son extends Father { }
看一個實例:
<script> // 父類有加法方法 class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } // 子類繼承父類加法方法 同時 擴展減法方法 class Son extends Father { constructor(x, y) { // 利用super 調用父類的構造函數 // super 必須在子類this之前調用 super(x, y); this.x = x; this.y = y; } subtract() { console.log(this.x - this.y); } } var son = new Son(5, 3); son.subtract(); son.sum();</script>
super
關鍵字用于訪問和調用對象父類上的函數,可以調用父類的構造函數,也可以調用父類的普通函數
語法:
// 父類class Person { constructor(surname){ this.surname = surname; }}// 子類繼承父類class Student entends Person { constructor(surname,firstname) { super(surname); //調用父類的 constructor(surname) this.firstname = firstname; //定義子類獨有的屬性 }}
注意:子類在構造函數中使用super,必須放到this前面(必須先調用父類的構造方法,在使用子類構造方法)
案例:
// 父類class Father { constructor(surname){ this.surname = surname; } saySurname() { console.log('我的姓是' + this.surname); }}// 子類繼承父類class Son entends Father { constructor(surname,firstname) { super(surname); //調用父類的 constructor(surname) this.firstname = firstname; //定義子類獨有的屬性 } sayFirstname() { console.log('我的名字是:' + this.firstname); }}var damao = new Son('劉','德華');damao.saySurname();damao.sayFirstname();
語法:
class Father { say() { return '我是爸爸'; }}class Son extends Father { say(){ // super.say() super調用父類的方法 return super.say() + '的兒子'; }}var damao = new Son();console.log(damao.say());
多個方法之間不需要添加逗號分隔
繼承中屬性和方法的查找原則:就近原則,先看子類,再看父類
在ES6中類沒有變量提升,所以必須先定義類,才能通過類實例化對象
類里面的共有屬性和方法一定要加 this
使用
類里面的this
指向:
constructor 里面的 this
指向實例對象
方法里面的this
指向這個方法的調用者
<body> <button>點擊</button> <script> var that; var _that; class Star { constructor(uname, age) { // constructor 里面的this 指向的是 創建的實例對象 that = this; this.uname = uname; this.age = age; // this.sing(); this.btn = document.querySelector('button'); this.btn.onclick = this.sing; } sing() { // 這個sing方法里面的this 指向的是 btn 這個按鈕,因為這個按鈕調用了這個函數 console.log(that.uname); // that里面存儲的是constructor里面的this } dance() { // 這個dance里面的this 指向的是實例對象 ldh 因為ldh 調用了這個函數 _that = this; console.log(this); } } var ldh = new Star('劉德華'); console.log(that === ldh); ldh.dance(); console.log(_that === ldh); // 1. 在 ES6 中類沒有變量提升,所以必須先定義類,才能通過類實例化對象 // 2. 類里面的共有的屬性和方法一定要加this使用. </script></body>
在典型的 OOP 的語言中(如 Java),都存在類的概念,類就是對象的模板,對象就是類的實例,但在 ES6之前, JS 中并沒用引入類的概念。
ES6, 全稱 ECMAScript 6.0 ,2015.06 發版。但是目前瀏覽器的 JavaScript 是 ES5 版本,大多數高版本的瀏覽器也支持 ES6,不過只實現了 ES6 的部分特性和功能。
在 ES6之前 ,對象不是基于類創建的,而是用一種稱為構建函數的特殊函數來定義對象和它們的特征。
創建對象有三種方式
對象字面量
new Object()
自定義構造函數
// 1. 利用 new Object() 創建對象var obj1 = new Object();// 2. 利用對象字面量創建對象var obj2 = {};// 3.利用構造函數創建對象function Star(uname,age) { this.uname = uname; this.age = age; this.sing = function() { console.log('我會唱歌'); }}var ldh = new Star('劉德華',18);
注意:
構造函數用于創建某一類對象,其首字母要大寫
構造函數要和new
一起使用才有意義
構造函數是一種特殊的函數,主要用來初始化對象(為對象成員變量賦初始值),它總與new
一起使用
我們可以把對象中的一些公共的屬性和方法抽取出來,然后封裝到這個函數里面
new 在執行時會做四件事
在內存中創建一個新的空對象。
讓 this 指向這個新的對象。
執行構造函數里面的代碼,給這個新對象添加屬性和方法。
返回這個新對象(所以構造函數里面不需要 return )。
JavaScript 的構造函數中可以添加一些成員,可以在構造函數本身上添加,也可以在構造函數內部的this
上添加。通過這兩種方式添加的成員,就分別稱為靜態成員和實例成員。
靜態成員:在構造函數本身上添加的成員為靜態成員,只能由構造函數本身來訪問
實例成員:在構造函數內部創建的對象成員稱為實例成員,只能由實例化的對象來訪問
// 構造函數中的屬性和方法我們稱為成員,成員可以添加 function Star(uname,age) { this.uname = uname; this.age = age; this.sing = function() { console.log('我會唱歌'); } } var ldh = new Star('劉德華',18); // 實例成員就是構造函數內部通過this添加的成員 uname age sing 就是實例成員 // 實例成員只能通過實例化的對象來訪問 ldh.sing(); Star.uname; // undefined 不可以通過構造函數來訪問實例成員 // 靜態成員就是在構造函數本身上添加的成員 sex 就是靜態成員 // 靜態成員只能通過構造函數來訪問 Star.sex = '男'; Star.sex; ldh.sex; // undefined 不能通過對象來訪問
構造函數方法很好用,但是存在浪費內存的問題。
我們希望所有的對象使用同一個函數,這樣就比較節省內存
構造函數通過原型分配的函數是所有對象所共享的,這樣就解決了內存浪費問題
JavaScript 規定,每一個構造函數都有一個prototype
屬性,指向另一個對象,注意這個prototype
就是一個對象,這個對象的所有屬性和方法,都會被構造函數所擁有
我們可以把那些不變的方法,直接定義在prototype
對象上,這樣所有對象的實例就可以共享這些方法
<body> <script> // 1. 構造函數的問題. function Star(uname, age) { //公共屬性定義到構造函數里面 this.uname = uname; this.age = age; // this.sing = function() { // console.log('我會唱歌'); // } } //公共的方法我們放到原型對象身上 Star.prototype.sing = function() { console.log('我會唱歌'); } var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 19); console.log(ldh.sing === zxy.sing); ldh.sing(); zxy.sing(); // 2. 一般情況下,我們的公共屬性定義到構造函數里面, 公共的方法我們放到原型對象身上 </script></body>
一般情況下,我們的公共屬性定義到構造函數里面, 公共的方法我們放到原型對象身上
問答:原型是什么?
一個對象,我們也稱為 prototype
為原型對象
問答:原型的作用是什么?
共享方法
對象都會有一個屬性 _proto_
指向構造函數的prototype
原型對象,之所以我們對象可以使用構造函數prototype
原型對象的屬性和方法,就是因為對象有_proto_
原型的存在。
_proto_
對象原型和原型對象 prototype
是等價的
_proto_
對象原型的意義就在于為對象的查找機制提供一個方向,或者說一條路線,但是它是一個非標準屬性,因此實際開發中,不可以使用這個屬性,它只是內部指向原型對象 prototype
Star.prototype 和 ldh._proto_
指向相同
<body> <script> function Star(uname, age) { this.uname = uname; this.age = age; } Star.prototype.sing = function() { console.log('我會唱歌'); } var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 19); ldh.sing(); console.log(ldh); // 對象身上系統自己添加一個 __proto__ 指向我們構造函數的原型對象 prototype console.log(ldh.__proto__ === Star.prototype); // 方法的查找規則: 首先先看ldh 對象身上是否有 sing 方法,如果有就執行這個對象上的sing // 如果沒有sing 這個方法,因為有 __proto__ 的存在,就去構造函數原型對象prototype身上去查找sing這個方法 </script></body>
對象原型(__ proto __)和構造函數(prototype)原型對象里面都有一個屬性constructor屬性, constructor 我們稱為構造函數,因為它指回構造函數本身。
constructor
主要用于記錄該對象引用于哪個構造函數,它可以讓原型對象重新指向原來的構造函數
一般情況下,對象的方法都在構造函數(prototype)的原型對象中設置
如果有多個對象的方法,我們可以給原型對象prototype
采取對象形式賦值,但是這樣會覆蓋構造函數原型對象原來的內容,這樣修改后的原型對象constructor
就不再指向當前構造函數了。此時,我們可以在修改后的原型對象中,添加一個constructor
指向原來的構造函數
具體請看實例配合理解
<body> <script> function Star(uname, age) { this.uname = uname; this.age = age; } // 很多情況下,我們需要手動的利用constructor 這個屬性指回 原來的構造函數 // Star.prototype.sing = function() { // console.log('我會唱歌'); // }; // Star.prototype.movie = function() { // console.log('我會演電影'); // } Star.prototype = { // 如果我們修改了原來的原型對象,給原型對象賦值的是一個對象,則必須手動的利用constructor指回原來的構造函數 constructor: Star, sing: function() { console.log('我會唱歌'); }, movie: function() { console.log('我會演電影'); } } var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 19); </script></body>
當訪問一個對象的屬性(包括方法)時,首先查找這個對象自身有沒有該屬性
如果沒有就查找它的原型(也就是_proto_
指向的prototype原型對象
)
如果還沒有就查找原型對象的原型(Object的原型對象)
依次類推一直找到Object為止(null)
__ proto __對象原型的意義就在于為對象成員查找機制提供一個方向,或者說一條路線。
<body> <script> function Star(uname, age) { this.uname = uname; this.age = age; } Star.prototype.sing = function() { console.log('我會唱歌'); } var ldh = new Star('劉德華', 18); // 1. 只要是對象就有__proto__ 原型, 指向原型對象 console.log(Star.prototype); console.log(Star.prototype.__proto__ === Object.prototype); // 2.我們Star原型對象里面的__proto__原型指向的是 Object.prototype console.log(Object.prototype.__proto__); // 3. 我們Object.prototype原型對象里面的__proto__原型 指向為 null </script></body>
構造函數中的 this
指向我們的實例對象
原型對象里面放的是方法,這個方法里面的this
指向的是這個方法的調用者,也就是這個實例對象
<body> <script> function Star(uname, age) { this.uname = uname; this.age = age; } var that; Star.prototype.sing = function() { console.log('我會唱歌'); that = this; } var ldh = new Star('劉德華', 18); // 1. 在構造函數中,里面this指向的是對象實例 ldh ldh.sing(); console.log(that === ldh); // 2.原型對象函數里面的this 指向的是 實例對象 ldh </script></body>
可以通過原型對象,對原來的內置對象進行擴展自定義的方法
比如給數組增加自定義求偶數和的功能
<body> <script> // 原型對象的應用 擴展內置對象方法 Array.prototype.sum = function() { var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return sum; }; // Array.prototype = { // sum: function() { // var sum = 0; // for (var i = 0; i < this.length; i++) { // sum += this[i]; // } // return sum; // } // } var arr = [1, 2, 3]; console.log(arr.sum()); console.log(Array.prototype); var arr1 = new Array(11, 22, 33); console.log(arr1.sum()); </script></body>
注意:
數組和字符串內置對象不能給原型對象覆蓋操作Array.prototype = {}
,只能是Array.prototype.xxx = function(){}
的方式
ES6 之前并沒有給我們提供extends
繼承
我們可以通過構造函數+原型對象模擬實現繼承,被稱為組合繼承
調用這個函數,并且修改函數運行時的 this 指向
fun.call(thisArg,arg1,arg2,......)
thisArg
:當前調用函數 this 的指向對象
arg1,arg2
: 傳遞的其他參數
示例
<body> <script> // call 方法 function fn(x, y) { console.log('我希望我的希望有希望'); console.log(this); // Object{...} console.log(x + y); // 3 } var o = { name: 'andy' }; // fn(); // 1. call() 可以調用函數 // fn.call(); // 2. call() 可以改變這個函數的this指向 此時這個函數的this 就指向了o這個對象 fn.call(o, 1, 2); </script></body>
核心原理: 通過 call()
把父類型的 this 指向子類型的 this,這樣就可以實現子類型繼承父類型的屬性
<body> <script> // 借用父構造函數繼承屬性 // 1. 父構造函數 function Father(uname, age) { // this 指向父構造函數的對象實例 this.uname = uname; this.age = age; } // 2 .子構造函數 function Son(uname, age, score) { // this 指向子構造函數的對象實例 Father.call(this, uname, age); this.score = score; } var son = new Son('劉德華', 18, 100); console.log(son); </script></body>
一般情況下,對象的方法都在構造函數的原型對象中設置,通過構造函數無法繼承父類方法
核心原理:
將子類所共享的方法提取出來,讓子類的 prototype 原型對象 = new 父類()
本質: 子類原型對象等于是實例化父類,因為父類實例化之后另外開辟空間,就不會影響原來父類原型對象
將子類的constructor
重新指向子類的構造函數
<body> <script> // 借用父構造函數繼承屬性 // 1. 父構造函數 function Father(uname, age) { // this 指向父構造函數的對象實例 this.uname = uname; this.age = age; } Father.prototype.money = function() { console.log(100000); }; // 2 .子構造函數 function Son(uname, age, score) { // this 指向子構造函數的對象實例 Father.call(this, uname, age); this.score = score; } // Son.prototype = Father.prototype; 這樣直接賦值會有問題,如果修改了子原型對象,父原型對象也會跟著一起變化 Son.prototype = new Father(); // 如果利用對象的形式修改了原型對象,別忘了利用constructor 指回原來的構造函數 Son.prototype.constructor = Son; // 這個是子構造函數專門的方法 Son.prototype.exam = function() { console.log('孩子要考試'); } var son = new Son('劉德華', 18, 100); console.log(son); console.log(Father.prototype); console.log(Son.prototype.constructor); </script></body>
class 本質還是 function
類的所有方法都定義在類的 prototype
屬性上
類創建的實例,里面也有_proto_
指向類的prototype
原型對象
所以 ES6 的類它的絕大部分功能,ES5都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。
所以 ES6 的類其實就是語法糖
語法糖:語法糖就是一種便捷寫法,簡單理解
ES5 給我們新增了一些方法,可以很方便的操作數組或者字符串
數組方法
字符串方法
對象方法
迭代(遍歷)方法:foreach() ,map(),filter(),some() ,every() ;
array.forEach(function(currentValue,index,arr))
currentValue: 數組當前項的值
index: 數組當前項的索引
arr: 數組對象本身
<body> <script> // forEach 迭代(遍歷) 數組 var arr = [1, 2, 3]; var sum = 0; arr.forEach(function(value, index, array) { console.log('每個數組元素' + value); console.log('每個數組元素的索引號' + index); console.log('數組本身' + array); sum += value; }) console.log(sum); </script></body>
array.filter(function(currentValue,index,arr))
filter()
方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素,主要用于篩選數組
注意它直接返回一個新數組
<body> <script> // filter 篩選數組 var arr = [12, 66, 4, 88, 3, 7]; var newArr = arr.filter(function(value, index) { // return value >= 20; return value % 2 === 0; }); console.log(newArr); </script></body>
some()
方法用于檢測數組中的元素是否滿足指定條件(查找數組中是否有滿足條件的元素)
注意它返回的是布爾值,如果查找到這個元素,就返回true,如果查找不到就返回false
如果找到第一個滿足條件的元素,則終止循環,不再繼續查找
<body> <script> // some 查找數組中是否有滿足條件的元素 var arr1 = ['red', 'pink', 'blue']; var flag1 = arr1.some(function(value) { return value == 'pink'; }); console.log(flag1); // 1. filter 也是查找滿足條件的元素 返回的是一個數組 而且是把所有滿足條件的元素返回回來 // 2. some 也是查找滿足條件的元素是否存在 返回的是一個布爾值 如果查找到第一個滿足條件的元素就終止循環 </script></body>
trim()
方法會從一個字符串的兩端刪除空白字符
trim()
方法并不影響原字符串本身,它返回的是一個新的字符串
<body> <input type="text"> <button>點擊</button> <p></p> <script> // trim 方法去除字符串兩側空格 var str = ' an dy '; console.log(str); var str1 = str.trim(); console.log(str1); var input = document.querySelector('input'); var btn = document.querySelector('button'); var p = document.querySelector('p'); btn.onclick = function() { var str = input.value.trim(); if (str === '') { alert('請輸入內容'); } else { console.log(str); console.log(str.length); p.innerHTML = str; } } </script></body>
Object.keys()
用于獲取對象自身所有的屬性
效果類似for...in
返回一個由屬性名組成的數組
<body> <script> // 用于獲取對象自身所有的屬性 var obj = { id: 1, pname: '小米', price: 1999, num: 2000 }; var arr = Object.keys(obj); console.log(arr); arr.forEach(function(value) { console.log(value); // id // pname // price // num }) </script></body>
Object.defineProperty()
定義對象中新屬性或修改原有的屬性(了解)
Object.defineProperty(obj,prop,descriptor)
obj : 目標對象
prop : 需定義或修改的屬性的名字
descriptor : 目標屬性所擁有的特性
<body> <script> // Object.defineProperty() 定義新屬性或修改原有的屬性 var obj = { id: 1, pname: '小米', price: 1999 }; // 1. 以前的對象添加和修改屬性的方式 // obj.num = 1000; // obj.price = 99; // console.log(obj); // 2. Object.defineProperty() 定義新屬性或修改原有的屬性 Object.defineProperty(obj, 'num', { value: 1000, enumerable: true }); console.log(obj); Object.defineProperty(obj, 'price', { value: 9.9 }); console.log(obj); Object.defineProperty(obj, 'id', { // 如果值為false 不允許修改這個屬性值 默認值也是false writable: false, }); obj.id = 2; console.log(obj); Object.defineProperty(obj, 'address', { value: '中國山東藍翔技校xx單元', // 如果只為false 不允許修改這個屬性值 默認值也是false writable: false, // enumerable 如果值為false 則不允許遍歷, 默認的值是 false enumerable: false, // configurable 如果為false 則不允許刪除這個屬性 不允許在修改第三個參數里面的特性 默認為false configurable: false }); console.log(obj); console.log(Object.keys(obj)); delete obj.address; console.log(obj); delete obj.pname; console.log(obj); Object.defineProperty(obj, 'address', { value: '中國山東藍翔技校xx單元', // 如果值為false 不允許修改這個屬性值 默認值也是false writable: true, // enumerable 如果值為false 則不允許遍歷, 默認的值是 false enumerable: true, // configurable 如果為false 則不允許刪除這個屬性 默認為false configurable: true }); console.log(obj.address); </script></body>
第三個參數 descriptor 說明:以對象形式{ }書寫
value:設置屬性的值,默認為undefined
writeable: 值是否可以重寫 true | false 默認為false
enumerable: 目標屬性是否可以被枚舉 true | false 默認為false
configurable: 目標屬性是否可以被刪除或是否可以再次修改特性 true | false 默認為false
函數聲明方式 function 關鍵字(命名函數)
函數表達式(匿名函數)
new Function()
var fn = new Function('參數1','參數2',.....,'函數體');
Function 里面參數都必須是字符串格式
第三種方式執行效率低,也不方便書寫,因此較少使用
所有函數都是 Function 的實例(對象)
函數也屬于對象
<body> <script> // 函數的定義方式 // 1. 自定義函數(命名函數) function fn() {}; // 2. 函數表達式 (匿名函數) var fun = function() {}; // 3. 利用 new Function('參數1','參數2', '函數體'); // Function 里面參數都必須是字符串格式,執行效率低,較少寫 var f = new Function('a', 'b', 'console.log(a + b)'); f(1, 2); // 4. 所有函數都是 Function 的實例(對象) console.dir(f); // 5. 函數也屬于對象 console.log(f instanceof Object); </script></body>
普通函數
對象的方法
構造函數
綁定事件函數
定時器函數
立即執行函數
<body> <script> // 函數的調用方式 // 1. 普通函數 function fn() { console.log('人生的巔峰'); } // fn(); fn.call() // 2. 對象的方法 var o = { sayHi: function() { console.log('人生的巔峰'); } } o.sayHi(); // 3. 構造函數 function Star() {}; new Star(); // 4. 綁定事件函數 // btn.onclick = function() {}; // 點擊了按鈕就可以調用這個函數 // 5. 定時器函數 // setInterval(function() {}, 1000); 這個函數是定時器自動1秒鐘調用一次 // 6. 立即執行函數 (function() { console.log('人生的巔峰'); })(); // 立即執行函數是自動調用 </script></body>
this
指向,是當我們調用函數的時候確定的,調用方式的不同決定了this
的指向不同,一般我們指向我們的調用者
調用方式 | this指向 |
---|---|
普通函數調用 | window |
構造函數調用 | 實例對象,原型對象里面的方法也指向實例對象 |
對象方法調用 | 該方法所屬對象 |
事件綁定方法 | 綁定事件對象 |
定時器函數 | window |
立即執行函數 | window |
<body> <button>點擊</button> <script> // 函數的不同調用方式決定了this 的指向不同 // 1. 普通函數 this 指向window function fn() { console.log('普通函數的this' + this); } window.fn(); // 2. 對象的方法 this指向的是對象 o var o = { sayHi: function() { console.log('對象方法的this:' + this); } } o.sayHi(); // 3. 構造函數 this 指向 ldh 這個實例對象 原型對象里面的this 指向的也是 ldh這個實例對象 function Star() {}; Star.prototype.sing = function() { } var ldh = new Star(); // 4. 綁定事件函數 this 指向的是函數的調用者 btn這個按鈕對象 var btn = document.querySelector('button'); btn.onclick = function() { console.log('綁定時間函數的this:' + this); }; // 5. 定時器函數 this 指向的也是window window.setTimeout(function() { console.log('定時器的this:' + this); }, 1000); // 6. 立即執行函數 this還是指向window (function() { console.log('立即執行函數的this' + this); })(); </script></body>
JavaScript 為我們專門提供了一些函數方法來幫我們處理函數內部 this 的指向問題,常用的有 bind(),call(),apply()
三種方法
call()
方法調用一個對象,簡單理解為調用函數的方式,但是它可以改變函數的this
指向
fun.call(thisArg,arg1,arg2,.....)
thisArg
: 在 fun 函數運行時指定的 this 值
arg1,arg2
: 傳遞的其他參數
返回值就是函數的返回值,因為它就是調用函數
因此當我們想改變 this 指向,同時想調用這個函數的時候,可以使用 call,比如繼承
<body> <script> // 改變函數內this指向 js提供了三種方法 call() apply() bind() // 1. call() var o = { name: 'andy' } function fn(a, b) { console.log(this); console.log(a + b); }; fn.call(o, 1, 2); // call 第一個可以調用函數 第二個可以改變函數內的this 指向 // call 的主要作用可以實現繼承 function Father(uname, age, sex) { this.uname = uname; this.age = age; this.sex = sex; } function Son(uname, age, sex) { Father.call(this, uname, age, sex); } var son = new Son('劉德華', 18, '男'); console.log(son); </script></body>
apply()
方法調用一個函數,簡單理解為調用函數的方式,但是它可以改變函數的 this
指向
fun.apply(thisArg,[argsArray])
thisArg: 在 fun 函數運行時指定的 this 值
argsArray : 傳遞的值,必須包含在數組里面
返回值就是函數的返回值,因為它就是調用函數
因此 apply 主要跟數組有關系,比如使用 Math.max() 求數組的最大值
<body> <script> // 改變函數內this指向 js提供了三種方法 call() apply() bind() // 2. apply() 應用 運用的意思 var o = { name: 'andy' }; function fn(arr) { console.log(this); console.log(arr); // 'pink' }; fn.apply(o, ['pink']); // 1. 也是調用函數 第二個可以改變函數內部的this指向 // 2. 但是他的參數必須是數組(偽數組) // 3. apply 的主要應用 比如說我們可以利用 apply 借助于數學內置對象求數組最大值 // Math.max(); var arr = [1, 66, 3, 99, 4]; var arr1 = ['red', 'pink']; // var max = Math.max.apply(null, arr); var max = Math.max.apply(Math, arr); var min = Math.min.apply(Math, arr); console.log(max, min); </script></body>
bind()
方法不會調用函數。但是能改變函數內部 this
指向
fun.bind(thisArg,arg1,arg2,....)
返回由指定的 this
值和初始化參數改造的原函數拷貝
因此當我們只是想改變 this 指向,并且不想調用這個函數的時候,可以使用bind
<body> <button>點擊</button> <button>點擊</button> <button>點擊</button> <script> // 改變函數內this指向 js提供了三種方法 call() apply() bind() // 3. bind() 綁定 捆綁的意思 var o = { name: 'andy' }; function fn(a, b) { console.log(this); console.log(a + b); }; var f = fn.bind(o, 1, 2); f(); // 1. 不會調用原來的函數 可以改變原來函數內部的this 指向 // 2. 返回的是原函數改變this之后產生的新函數 // 3. 如果有的函數我們不需要立即調用,但是又想改變這個函數內部的this指向此時用bind // 4. 我們有一個按鈕,當我們點擊了之后,就禁用這個按鈕,3秒鐘之后開啟這個按鈕 // var btn1 = document.querySelector('button'); // btn1.onclick = function() { // this.disabled = true; // 這個this 指向的是 btn 這個按鈕 // // var that = this; // setTimeout(function() { // // that.disabled = false; // 定時器函數里面的this 指向的是window // this.disabled = false; // 此時定時器函數里面的this 指向的是btn // }.bind(this), 3000); // 這個this 指向的是btn 這個對象 // } var btns = document.querySelectorAll('button'); for (var i = 0; i < btns.length; i++) { btns[i].onclick = function() { this.disabled = true; setTimeout(function() { this.disabled = false; }.bind(this), 2000); } } </script></body>
call apply bind 總結:
相同點:
都可以改變函數內部的 this
指向
區別點:
call
和apply
會調用函數,并且改變函數內部的this
指向
call
和apply
傳遞的參數不一樣,call 傳遞參數,apply 必須數組形式
bind
不會調用函數,可以改變函數內部this
指向
主要應用場景
call
經常做繼承
apply
經常跟數組有關系,比如借助于數學對線實現數組最大值與最小值
bind
不調用函數,但是還想改變this指向,比如改變定時器內部的this指向
以上就是關于“JavaScript面向對象的思維特點是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。