成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JS高級(jí)講解面向?qū)ο?,原型,繼承,閉包,正則表達(dá)式,讓你徹底愛上前端(進(jìn)階二)

Nino / 1441人閱讀

摘要:通過構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的對(duì)象的指針。

JavaScript 高級(jí)

學(xué)習(xí)目標(biāo):

理解面向?qū)ο箝_發(fā)思想

掌握 JavaScript 面向?qū)ο箝_發(fā)相關(guān)模式

掌握在 JavaScript 中使用正則表達(dá)式

面向?qū)ο蠼榻B 程序中面向?qū)ο蟮幕倔w現(xiàn)

在 JavaScript 中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。
自定義的對(duì)象數(shù)據(jù)類型就是面向?qū)ο笾械念悾?Class )的概念。
我們以一個(gè)例子來說明面向過程和面向?qū)ο笤诔绦蛄鞒躺系牟煌帯?br>假設(shè)我們要處理學(xué)生的成績(jī)表,為了表示一個(gè)學(xué)生的成績(jī),面向過程的程序可以用一個(gè)對(duì)象表示:

var std1 = { name: "Michael", score: 98 }
var std2 = { name: "Bob", score: 81 }

而處理學(xué)生成績(jī)可以通過函數(shù)實(shí)現(xiàn),比如打印學(xué)生的成績(jī):

function printScore (student) {
  console.log("姓名:" + student.name + "  " + "成績(jī):" + student.score)
}

如果采用面向?qū)ο蟮某绦蛟O(shè)計(jì)思想,我們首選思考的不是程序的執(zhí)行流程,

而是 Student 這種數(shù)據(jù)類型應(yīng)該被視為一個(gè)對(duì)象,這個(gè)對(duì)象擁有 name 和 score 這兩個(gè)屬性(Property)。

如果要打印一個(gè)學(xué)生的成績(jī),首先必須創(chuàng)建出這個(gè)學(xué)生對(duì)應(yīng)的對(duì)象,然后,給對(duì)象發(fā)一個(gè) printScore 消息,讓對(duì)象自己把自己的數(shù)據(jù)打印出來。

抽象數(shù)據(jù)行為模板(Class):

function Student (name, score) {
  this.name = name
  this.score = score
}

Student.prototype.printScore = function () {
  console.log("姓名:" + this.name + "  " + "成績(jī):" + this.score)
}

根據(jù)模板創(chuàng)建具體實(shí)例對(duì)象(Instance):

var std1 = new Student("Michael", 98)
var std2 = new Student("Bob", 81)

實(shí)例對(duì)象具有自己的具體行為(給對(duì)象發(fā)消息):

std1.printScore() // => 姓名:Michael  成績(jī):98
std2.printScore() // => 姓名:Bob  成績(jī) 81

面向?qū)ο蟮脑O(shè)計(jì)思想是從自然界中來的,因?yàn)樵谧匀唤缰校悾–lass)和實(shí)例(Instance)的概念是很自然的。

Class 是一種抽象概念,比如我們定義的 Class——Student ,是指學(xué)生這個(gè)概念,

而實(shí)例(Instance)則是一個(gè)個(gè)具體的 Student ,比如, Michael 和 Bob 是兩個(gè)具體的 Student 。

所以,面向?qū)ο蟮脑O(shè)計(jì)思想是:

抽象出 Class

根據(jù) Class 創(chuàng)建 Instance

指揮 Instance 得結(jié)果

面向?qū)ο蟮某橄蟪潭扔直群瘮?shù)要高,因?yàn)橐粋€(gè) Class 既包含數(shù)據(jù),又包含操作數(shù)據(jù)的方法。

創(chuàng)建對(duì)象三種方法 1、調(diào)用系統(tǒng)的構(gòu)造函數(shù)

我們可以直接通過 new Object() 創(chuàng)建:

var person = new Object()
person.name = "Jack"
person.age = 18

person.sayName = function () {
  console.log(this.name)
}
2、字面量創(chuàng)建
var person = {
  name: "Jack",
  age: 18,
  sayName: function () {
    console.log(this.name)
  }
}

對(duì)于上面的寫法固然沒有問題,但是假如我們要生成兩個(gè) person 實(shí)例對(duì)象呢?

3、工廠函數(shù)創(chuàng)建

我們可以寫一個(gè)函數(shù),解決代碼重復(fù)問題:

function createPerson (name, age) {
  return {
    name: name,
    age: age,
    sayName: function () {
      console.log(this.name)
    }
  }
}

然后生成實(shí)例對(duì)象:

var p1 = createPerson("Jack", 18)
var p2 = createPerson("Mike", 18)

這樣封裝確實(shí)爽多了,通過工廠模式我們解決了創(chuàng)建多個(gè)相似對(duì)象代碼冗余的問題,
但卻沒有解決對(duì)象識(shí)別的問題(即怎樣知道一個(gè)對(duì)象的類型)。

構(gòu)造函數(shù)

內(nèi)容引導(dǎo):

構(gòu)造函數(shù)語(yǔ)法

分析構(gòu)造函數(shù)

構(gòu)造函數(shù)和實(shí)例對(duì)象的關(guān)系

實(shí)例的 constructor 屬性

instanceof 操作符

普通函數(shù)調(diào)用和構(gòu)造函數(shù)調(diào)用的區(qū)別

構(gòu)造函數(shù)的返回值

構(gòu)造函數(shù)的靜態(tài)成員和實(shí)例成員

函數(shù)也是對(duì)象

實(shí)例成員

靜態(tài)成員

構(gòu)造函數(shù)的問題

更優(yōu)雅的工廠函數(shù):構(gòu)造函數(shù)

一種更優(yōu)雅的工廠函數(shù)就是下面這樣,構(gòu)造函數(shù):

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
解析構(gòu)造函數(shù)代碼的執(zhí)行

在上面的示例中,Person() 函數(shù)取代了 createPerson() 函數(shù),但是實(shí)現(xiàn)效果是一樣的。

這是為什么呢?

我們注意到,Person() 中的代碼與 createPerson() 有以下幾點(diǎn)不同之處:

沒有顯示的創(chuàng)建對(duì)象

直接將屬性和方法賦給了 this 對(duì)象

沒有 return 語(yǔ)句

函數(shù)名使用的是大寫的 Person

而要?jiǎng)?chuàng)建 Person 實(shí)例,則必須使用 new 操作符。

以這種方式調(diào)用構(gòu)造函數(shù)會(huì)經(jīng)歷以下 4 個(gè)步驟:

創(chuàng)建一個(gè)新對(duì)象

將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此 this 就指向了這個(gè)新對(duì)象)

執(zhí)行構(gòu)造函數(shù)中的代碼

返回新對(duì)象

下面是具體的偽代碼:

function Person (name, age) {
  // 當(dāng)使用 new 操作符調(diào)用 Person() 的時(shí)候,實(shí)際上這里會(huì)先創(chuàng)建一個(gè)對(duì)象
  // var instance = {}
  // 然后讓內(nèi)部的 this 指向 instance 對(duì)象
  // this = instance
  // 接下來所有針對(duì) this 的操作實(shí)際上操作的就是 instance

  this.name = name
  this.age = age
  this.sayName = function () {
    console.log(this.name)
  }

  // 在函數(shù)的結(jié)尾處會(huì)將 this 返回,也就是 instance
  // return this
}
構(gòu)造函數(shù)和實(shí)例對(duì)象的關(guān)系

使用構(gòu)造函數(shù)的好處不僅僅在于代碼的簡(jiǎn)潔性,更重要的是我們可以識(shí)別對(duì)象的具體類型了。

在每一個(gè)實(shí)例對(duì)象中的_proto_中同時(shí)有一個(gè) constructor 屬性,該屬性指向創(chuàng)建該實(shí)例的構(gòu)造函數(shù):

console.log(p1.constructor === Person) // => true
console.log(p2.constructor === Person) // => true
console.log(p1.constructor === p2.constructor) // => true

對(duì)象的 constructor 屬性最初是用來標(biāo)識(shí)對(duì)象類型的,
但是,如果要檢測(cè)對(duì)象的類型,還是使用 instanceof 操作符更可靠一些:

console.log(p1 instanceof Person) // => true
console.log(p2 instanceof Person) // => true
構(gòu)造函數(shù)的問題

使用構(gòu)造函數(shù)帶來的最大的好處就是創(chuàng)建對(duì)象更方便了,但是其本身也存在一個(gè)浪費(fèi)內(nèi)存的問題:

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)

在該示例中,從表面上好像沒什么問題,但是實(shí)際上這樣做,有一個(gè)很大的弊端。那就是對(duì)于每一個(gè)實(shí)例對(duì)象,type 和 sayHello 都是一模一樣的內(nèi)容,每一次生成一個(gè)實(shí)例,都必須為重復(fù)的內(nèi)容,多占用一些內(nèi)存,如果實(shí)例對(duì)象很多,會(huì)造成極大的內(nèi)存浪費(fèi)。

console.log(p1.sayHello === p2.sayHello) // => false

對(duì)于這種問題我們可以把需要共享的函數(shù)定義到構(gòu)造函數(shù)外部:

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

這樣確實(shí)可以了,但是如果有多個(gè)需要共享的函數(shù)的話就會(huì)造成全局命名空間沖突的問題。

你肯定想到了可以把多個(gè)函數(shù)放到一個(gè)對(duì)象中用來避免全局命名空間沖突的問題:

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

至此,我們利用自己的方式基本上解決了構(gòu)造函數(shù)的內(nèi)存浪費(fèi)問題。
小結(jié)

構(gòu)造函數(shù)語(yǔ)法

分析構(gòu)造函數(shù)

構(gòu)造函數(shù)和實(shí)例對(duì)象的關(guān)系

實(shí)例的 constructor 屬性

instanceof 操作符

構(gòu)造函數(shù)的問題

原型

內(nèi)容引導(dǎo):

使用 prototype 原型對(duì)象解決構(gòu)造函數(shù)的問題

分析 構(gòu)造函數(shù)、prototype 原型對(duì)象、實(shí)例對(duì)象 三者之間的關(guān)系

屬性成員搜索原則:原型鏈

實(shí)例對(duì)象讀寫原型對(duì)象中的成員

原型對(duì)象的簡(jiǎn)寫形式

原生對(duì)象的原型

Object

Array

String

...

原型對(duì)象的問題

構(gòu)造的函數(shù)和原型對(duì)象使用建議

更好的解決方案: prototype

Javascript 規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè) prototype 屬性,指向另一個(gè)對(duì)象。

這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承。

這也就意味著,我們可以把所有對(duì)象實(shí)例需要共享的屬性和方法直接定義在 prototype 對(duì)象上。

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

這時(shí)所有實(shí)例的 type 屬性和 sayName() 方法,

其實(shí)都是同一個(gè)內(nèi)存地址,指向 prototype 對(duì)象,因此就提高了運(yùn)行效率。

任何函數(shù)都具有一個(gè) prototype 屬性,該屬性是一個(gè)對(duì)象。

function F () {}
console.log(F.prototype) // => object

F.prototype.sayHi = function () {
  console.log("hi!")
}

構(gòu)造函數(shù)的 prototype 對(duì)象默認(rèn)都有一個(gè) constructor 屬性,指向 prototype 對(duì)象所在函數(shù)。

console.log(F.constructor === F) // => true

通過構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的 prototype 對(duì)象的指針 __proto__。

var instance = new F()
console.log(instance.__proto__ === F.prototype) // => true

proto 是非標(biāo)準(zhǔn)屬性。

實(shí)例對(duì)象可以直接訪問原型對(duì)象成員。

instance.sayHi() // => hi!

總結(jié):

任何函數(shù)都具有一個(gè) prototype 屬性,該屬性是一個(gè)對(duì)象

構(gòu)造函數(shù)的 prototype 對(duì)象默認(rèn)都有一個(gè) constructor 屬性,指向 prototype 對(duì)象所在函數(shù)

通過構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的 prototype 對(duì)象的指針 proto

所有實(shí)例都直接或間接繼承了原型對(duì)象的成員

屬性成員的搜索原則:原型鏈

了解了 構(gòu)造函數(shù)-實(shí)例-原型對(duì)象 三者之間的關(guān)系后,接下來我們來解釋一下為什么實(shí)例對(duì)象可以訪問原型對(duì)象中的成員。

每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性

搜索首先從對(duì)象實(shí)例本身開始

如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值

如果沒有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性

如果在原型對(duì)象中找到了這個(gè)屬性,則返回該屬性的值

也就是說,在我們調(diào)用 person1.sayName() 的時(shí)候,會(huì)先后執(zhí)行兩次搜索:

首先,解析器會(huì)問:“實(shí)例 person1 有 sayName 屬性嗎?”答:“沒有。

”然后,它繼續(xù)搜索,再問:“ person1 的原型有 sayName 屬性嗎?”答:“有。

”于是,它就讀取那個(gè)保存在原型對(duì)象中的函數(shù)。

當(dāng)我們調(diào)用 person2.sayName() 時(shí),將會(huì)重現(xiàn)相同的搜索過程,得到相同的結(jié)果。

而這正是多個(gè)對(duì)象實(shí)例共享原型所保存的屬性和方法的基本原理。

總結(jié):

先在自己身上找,找到即返回

自己身上找不到,則沿著原型鏈向上查找,找到即返回

如果一直到原型鏈的末端還沒有找到,則返回 undefined

實(shí)例對(duì)象讀寫原型對(duì)象成員 更簡(jiǎn)單的原型語(yǔ)法

我們注意到,前面例子中每添加一個(gè)屬性和方法就要敲一遍 Person.prototype 。

為減少不必要的輸入,更常見的做法是用一個(gè)包含所有屬性和方法的對(duì)象字面量來重寫整個(gè)原型對(duì)象:

function Person (name, age) {
  this.name = name
  this.age = age
}

Person.prototype = {
  type: "human",
  sayHello: function () {
    console.log("我叫" + this.name + ",我今年" + this.age + "歲了")
  }
}

在該示例中,我們將 Person.prototype 重置到了一個(gè)新的對(duì)象。

這樣做的好處就是為 Person.prototype 添加成員簡(jiǎn)單了,但是也會(huì)帶來一個(gè)問題,那就是原型對(duì)象丟失了 constructor 成員。

所以,我們?yōu)榱吮3?constructor 的指向正確,建議的寫法是:

function Person (name, age) {
  this.name = name
  this.age = age
}

Person.prototype = {
  constructor: Person, // => 手動(dòng)將 constructor 指向正確的構(gòu)造函數(shù)
  type: "human",
  sayHello: function () {
    console.log("我叫" + this.name + ",我今年" + this.age + "歲了")
  }
}
原生對(duì)象的原型

所有函數(shù)都有 prototype 屬性對(duì)象。

Object.prototype

Function.prototype

Array.prototype

String.prototype

Number.prototype

Date.prototype

...

練習(xí):為數(shù)組對(duì)象和字符串對(duì)象擴(kuò)展原型方法

繼承 什么是繼承

現(xiàn)實(shí)生活中的繼承

程序中的繼承

構(gòu)造函數(shù)的屬性繼承:借用構(gòu)造函數(shù)
function Person (name, age) {
  this.type = "human"
  this.name = name
  this.age = age
}

function Student (name, age) {
  // 借用構(gòu)造函數(shù)繼承屬性成員
  Person.call(this, name, age)
}

var s1 = Student("張三", 18)
console.log(s1.type, s1.name, s1.age) // => human 張三 18
構(gòu)造函數(shù)的原型方法繼承:拷貝繼承(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)
}

// 原型對(duì)象拷貝繼承原型對(duì)象成員
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)
}

// 利用原型的特性實(shí)現(xiàn)繼承
Student.prototype = new Person()

var s1 = Student("張三", 18)

console.log(s1.type) // => human

s1.sayName() // => hello 張三
函數(shù)進(jìn)階 函數(shù)內(nèi) this 指向的不同場(chǎng)景

函數(shù)的調(diào)用方式?jīng)Q定了 this 指向的不同:

這就是對(duì)函數(shù)內(nèi)部 this 指向的基本整理,寫代碼寫多了自然而然就熟悉了。
函數(shù)也是對(duì)象

所有函數(shù)都是 Function 的實(shí)例

call、apply、bind

那了解了函數(shù) this 指向的不同場(chǎng)景之后,我們知道有些情況下我們?yōu)榱耸褂媚撤N特定環(huán)境的 this 引用,

這時(shí)候時(shí)候我們就需要采用一些特殊手段來處理了,例如我們經(jīng)常在定時(shí)器外部備份 this 引用,然后在定時(shí)器函數(shù)內(nèi)部使用外部 this 的引用。

然而實(shí)際上對(duì)于這種做法我們的 JavaScript 為我們專門提供了一些函數(shù)方法用來幫我們更優(yōu)雅的處理函數(shù)內(nèi)部 this 指向問題。

這就是接下來我們要學(xué)習(xí)的 call、apply、bind 三個(gè)函數(shù)方法。

call

call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值和分別地提供的參數(shù)(參數(shù)的列表)。

注意:該方法的作用和 apply() 方法類似,只有一個(gè)區(qū)別,就是 call() 方法接受的是若干個(gè)參數(shù)的列表,而 apply() 方法接受的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。

語(yǔ)法:

fun.call(thisArg[, arg1[, arg2[, ...]]])

參數(shù):

thisArg

在 fun 函數(shù)運(yùn)行時(shí)指定的 this 值

如果指定了 null 或者 undefined 則內(nèi)部 this 指向 window

arg1, arg2, ...

指定的參數(shù)列表

apply

apply() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值,以及作為一個(gè)數(shù)組(或類似數(shù)組的對(duì)象)提供的參數(shù)。

注意:該方法的作用和 call() 方法類似,只有一個(gè)區(qū)別,就是 call() 方法接受的是若干個(gè)參數(shù)的列表,而 apply() 方法接受的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。

語(yǔ)法:

fun.apply(thisArg, [argsArray])

參數(shù):

thisArg

argsArray

apply() 與 call() 非常相似,不同之處在于提供參數(shù)的方式。

apply() 使用參數(shù)數(shù)組而不是一組參數(shù)列表。例如:

fun.apply(this, ["eat", "bananas"])

bind

bind() 函數(shù)會(huì)創(chuàng)建一個(gè)新函數(shù)(稱為綁定函數(shù)),新函數(shù)與被調(diào)函數(shù)(綁定函數(shù)的目標(biāo)函數(shù))具有相同的函數(shù)體(在 ECMAScript 5 規(guī)范中內(nèi)置的call屬性)。

當(dāng)目標(biāo)函數(shù)被調(diào)用時(shí) this 值綁定到 bind() 的第一個(gè)參數(shù),該參數(shù)不能被重寫。綁定函數(shù)被調(diào)用時(shí),bind() 也接受預(yù)設(shè)的參數(shù)提供給原函數(shù)。

一個(gè)綁定函數(shù)也能使用new操作符創(chuàng)建對(duì)象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的 this 值被忽略,同時(shí)調(diào)用時(shí)的參數(shù)被提供給模擬函數(shù)。

語(yǔ)法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

參數(shù):

thisArg

當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的 this 指向。當(dāng)使用new 操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無效。

arg1, arg2, ...

當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法。

返回值:

返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝。

小結(jié)

call 和 apply 特性一樣

都是用來調(diào)用函數(shù),而且是立即調(diào)用

但是可以在調(diào)用函數(shù)的同時(shí),通過第一個(gè)參數(shù)指定函數(shù)內(nèi)部 this 的指向

call 調(diào)用的時(shí)候,參數(shù)必須以參數(shù)列表的形式進(jìn)行傳遞,也就是以逗號(hào)分隔的方式依次傳遞即可

apply 調(diào)用的時(shí)候,參數(shù)必須是一個(gè)數(shù)組,然后在執(zhí)行的時(shí)候,會(huì)將數(shù)組內(nèi)部的元素一個(gè)一個(gè)拿出來,與形參一一對(duì)應(yīng)進(jìn)行傳遞

如果第一個(gè)參數(shù)指定了 null 或者 undefined 則內(nèi)部 this 指向 window

bind

可以用來指定內(nèi)部 this 的指向,然后生成一個(gè)改變了 this 指向的新的函數(shù)

它和 call、apply 最大的區(qū)別是:bind 不會(huì)調(diào)用

bind 支持傳遞參數(shù),它的傳參方式比較特殊,一共有兩個(gè)位置可以傳遞

在 bind 的同時(shí),以參數(shù)列表的形式進(jìn)行傳遞

在調(diào)用的時(shí)候,以參數(shù)列表的形式進(jìn)行傳遞

那到底以誰 bind 的時(shí)候傳遞的參數(shù)為準(zhǔn)呢還是以調(diào)用的時(shí)候傳遞的參數(shù)為準(zhǔn)

兩者合并:bind 的時(shí)候傳遞的參數(shù)和調(diào)用的時(shí)候傳遞的參數(shù)會(huì)合并到一起,傳遞到函數(shù)內(nèi)部

函數(shù)的其它成員

arguments

實(shí)參集合

caller

函數(shù)的調(diào)用者

length

形參的個(gè)數(shù)

name

函數(shù)的名稱

function fn(x, y, z) {
  console.log(fn.length) // => 形參的個(gè)數(shù)
  console.log(arguments) // 偽數(shù)組實(shí)參參數(shù)集合
  console.log(arguments.callee === fn) // 函數(shù)本身
  console.log(fn.caller) // 函數(shù)的調(diào)用者
  console.log(fn.name) // => 函數(shù)的名字
}

function f() {
  fn(10, 20, 30)
}

f()
什么是閉包

閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),

由于在 Javascript 語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,

因此可以把閉包簡(jiǎn)單理解成 “定義在一個(gè)函數(shù)內(nèi)部的函數(shù)”。

所以,在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來的一座橋梁。

閉包的用途:

可以在函數(shù)外部讀取函數(shù)內(nèi)部成員

讓函數(shù)內(nèi)成員始終存活在內(nèi)存中

一些關(guān)于閉包的例子
示例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)
正則表達(dá)式

了解正則表達(dá)式基本語(yǔ)法

能夠使用JavaScript的正則對(duì)象

正則表達(dá)式簡(jiǎn)介

什么是正則表達(dá)式

正則表達(dá)式是對(duì)字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個(gè)“規(guī)則字符串”,這個(gè)“規(guī)則字符串”用來表達(dá)對(duì)字符串的一種過濾邏輯。

JavaScript 中使用正則表達(dá)式 創(chuàng)建正則對(duì)象

方式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";
// 正則表達(dá)式中的()作為分組來使用,獲取分組匹配到的結(jié)果用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);
案例:表單驗(yàn)證
QQ號(hào):
郵箱:
手機(jī):
生日:
姓名:
//獲取文本框
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 () {
  //獲取當(dāng)前文本框?qū)?yīng)的span
  var span = this.nextElementSibling;
  var reg = /^d{5,12}$/;
  //判斷驗(yàn)證是否成功
  if(!reg.test(this.value) ){
    //驗(yàn)證不成功
    span.innerText = "請(qǐng)輸入正確的QQ號(hào)";
    span.style.color = "red";
  }else{
    //驗(yàn)證成功
    span.innerText = "";
    span.style.color = "";
  }
};

//txtEMail
txtEMail.onblur = function () {
  //獲取當(dāng)前文本框?qū)?yīng)的span
  var span = this.nextElementSibling;
  var reg = /^w+@w+.w+(.w+)?$/;
  //判斷驗(yàn)證是否成功
  if(!reg.test(this.value) ){
    //驗(yàn)證不成功
    span.innerText = "請(qǐng)輸入正確的EMail地址";
    span.style.color = "red";
  }else{
    //驗(yàn)證成功
    span.innerText = "";
    span.style.color = "";
  }
};

表單驗(yàn)證部分,封裝成函數(shù):

var regBirthday = /^d{4}-d{1,2}-d{1,2}$/;
addCheck(txtBirthday, regBirthday, "請(qǐng)輸入正確的出生日期");
//給文本框添加驗(yàn)證
function addCheck(element, reg, tip) {
  element.onblur = function () {
    //獲取當(dāng)前文本框?qū)?yīng)的span
    var span = this.nextElementSibling;
    //判斷驗(yàn)證是否成功
    if(!reg.test(this.value) ){
      //驗(yàn)證不成功
      span.innerText = tip;
      span.style.color = "red";
    }else{
      //驗(yàn)證成功
      span.innerText = "";
      span.style.color = "";
    }
  };
}

通過給元素增加自定義驗(yàn)證屬性對(duì)表單進(jìn)行驗(yàn)證:

QQ號(hào):
郵箱:
手機(jī):
生日:
姓名:
// 所有的驗(yàn)證規(guī)則
var rules = [
  {
    name: "qq",
    reg: /^d{5,12}$/,
    tip: "請(qǐng)輸入正確的QQ"
  },
  {
    name: "email",
    reg: /^w+@w+.w+(.w+)?$/,
    tip: "請(qǐng)輸入正確的郵箱地址"
  },
  {
    name: "phone",
    reg: /^d{11}$/,
    tip: "請(qǐng)輸入正確的手機(jī)號(hào)碼"
  },
  {
    name: "date",
    reg: /^d{4}-d{1,2}-d{1,2}$/,
    tip: "請(qǐng)輸入正確的出生日期"
  },
  {
    name: "cn",
    reg: /^[u4e00-u9fa5]{2,4}$/,
    tip: "請(qǐng)輸入正確的姓名"
  }];

addCheck("frm");


//給文本框添加驗(yàn)證
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屬性的元素添加驗(yàn)證
    if (element.name) {
      element.onblur = function () {
        // 使用dataset獲取data-自定義屬性的值
        var ruleName = this.dataset.rule;
        var rule =getRuleByRuleName(rules, ruleName);

        var span = this.nextElementSibling;
        //判斷驗(yàn)證是否成功
        if(!rule.reg.test(this.value) ){
          //驗(yàn)證不成功
          span.innerText = rule.tip;
          span.style.color = "red";
        }else{
          //驗(yàn)證成功
          span.innerText = "";
          span.style.color = "";
        }
      }
    }
  }
}

// 根據(jù)規(guī)則的名稱獲取規(guī)則對(duì)象
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;
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/101432.html

相關(guān)文章

  • JS高級(jí)講解面向對(duì)象,原型繼承,閉包正則達(dá)式,讓你徹底愛上前端進(jìn)階

    摘要:通過構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的對(duì)象的指針。 JavaScript 高級(jí) 學(xué)習(xí)目標(biāo): 理解面向?qū)ο箝_發(fā)思想 掌握 JavaScript 面向?qū)ο箝_發(fā)相關(guān)模式 掌握在 JavaScript 中使用正則表達(dá)式 面向?qū)ο蠼榻B 程序中面向?qū)ο蟮幕倔w現(xiàn) 在 JavaScript 中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。自定義的對(duì)象數(shù)據(jù)類型就是面向?qū)ο笾?..

    source 評(píng)論0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語(yǔ)言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評(píng)論0 收藏0
  • JS程序

    摘要:設(shè)計(jì)模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時(shí)候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計(jì)模式必須要先搞懂面向?qū)ο缶幊?,否則只會(huì)讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識(shí)只有分享才有存在的意義。 是時(shí)候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...

    melody_lql 評(píng)論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<