摘要:通過構造函數得到的實例對象內部會包含一個指向構造函數的對象的指針。
JavaScript 高級
學習目標:
理解面向對象開發思想
掌握 JavaScript 面向對象開發相關模式
掌握在 JavaScript 中使用正則表達式
面向對象介紹 程序中面向對象的基本體現在 JavaScript 中,所有數據類型都可以視為對象,當然也可以自定義對象。
自定義的對象數據類型就是面向對象中的類( Class )的概念。
我們以一個例子來說明面向過程和面向對象在程序流程上的不同之處。
假設我們要處理學生的成績表,為了表示一個學生的成績,面向過程的程序可以用一個對象表示:
var std1 = { name: "Michael", score: 98 } var std2 = { name: "Bob", score: 81 }
而處理學生成績可以通過函數實現,比如打印學生的成績:
function printScore (student) { console.log("姓名:" + student.name + " " + "成績:" + student.score) }
如果采用面向對象的程序設計思想,我們首選思考的不是程序的執行流程,
而是 Student 這種數據類型應該被視為一個對象,這個對象擁有 name 和 score 這兩個屬性(Property)。
如果要打印一個學生的成績,首先必須創建出這個學生對應的對象,然后,給對象發一個 printScore 消息,讓對象自己把自己的數據打印出來。
抽象數據行為模板(Class):
function Student (name, score) { this.name = name this.score = score } Student.prototype.printScore = function () { console.log("姓名:" + this.name + " " + "成績:" + this.score) }
根據模板創建具體實例對象(Instance):
var std1 = new Student("Michael", 98) var std2 = new Student("Bob", 81)
實例對象具有自己的具體行為(給對象發消息):
std1.printScore() // => 姓名:Michael 成績:98 std2.printScore() // => 姓名:Bob 成績 81
面向對象的設計思想是從自然界中來的,因為在自然界中,類(Class)和實例(Instance)的概念是很自然的。
Class 是一種抽象概念,比如我們定義的 Class——Student ,是指學生這個概念,
而實例(Instance)則是一個個具體的 Student ,比如, Michael 和 Bob 是兩個具體的 Student 。
所以,面向對象的設計思想是:
抽象出 Class
根據 Class 創建 Instance
指揮 Instance 得結果
面向對象的抽象程度又比函數要高,因為一個 Class 既包含數據,又包含操作數據的方法。
創建對象三種方法 1、調用系統的構造函數我們可以直接通過 new Object() 創建:
var person = new Object() person.name = "Jack" person.age = 18 person.sayName = function () { console.log(this.name) }2、字面量創建
var person = { name: "Jack", age: 18, sayName: function () { console.log(this.name) } }
對于上面的寫法固然沒有問題,但是假如我們要生成兩個 person 實例對象呢?
3、工廠函數創建我們可以寫一個函數,解決代碼重復問題:
function createPerson (name, age) { return { name: name, age: age, sayName: function () { console.log(this.name) } } }
然后生成實例對象:
var p1 = createPerson("Jack", 18) var p2 = createPerson("Mike", 18)
這樣封裝確實爽多了,通過工廠模式我們解決了創建多個相似對象代碼冗余的問題,
但卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)。
內容引導:
構造函數語法
分析構造函數
構造函數和實例對象的關系
實例的 constructor 屬性
instanceof 操作符
普通函數調用和構造函數調用的區別
構造函數的返回值
構造函數的靜態成員和實例成員
函數也是對象
實例成員
靜態成員
構造函數的問題
更優雅的工廠函數:構造函數一種更優雅的工廠函數就是下面這樣,構造函數:
function Person (name, age) { this.name = name this.age = age this.sayName = function () { console.log(this.name) } } var p1 = new Person("Jack", 18) p1.sayName() // => Jack var p2 = new Person("Mike", 23) p2.sayName() // => Mike解析構造函數代碼的執行
在上面的示例中,Person() 函數取代了 createPerson() 函數,但是實現效果是一樣的。
這是為什么呢?
我們注意到,Person() 中的代碼與 createPerson() 有以下幾點不同之處:
沒有顯示的創建對象
直接將屬性和方法賦給了 this 對象
沒有 return 語句
函數名使用的是大寫的 Person
而要創建 Person 實例,則必須使用 new 操作符。
以這種方式調用構造函數會經歷以下 4 個步驟:
創建一個新對象
將構造函數的作用域賦給新對象(因此 this 就指向了這個新對象)
執行構造函數中的代碼
返回新對象
下面是具體的偽代碼:
function Person (name, age) { // 當使用 new 操作符調用 Person() 的時候,實際上這里會先創建一個對象 // var instance = {} // 然后讓內部的 this 指向 instance 對象 // this = instance // 接下來所有針對 this 的操作實際上操作的就是 instance this.name = name this.age = age this.sayName = function () { console.log(this.name) } // 在函數的結尾處會將 this 返回,也就是 instance // return this }構造函數和實例對象的關系
使用構造函數的好處不僅僅在于代碼的簡潔性,更重要的是我們可以識別對象的具體類型了。
在每一個實例對象中的_proto_中同時有一個 constructor 屬性,該屬性指向創建該實例的構造函數:
console.log(p1.constructor === Person) // => true console.log(p2.constructor === Person) // => true console.log(p1.constructor === p2.constructor) // => true
對象的 constructor 屬性最初是用來標識對象類型的,
但是,如果要檢測對象的類型,還是使用 instanceof 操作符更可靠一些:
console.log(p1 instanceof Person) // => true console.log(p2 instanceof Person) // => true構造函數的問題
使用構造函數帶來的最大的好處就是創建對象更方便了,但是其本身也存在一個浪費內存的問題:
function Person (name, age) { this.name = name this.age = age this.type = "human" this.sayHello = function () { console.log("hello " + this.name) } } var p1 = new Person("lpz", 18) var p2 = new Person("Jack", 16)
在該示例中,從表面上好像沒什么問題,但是實際上這樣做,有一個很大的弊端。那就是對于每一個實例對象,type 和 sayHello 都是一模一樣的內容,每一次生成一個實例,都必須為重復的內容,多占用一些內存,如果實例對象很多,會造成極大的內存浪費。
console.log(p1.sayHello === p2.sayHello) // => false
對于這種問題我們可以把需要共享的函數定義到構造函數外部:
function sayHello = function () { console.log("hello " + this.name) } function Person (name, age) { this.name = name this.age = age this.type = "human" this.sayHello = sayHello } var p1 = new Person("lpz", 18) var p2 = new Person("Jack", 16) console.log(p1.sayHello === p2.sayHello) // => true
這樣確實可以了,但是如果有多個需要共享的函數的話就會造成全局命名空間沖突的問題。
你肯定想到了可以把多個函數放到一個對象中用來避免全局命名空間沖突的問題:
var fns = { sayHello: function () { console.log("hello " + this.name) }, sayAge: function () { console.log(this.age) } } function Person (name, age) { this.name = name this.age = age this.type = "human" this.sayHello = fns.sayHello this.sayAge = fns.sayAge } var p1 = new Person("lpz", 18) var p2 = new Person("Jack", 16) console.log(p1.sayHello === p2.sayHello) // => true console.log(p1.sayAge === p2.sayAge) // => true
至此,我們利用自己的方式基本上解決了構造函數的內存浪費問題。
小結
構造函數語法
分析構造函數
構造函數和實例對象的關系
實例的 constructor 屬性
instanceof 操作符
構造函數的問題
原型內容引導:
使用 prototype 原型對象解決構造函數的問題
分析 構造函數、prototype 原型對象、實例對象 三者之間的關系
屬性成員搜索原則:原型鏈
實例對象讀寫原型對象中的成員
原型對象的簡寫形式
原生對象的原型
Object
Array
String
...
原型對象的問題
構造的函數和原型對象使用建議
更好的解決方案: prototypeJavascript 規定,每一個構造函數都有一個 prototype 屬性,指向另一個對象。
這個對象的所有屬性和方法,都會被構造函數的實例繼承。
這也就意味著,我們可以把所有對象實例需要共享的屬性和方法直接定義在 prototype 對象上。
function Person (name, age) { this.name = name this.age = age } console.log(Person.prototype) Person.prototype.type = "human" Person.prototype.sayName = function () { console.log(this.name) } var p1 = new Person(...) var p2 = new Person(...) console.log(p1.sayName === p2.sayName) // => true
這時所有實例的 type 屬性和 sayName() 方法,
其實都是同一個內存地址,指向 prototype 對象,因此就提高了運行效率。
任何函數都具有一個 prototype 屬性,該屬性是一個對象。
function F () {} console.log(F.prototype) // => object F.prototype.sayHi = function () { console.log("hi!") }
構造函數的 prototype 對象默認都有一個 constructor 屬性,指向 prototype 對象所在函數。
console.log(F.constructor === F) // => true
通過構造函數得到的實例對象內部會包含一個指向構造函數的 prototype 對象的指針 __proto__。
var instance = new F() console.log(instance.__proto__ === F.prototype) // => true
proto 是非標準屬性。
實例對象可以直接訪問原型對象成員。
instance.sayHi() // => hi!
總結:
任何函數都具有一個 prototype 屬性,該屬性是一個對象
構造函數的 prototype 對象默認都有一個 constructor 屬性,指向 prototype 對象所在函數
通過構造函數得到的實例對象內部會包含一個指向構造函數的 prototype 對象的指針 proto
所有實例都直接或間接繼承了原型對象的成員
屬性成員的搜索原則:原型鏈了解了 構造函數-實例-原型對象 三者之間的關系后,接下來我們來解釋一下為什么實例對象可以訪問原型對象中的成員。
每當代碼讀取某個對象的某個屬性時,都會執行一次搜索,目標是具有給定名字的屬性
搜索首先從對象實例本身開始
如果在實例中找到了具有給定名字的屬性,則返回該屬性的值
如果沒有找到,則繼續搜索指針指向的原型對象,在原型對象中查找具有給定名字的屬性
如果在原型對象中找到了這個屬性,則返回該屬性的值
也就是說,在我們調用 person1.sayName() 的時候,會先后執行兩次搜索:
首先,解析器會問:“實例 person1 有 sayName 屬性嗎?”答:“沒有。
”然后,它繼續搜索,再問:“ person1 的原型有 sayName 屬性嗎?”答:“有。
”于是,它就讀取那個保存在原型對象中的函數。
當我們調用 person2.sayName() 時,將會重現相同的搜索過程,得到相同的結果。
而這正是多個對象實例共享原型所保存的屬性和方法的基本原理。
總結:
先在自己身上找,找到即返回
自己身上找不到,則沿著原型鏈向上查找,找到即返回
如果一直到原型鏈的末端還沒有找到,則返回 undefined
實例對象讀寫原型對象成員 更簡單的原型語法我們注意到,前面例子中每添加一個屬性和方法就要敲一遍 Person.prototype 。
為減少不必要的輸入,更常見的做法是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象:
function Person (name, age) { this.name = name this.age = age } Person.prototype = { type: "human", sayHello: function () { console.log("我叫" + this.name + ",我今年" + this.age + "歲了") } }
在該示例中,我們將 Person.prototype 重置到了一個新的對象。
這樣做的好處就是為 Person.prototype 添加成員簡單了,但是也會帶來一個問題,那就是原型對象丟失了 constructor 成員。
所以,我們為了保持 constructor 的指向正確,建議的寫法是:
function Person (name, age) { this.name = name this.age = age } Person.prototype = { constructor: Person, // => 手動將 constructor 指向正確的構造函數 type: "human", sayHello: function () { console.log("我叫" + this.name + ",我今年" + this.age + "歲了") } }原生對象的原型
所有函數都有 prototype 屬性對象。
Object.prototype
Function.prototype
Array.prototype
String.prototype
Number.prototype
Date.prototype
...
練習:為數組對象和字符串對象擴展原型方法
繼承 什么是繼承現實生活中的繼承
程序中的繼承
構造函數的屬性繼承:借用構造函數function Person (name, age) { this.type = "human" this.name = name this.age = age } function Student (name, age) { // 借用構造函數繼承屬性成員 Person.call(this, name, age) } var s1 = Student("張三", 18) console.log(s1.type, s1.name, s1.age) // => human 張三 18構造函數的原型方法繼承:拷貝繼承(for-in)
function Person (name, age) { this.type = "human" this.name = name this.age = age } Person.prototype.sayName = function () { console.log("hello " + this.name) } function Student (name, age) { Person.call(this, name, age) } // 原型對象拷貝繼承原型對象成員 for(var key in Person.prototype) { Student.prototype[key] = Person.prototype[key] } var s1 = Student("張三", 18) s1.sayName() // => hello 張三另一種繼承方式:原型繼承
function Person (name, age) { this.type = "human" this.name = name this.age = age } Person.prototype.sayName = function () { console.log("hello " + this.name) } function Student (name, age) { Person.call(this, name, age) } // 利用原型的特性實現繼承 Student.prototype = new Person() var s1 = Student("張三", 18) console.log(s1.type) // => human s1.sayName() // => hello 張三函數進階 函數內 this 指向的不同場景
函數的調用方式決定了 this 指向的不同:
這就是對函數內部 this 指向的基本整理,寫代碼寫多了自然而然就熟悉了。
函數也是對象
所有函數都是 Function 的實例
call、apply、bind
那了解了函數 this 指向的不同場景之后,我們知道有些情況下我們為了使用某種特定環境的 this 引用,
這時候時候我們就需要采用一些特殊手段來處理了,例如我們經常在定時器外部備份 this 引用,然后在定時器函數內部使用外部 this 的引用。
然而實際上對于這種做法我們的 JavaScript 為我們專門提供了一些函數方法用來幫我們更優雅的處理函數內部 this 指向問題。
這就是接下來我們要學習的 call、apply、bind 三個函數方法。
call
call() 方法調用一個函數, 其具有一個指定的 this 值和分別地提供的參數(參數的列表)。
注意:該方法的作用和 apply() 方法類似,只有一個區別,就是 call() 方法接受的是若干個參數的列表,而 apply() 方法接受的是一個包含多個參數的數組。
語法:
fun.call(thisArg[, arg1[, arg2[, ...]]])
參數:
thisArg
在 fun 函數運行時指定的 this 值
如果指定了 null 或者 undefined 則內部 this 指向 window
arg1, arg2, ...
指定的參數列表
apply
apply() 方法調用一個函數, 其具有一個指定的 this 值,以及作為一個數組(或類似數組的對象)提供的參數。
注意:該方法的作用和 call() 方法類似,只有一個區別,就是 call() 方法接受的是若干個參數的列表,而 apply() 方法接受的是一個包含多個參數的數組。
語法:
fun.apply(thisArg, [argsArray])
參數:
thisArg
argsArray
apply() 與 call() 非常相似,不同之處在于提供參數的方式。
apply() 使用參數數組而不是一組參數列表。例如:
fun.apply(this, ["eat", "bananas"])
bind
bind() 函數會創建一個新函數(稱為綁定函數),新函數與被調函數(綁定函數的目標函數)具有相同的函數體(在 ECMAScript 5 規范中內置的call屬性)。
當目標函數被調用時 this 值綁定到 bind() 的第一個參數,該參數不能被重寫。綁定函數被調用時,bind() 也接受預設的參數提供給原函數。
一個綁定函數也能使用new操作符創建對象:這種行為就像把原函數當成構造器。提供的 this 值被忽略,同時調用時的參數被提供給模擬函數。
語法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
參數:
thisArg
當綁定函數被調用時,該參數會作為原函數運行時的 this 指向。當使用new 操作符調用綁定函數時,該參數無效。
arg1, arg2, ...
當綁定函數被調用時,這些參數將置于實參之前傳遞給被綁定的方法。
返回值:
返回由指定的this值和初始化參數改造的原函數拷貝。
小結
call 和 apply 特性一樣
都是用來調用函數,而且是立即調用
但是可以在調用函數的同時,通過第一個參數指定函數內部 this 的指向
call 調用的時候,參數必須以參數列表的形式進行傳遞,也就是以逗號分隔的方式依次傳遞即可
apply 調用的時候,參數必須是一個數組,然后在執行的時候,會將數組內部的元素一個一個拿出來,與形參一一對應進行傳遞
如果第一個參數指定了 null 或者 undefined 則內部 this 指向 window
bind
可以用來指定內部 this 的指向,然后生成一個改變了 this 指向的新的函數
它和 call、apply 最大的區別是:bind 不會調用
bind 支持傳遞參數,它的傳參方式比較特殊,一共有兩個位置可以傳遞
在 bind 的同時,以參數列表的形式進行傳遞
在調用的時候,以參數列表的形式進行傳遞
那到底以誰 bind 的時候傳遞的參數為準呢還是以調用的時候傳遞的參數為準
兩者合并:bind 的時候傳遞的參數和調用的時候傳遞的參數會合并到一起,傳遞到函數內部
函數的其它成員
arguments
實參集合
caller
函數的調用者
length
形參的個數
name
函數的名稱
function fn(x, y, z) { console.log(fn.length) // => 形參的個數 console.log(arguments) // 偽數組實參參數集合 console.log(arguments.callee === fn) // 函數本身 console.log(fn.caller) // 函數的調用者 console.log(fn.name) // => 函數的名字 } function f() { fn(10, 20, 30) } f()什么是閉包
閉包就是能夠讀取其他函數內部變量的函數,
由于在 Javascript 語言中,只有函數內部的子函數才能讀取局部變量,
因此可以把閉包簡單理解成 “定義在一個函數內部的函數”。
所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。
閉包的用途:
可以在函數外部讀取函數內部成員
讓函數內成員始終存活在內存中
一些關于閉包的例子
示例1:
var arr = [10, 20, 30] for(var i = 0; i < arr.length; i++) { arr[i] = function () { console.log(i) } }
示例2:
console.log(111) for(var i = 0; i < 3; i++) { setTimeout(function () { console.log(i) }, 0) } console.log(222)正則表達式
了解正則表達式基本語法
能夠使用JavaScript的正則對象
正則表達式簡介 什么是正則表達式正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。
JavaScript 中使用正則表達式 創建正則對象方式1:
var reg = new Regex("d", "i"); var reg = new Regex("d", "gi");
方式2:
var reg = /d/i; var reg = /d/gi;案例 正則提取
// 1. 提取工資 var str = "張三:1000,李四:5000,王五:8000。"; var array = str.match(/d+/g); console.log(array); // 2. 提取email地址 var str = "123123@xx.com,fangfang@valuedopinions.cn 286669312@qq.com 2、emailenglish@emailenglish.englishtown.com 286669312@qq.com..."; var array = str.match(/w+@w+.w+(.w+)?/g); console.log(array); // 3. 分組提取 ? // 3. 提取日期中的年部分 2015-5-10var dateStr = "2016-1-5"; // 正則表達式中的()作為分組來使用,獲取分組匹配到的結果用Regex.$1 $2 $3....來獲取 var reg = /(d{4})-d{1,2}-d{1,2}/; if (reg.test(dateStr)) { ?console.log(RegExp.$1);} // 4. 提取郵件中的每一部分 var reg = /(w+)@(w+).(w+)(.w+)?/; var str = "123123@xx.com"; if (reg.test(str)) { ?console.log(RegExp.$1); ?console.log(RegExp.$2); ? console.log(RegExp.$3);}正則替換
// 1. 替換所有空白 var str = " 123AD asadf asadfasf adf "; str = str.replace(/s/g,"xx"); console.log(str); // 2. 替換所有,|, var str = "abc,efg,123,abc,123,a"; str = str.replace(/,|,/g, "."); console.log(str);案例:表單驗證
QQ號:
郵箱:
手機:
生日:
姓名:
//獲取文本框 var txtQQ = document.getElementById("txtQQ"); var txtEMail = document.getElementById("txtEMail"); var txtPhone = document.getElementById("txtPhone"); var txtBirthday = document.getElementById("txtBirthday"); var txtName = document.getElementById("txtName"); // txtQQ.onblur = function () { //獲取當前文本框對應的span var span = this.nextElementSibling; var reg = /^d{5,12}$/; //判斷驗證是否成功 if(!reg.test(this.value) ){ //驗證不成功 span.innerText = "請輸入正確的QQ號"; span.style.color = "red"; }else{ //驗證成功 span.innerText = ""; span.style.color = ""; } }; //txtEMail txtEMail.onblur = function () { //獲取當前文本框對應的span var span = this.nextElementSibling; var reg = /^w+@w+.w+(.w+)?$/; //判斷驗證是否成功 if(!reg.test(this.value) ){ //驗證不成功 span.innerText = "請輸入正確的EMail地址"; span.style.color = "red"; }else{ //驗證成功 span.innerText = ""; span.style.color = ""; } };
表單驗證部分,封裝成函數:
var regBirthday = /^d{4}-d{1,2}-d{1,2}$/; addCheck(txtBirthday, regBirthday, "請輸入正確的出生日期"); //給文本框添加驗證 function addCheck(element, reg, tip) { element.onblur = function () { //獲取當前文本框對應的span var span = this.nextElementSibling; //判斷驗證是否成功 if(!reg.test(this.value) ){ //驗證不成功 span.innerText = tip; span.style.color = "red"; }else{ //驗證成功 span.innerText = ""; span.style.color = ""; } }; }
通過給元素增加自定義驗證屬性對表單進行驗證:
// 所有的驗證規則 var rules = [ { name: "qq", reg: /^d{5,12}$/, tip: "請輸入正確的QQ" }, { name: "email", reg: /^w+@w+.w+(.w+)?$/, tip: "請輸入正確的郵箱地址" }, { name: "phone", reg: /^d{11}$/, tip: "請輸入正確的手機號碼" }, { name: "date", reg: /^d{4}-d{1,2}-d{1,2}$/, tip: "請輸入正確的出生日期" }, { name: "cn", reg: /^[u4e00-u9fa5]{2,4}$/, tip: "請輸入正確的姓名" }]; addCheck("frm"); //給文本框添加驗證 function addCheck(formId) { var i = 0, len = 0, frm =document.getElementById(formId); len = frm.children.length; for (; i < len; i++) { var element = frm.children[i]; // 表單元素中有name屬性的元素添加驗證 if (element.name) { element.onblur = function () { // 使用dataset獲取data-自定義屬性的值 var ruleName = this.dataset.rule; var rule =getRuleByRuleName(rules, ruleName); var span = this.nextElementSibling; //判斷驗證是否成功 if(!rule.reg.test(this.value) ){ //驗證不成功 span.innerText = rule.tip; span.style.color = "red"; }else{ //驗證成功 span.innerText = ""; span.style.color = ""; } } } } } // 根據規則的名稱獲取規則對象 function getRuleByRuleName(rules, ruleName) { var i = 0, len = rules.length; var rule = null; for (; i < len; i++) { if (rules[i].name == ruleName) { rule = rules[i]; break; } } return rule; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101432.html
摘要:通過構造函數得到的實例對象內部會包含一個指向構造函數的對象的指針。 JavaScript 高級 學習目標: 理解面向對象開發思想 掌握 JavaScript 面向對象開發相關模式 掌握在 JavaScript 中使用正則表達式 面向對象介紹 程序中面向對象的基本體現 在 JavaScript 中,所有數據類型都可以視為對象,當然也可以自定義對象。自定義的對象數據類型就是面向對象中...
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
閱讀 2047·2021-09-07 10:14
閱讀 1483·2019-08-30 15:53
閱讀 2275·2019-08-30 12:43
閱讀 2866·2019-08-29 16:37
閱讀 760·2019-08-26 13:29
閱讀 2004·2019-08-26 13:28
閱讀 445·2019-08-23 18:33
閱讀 3516·2019-08-23 16:09