// new 的實現原理 // 簡單的雙向綁定 1.new 2.Function 3.this 若是函數掛載在一個對象上,做爲對象的一個屬性,就稱它爲對象的方法。當經過這個對象來調用函數時,該對象就是這次調用的上下文(context),也就是該函數的this的值。 4.constructor 用於初始化一個新建立的對象的函數就是這次調用的上下文。 在JS中函數即對象,程序能夠隨意操控它們。好比:JS能夠把函數賦值給變量,或者做爲參數傳遞給其餘函數。由於函數就是對象,因此能夠給它們設置屬性,甚至調用它們的方法。 JS的函數可嵌套在其餘函數中定義,這樣它們就能夠訪問它們被定義時所處的做用域中的任何變量。這意味着JS函數構成了一個閉包(closure),它給JS帶來了很是強勁的編程能力。編程
嵌套函數bash
function hypotenuse(a, b) {
function square(x) {
return x * x
}
return Math.sqrt(square(a) + square(b))
}
function square(x) {return x * x}
function hypotenuse(a, b) {
return Math.sqrt(square(a) + square(b))
}
複製代碼
函數調用 構成函數主體的JS代碼在執行之時並不會調用,只有調用該函數時,它們再回執行。有4種方式來調用JS函數。閉包
1.做爲函數調用,對於普通的函數調用,函數的返回值成爲調用表達式的值。若是該函數返回值是由於解釋器到達結尾,返回值就是undefined。若是函數返回是由於解釋器執行到一條return語句,返回值就是return以後的表達式的值,若是return語句沒有值,則返回undefined。app
2.做爲方法調用,方法和this關鍵字是面向對象編程範例的核心。任何函數只要做爲方法調用實際上都會傳入一個隱式的實參------這個實參是一個對象,方法調用的母體就是這個對象。函數
var o = {
m: function () {
var self = this
console.log(this === o)
f()
function f() {
console.log(this === o)
console.log(self === o)
}
}
}
o.m()
複製代碼
3.做爲構造函數ui
若是函數或者方法調用以前帶有關鍵字new,它就構成構造函數調用。構造函數調用和普通的函數調用以及方法調用在實參處理、調用上下文和返回值方面都有不一樣。 構造函數調用建立一個新的空對象,這個對象繼承自構造函數的prototype屬性。構造函數試圖初始化這個新建立的對象,並將這個對象用作其調用上下文,所以構造函數能夠使用this關鍵字來引用這個新建立的對象。this
4.經過它們的call()和apply()方法間接調用spa
JS中函數也是對象,函數也能夠包含方法。 函數能夠被任意次執行或調用。prototype
原型鏈 1.建立對象有幾種方法 2.原型、構造函數、實例、原型鏈 3.instanceof的原理 4.new運算符雙向綁定
1.建立對象有幾種方法
方法1
var a = {name: 'mary'}
var b = new Object({name: 'john'})
a、b結果相同
方法2
var M = function(name) {this.name = name}
var c = new M('henri')
方法3
var P = {name: 'john'}
var d = Object.create(P)
d.__proto__ === p // true
複製代碼
每個JS對象都和另外一個對象相關聯,每個對象都從原型繼承屬性。
2.原型、構造函數、實例、原型鏈
實例:a,b,c都稱爲實例 構造函數:構造函數也是函數,任何函數只要被new操做的函數,就是構造函數。不使用new就是普通的函數。 函數:函數都有一個prototype屬性,聲明函數的時候就會被js引擎帶上。對象沒有prototype。實例有__proto__,函數沒有。 原型對象:經過constructor(構造器)來區分被哪一個構造函數所引用。
M.prototype.constructor === M
c.__proto__ === M.prototype
M.__proto__ === Function.prototype
M.prototype.__proto__ === Object.prototype // true
Object.prototype是整個原型鏈的頂端
M.prototype.run = function () {
console.log('run fast')
}
var e = new M('mary')
此時c、e都有了run方法
複製代碼
c instanceof M // true
c instanceof Object // true
c.__proto__ === M.prototype // true
M.prototype.__proto === Object.prototype // true
c.__proto__.constructor === M // true
c.__proto__.constructor === Object // false
所以用constructor比用instanceof更嚴謹
複製代碼
4.1 一個新對象被建立。它繼承自foo.prototype 4.2 構造函數foo被執行。執行的時候,相應的傳參會被傳入,同時上下文(this)會被指定爲這個新實例。new foo等同於new foo(),只能用在不傳遞任何參數的狀況下 4.3 若是構造函數返回了一個「對象」,那麼這個對象會取代整個new出來的結果。若是構造函數沒有返回對象,那麼new出來的結果爲步驟1建立的對象
new運算符背後的原理
var f = function(func) {
var o = Object.create(func.prototype)
var k = func.call(o)
if (typeof k === 'object') {
return k
} else {
return o
}
}
var h = f(M)
h instanceof M
h instanceof Object
h.__proto__.constructor === M
複製代碼
函數其實是對象,每一個函數都是Function類型的實例,並且與其餘引用類型同樣具備屬性和方法。因爲函數就是對象,所以函數名實際上也是一個指向函數對象的指針,不會與某個函數綁定。M.proto === Function.prototype function M () {
} M.proto === Function.prototype
用constructor判斷比instanceof要準確
__proto__
prototype
prototype
中繼承屬性和方法prototype
constructor
prototype
裏面prototype
的屬性和方法Object:既是對象,也是構造函數
Object.__proto__
=== Function.prototype
Object.prototype
是原型鏈的頂端,Object.prototype.__proto = null
Function: 既是對象,也是構造函數
Function.__proto__
=== Function.prototype
Function.prototype
用於共享,而Function.prototype.__proto__
繼承自Object.prototype
Array(Date、Number...):既是對象,也是構造函數
Array.__proto__
=== Function.prototype
Array.prototype
用於共享,Array.prototype.__proto__
繼承自Object.prototype
對象Person: 既是對象,也是構造函數
Person.__proto__
=== Function.prototype
Person.prototype
用於共享,·Person.prototype.__proto
繼承自Object.prototype
所以: 一、原型鏈頂端是Object.prototype
二、構造函數建立的對象(Object、Fucntion、Array、普通對象等)都是Function的實例,它們的__proto__
均指向Function.prototype
三、除了Object,全部對象(或構造函數)的prototype
,均繼承自Object.prototype