編譯發生在代碼執行前幾微秒,簡單來講就是js在執行前要進行編譯,編譯過程發生在代碼執行前幾微妙,甚至更短。閉包
若是查找的目的是對變量進行賦值,那麼就會使用 LHS 查詢;若是目的是獲取變量的值,就會使用 RHS 查詢。app
決定於你在寫代碼時的塊級做用域ide
依賴於詞法的靜態分析函數
在詞法分析階段,沒法知道eval with會對做用域作怎樣的修改,此時引擎再也不對做用域進行任何優化優化
區分函數聲明和表達式最簡單的方法是看 function 關鍵字出如今聲明中的位
置(不只僅是一行代碼,而是整個聲明中的位置)。若是 function 是聲明中
的第一個詞,那麼就是一個函數聲明,不然就是一個函數表達式。this
變量(包括函數在內)的全部聲明都會優先執行,只有聲明自己會提高,而賦值或其餘運行邏輯會留在原位置prototype
這意味着不管做用域中的聲明出如今什麼地方,都將在代碼自己被執行前首先進行處理。
能夠將這個過程形象地想象成全部的聲明(變量和函數)都會被「移動」到各自做用域的
最頂端,這個過程被稱爲提高。
聲明自己會被提高,而包括函數表達式的賦值在內的賦值操做並不會提高。code
當函數可以記住或訪問所在的詞法做用域,及時是被做用域外調用,就產生了閉包對象
是在函數運行時綁定的,而非定義時。它的上下文取決於函數調用時的各類條件,和在哪裏定義的沒有關係,只取決於函數的調用方式。繼承
當函數被調用時,會建立一個執行上下文,在這個上下文裏包含了函數在哪裏沒調用(調用棧),調用函數的方法,參數等。this做爲執行上下文的一個屬性,能夠在函數執行的過程當中用到。
默認綁定
即綁定到全局,嚴格模式下回綁定到undefined。
function foo() { console.log( this.a ); } var a = 2; (function(){ "use strict"; foo(); // 2 })()
隱式綁定
即綁定到最頂層(或最近調用對象)上
function fun() { console.log(this.a) } var obj2 = { a: 3, fun: fun, } var obj1 = { a: 2, obj2: obj2, } obj1.obj2.fun() // 3
new綁定(構造函數)
new發生了什麼?
基本類型在須要的時候(好比說獲取長度),會被引擎默認轉成內置對象,從而進行方法的調用。
基礎類型並非繼承自內置對象
var strPrimitive = "I am a string"; typeof strPrimitive; // "string" strPrimitive instanceof String; // false var strObject = new String( "I am a string" ); typeof strObject; // "object" strObject instanceof String; // true Object.prototype.toString.call( strObject ); // [object String]
typeof null === Object;
原理是這樣的,不一樣的對象在底層都表示爲二進制,在 JavaScript 中二進制前三位都爲 0 的話會被判
斷爲 object 類型,null 的二進制表示是全 0,天然前三位也是 0,因此執行 typeof 時會返回「object」
getOwnPropertyDescriptor(myObj, 'a') defineProperty Object.defineProperty(myObj, 'a', { value: 2, writable: true, configurable: true, enumerable: true })
var obj = { get a() { return this._a_ }, set a(val) { this._a_ = val * 5 } } obj.a = 10 console.log(obj.a) // 50 var obj2 = {} Object.defineProperty(obj2, 'a', { get: function() { return this._a_ }, set: function(val) { this._a_ = val * 2 } }) obj2.a = 15 console.log(obj2.a) // 30
返回實例對象O的構造函數(的引用)。任何一個prototype對象都有一個constructor屬性,指向它的構造函數,每個實例也有一個constructor屬性,默認調用prototype對象的constructor屬性
例如
function Test() { this.name = 'test' } var test = new Test() console.log(test.constructor === Test) // true
構造函數 constructor 是用於建立和初始化類中建立的一個對象的一種特殊方法.
class Polygon { constructor() { this.name = "Polygon"; } } class Square extends Polygon { constructor() { super(); } } class Rectangle {} Object.setPrototypeOf(Square.prototype, Rectangle.prototype); console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true let newInstance = new Square(); console.log(newInstance.name); //Polygon
實例對象__proto__指向生成改對象的構造函數的原型
例如
|function Test() { this.name = 'test' } Test.prototype = { color: 'red' } var test = new Test() console.log(test.__proto__ === Test.prototype) // true console.log(test.__proto__)
var foo = { something: function() { console.log( "Tell me something good..." ); } }; var bar = Object.create( foo ); bar.something(); // Tell me something good... Object.create(..) 會建立一個新對象(bar)並把它關聯到咱們指定的對象(foo)
這樣 咱們就能夠充分發揮 [[Prototype]]
機制的威力(委託)而且避免沒必要要的麻煩
(好比使 用 new 的構造函數調用會生成 .prototype 和 .constructor 引用)。
缺點
實例的屬性都會指向同一個引用
實現
function Parent() { this.names = [1, 2, 3] } function Child() { } Child.prototype = new Parent() var child1 = new Child() var child2 = new Child() child1.names.push(4) console.log(child1.names) // [1,2, 3,4] console.log(child2.names) // [1,2, 3,4]
實現
function Parent() { this.names = [1, 2, 3] this.getName = function () { console.log(this.name) } } function Child() { Parent.call(this) } var child1 = new Child() var child2 = new Child() child1.names.push(4) console.log(child1.names) console.log(child2.names)
缺點
每一個子實例都會實例化方法一次,內存爆炸
實現
function Parent() { this.names = [1, 2, 3] } Parent.prototype.getName = function () { console.log(this.names) } function Child() { Parent.call(this) } Child.prototype = new Parent() var child1 = new Child() var child2 = new Child() child1.names.push(4) child1.getName() child2.getName()
缺點
實現
function Parent() { this.names = [1, 2, 3] } Parent.prototype.getName = function () { console.log(this.names) } function Child() { Parent.call(this) } Child.prototype = Object.create(Parent.prototype) var child1 = new Child() var child2 = new Child() child1.names.push(4) child1.getName() child2.getName()
優勢
屬性不會再原型鏈上重複
js中的繼承其實就是在對象間創建關聯關係,而行爲委託就是創建這種關聯關係的紐帶。
function Foo(who) { this.me = who; } Foo.prototype.identify = function () { return "I am" + this.me; }; function Bar(who) { Foo.call(this,who); } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.speak = function () { alert("Hello," + this.identify() + '.'); }; var b1 = new Bar("b1"); var b2 = new Bar("b2"); b1.speak(); b2.speak();
Foo = { init:function (who) { this.me = who; }, identify:function () { return "I am" + this.name } }; Bar = Object.create(Foo); Bar.speak = function () { alert("hello," + this.identify() + '.'); }; var b3 = Object.create(Bar); b3.init("b3"); var b4 = Object.create(Bar); b4.init("b4"); b1.speak(); b2.speak();