首先咱們要知道在ES6以前JS是沒有塊級做用域的。那時只能經過函數來建立局部做用域,那麼做用域究竟是什麼呢?首先咱們須要瞭解的是做用域作什麼的?當JavaScript引擎在某一做用域中碰見變量和函數的時候,須要可以明確變量和函數所對應的值是什麼,因此就須要做用域來對變量和函數進行查找,而且還須要肯定當前代碼是否對該變量具備訪問權限。說白了所謂做用域,就是變量或者是函數能做用的範圍。bash
那麼JavaScript中有哪些做用域呢?函數
咱們所定義的除了函數裏的變量之外的全部變量都在全局做用域內。this
var str ="hello world"
var arr =[1,2,3]
var obj ={name:"cxk"}
var a=1;
function f(){
var b=2;
}
複製代碼
上面定義的全部變量只有b不在全局做用域裏,由於b被定義在f函數內,與此同時b所在的做用域就叫作局部做用域。spa
ES6以後出現了let和const能夠定義變量,而它們所定義的變量就存在着塊級做用域。prototype
let a=1;
}
consloe.log(a)
複製代碼
運行代碼會報錯:a is not defined 代碼中的{}就是一個因爲let定義變量而造成的塊級做用域,a這個變量只有在{}中才能訪問。3d
變量隨着做用長輩函數一級一級往上搜索,直到找到爲止,找不到就報錯,這個過程就是做用域鏈起的做用。咱們也能夠從執行上下文這個角度來理解做用域鏈這個概念。code
function Outer(){
var outer = 'outer';
Inner();
function Inner(){
var inner = 'inner';
console.log(outer,inner) // outer inner
}
}
複製代碼
當咱們調用Inner函數時它會在本身的函數執行上下文找outer和inner變量,結果只找到了inner。那麼這時它就去本身的父函數Outer中找outer變量,找到了就返回給Inner函數。因此這種逐級去本身的父函數的執行上下文中搜索變量的方式就是做用域鏈。orm
在JavaScript中一切皆對象,那麼函數也是一個對象。因此這函數裏也有不少屬性,這其中必然有一個prototype
屬性 cdn
var Person = function(name){
this.name = name;
}
Person.prototype.say = function(){
console.log( this.name)
};
var person = new Person('cxk');
person.say();//cxk
複製代碼
上面的例子中,對象person是new Person建立的實例,在使用new操做符調用函數時主要執行如下幾個步驟:對象
1,建立新的對象,並將函數的this指向新建立的對象
2,執行函數
3,返回新建立的對象
4,將本身的__proto__(隱式原型對象)指向構造函數的原型對象
與此同時原型對象中的constructor也指向了構造器
因爲原型對象也是一個對象,因此它也有一個__proto__指向它的構造器Object,一樣的Object也有一個__proto__指向Null。
因此當咱們想使用對象的某些方法時例如obj.a()
會先到本身的__proto__對象中找,若是沒有就會去它的原型對象的原型對象中找,也就是__proto__.proto 。以此類推...
至此做用域鏈和原型鏈介紹完了,若有錯誤還望指正,謝謝。