国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入理解JavaScript原型和閉包

missonce / 920人閱讀

摘要:本文是本人閱讀學(xué)習(xí)深入理解原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。即這里的稱為隱式原型。注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。但實(shí)際上,上述情況是一種理想的情況。

本文是本人閱讀學(xué)習(xí)深入理解JavaScript原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。

1、一切都是對(duì)象

先說(shuō)結(jié)論,一切引用類型都是對(duì)象,對(duì)象是屬性的集合

首先我們對(duì)不同變量使用typeof()看看都有哪些輸出的類型。

console.log(typeof(x));                 // undefined
console.log(typeof(10));                // number
console.log(typeof("abc"));             // string
console.log(typeof(true));              // boolean
console.log(typeof(function () {}));    // function
console.log(typeof([1, "a", true]));    // object
console.log(typeof({ a: 10, b: 20 })); // object
console.log(typeof(null));             // object
console.log(typeof(new Number(10)));   // object

在以上代碼中,undefined, number, string, boolean屬于值類型,不是對(duì)象。
而其他的幾種類型 - 包括函數(shù)、數(shù)組、對(duì)象、nullnew Number(10)都是對(duì)象,它們屬于引用類型

在JavaScript中,數(shù)組是對(duì)象,函數(shù)是對(duì)象,對(duì)象還是對(duì)象。對(duì)象里面的一切都是屬性,只有屬性,沒有方法,或者說(shuō)方法也是一種屬性。屬性表示為鍵值對(duì)的形式。

JavaScript中的對(duì)象可以任意的擴(kuò)展屬性,定義屬性的方法通常有兩種。

var obj = {
  a = 10,
  b: function(x) {
    console.log(this.a + x)
  },
  c: {
    name: "Steven",
    year: 1988
  }
}

上面這段代碼中,obj是一個(gè)自定義的對(duì)象,其中abc是它的屬性,而屬性c的本身又是一個(gè)對(duì)象,它又有nameyear兩個(gè)屬性。

函數(shù)和數(shù)組不能用上面的方法定義屬性,下面以函數(shù)為例:

var fn = function () {
  alert(100);
};
fn.a = 10;
fn.b = function () {
  alert(123);
};
fn.c = {
  name: "Steven",
  year: 1988
};

在jQuery源碼中,變量jQuery或者$其實(shí)是一個(gè)函數(shù),我們可以用typeof()驗(yàn)證一下:

console.log(typeof ($));  // function
console.log($.trim(" ABC "));

很明顯,這就是在$或者jQuery函數(shù)上加了一個(gè)trim屬性,屬性值是函數(shù),作用是截取前后空格。

2、函數(shù)和對(duì)象的關(guān)系

上文已經(jīng)說(shuō)到,函數(shù)也是一種對(duì)象,我們可以用instanceof驗(yàn)證一下:

var fn = function () { };
console.log(fn instanceof Object);  // true

但是函數(shù)和對(duì)象的關(guān)系卻有一點(diǎn)復(fù)雜,請(qǐng)看下面這個(gè)例子:

function Fn() {
  this.name = "嚴(yán)新晨";
  this.year = 1990;
}
var fn_1 = new Fn();

由上面這個(gè)例子可以得出,對(duì)象是可以通過(guò)函數(shù)創(chuàng)建的。

但其實(shí),對(duì)象都是通過(guò)函數(shù)創(chuàng)建的

var obj = { a: 10, b: 20 };
var arr = [5, "x", true];

上面這種方式,其實(shí)是一個(gè)語(yǔ)法糖,而這段代碼的本質(zhì)是:

var obj = new Object();
obj.a = 10;
obj.b = 20;

var arr = new Array();
arr[0] = 5;
arr[1] = "x";
arr[2] = true;

而其中的ObjectArray都是函數(shù):

console.log(typeof (Object));  // function
console.log(typeof (Array));  // function

由此可以得出,對(duì)象都是通過(guò)函數(shù)創(chuàng)建的

3、prototype原型

每個(gè)函數(shù)都有一個(gè)默認(rèn)屬性 - prototype

這個(gè)prototype的屬性值是一個(gè)對(duì)象,這個(gè)對(duì)象有一個(gè)默認(rèn)屬性 - constructor,這個(gè)屬性指向這個(gè)函數(shù)本身。

而原型作為一個(gè)對(duì)象,除了constructor之外,當(dāng)然可以有其他屬性,以函數(shù)Object為例,在瀏覽器調(diào)試窗口輸入Object.prototype會(huì)得到以下返回值:

Object
  ...
  constructor
  hasOwnProperty
  isPrototypeOfs
  toLocalString
  toString
  valueOf
  ...

同時(shí),我們還可以為這個(gè)原型增添自定義方法或?qū)傩?/p>

function Fn(){}
Fn.prototype.name = "Steven"
Fn.prototype.getYear = function(){
  return 1988;
}

var fn = new Fn();
console.log(fn.name);
console.log(fn.getYear());

在上例中,Fn是一個(gè)函數(shù),fn對(duì)象是從Fn函數(shù)中new出來(lái)的,這樣fn對(duì)象就可以調(diào)用Fn.prototype中的屬性。

每個(gè)對(duì)象都有一個(gè)隱藏的屬性 - __proto__,這個(gè)屬性引用了創(chuàng)建這個(gè)對(duì)象的函數(shù)的prototype。即:fn.__proto__ === Fn.prototype

這里的__proto__稱為“隱式原型”。

4、隱式原型

每個(gè)函數(shù)function都有一個(gè)prototype,即原型。

每個(gè)對(duì)象都有一個(gè)__proto__,可稱為隱式原型。

var obj = {}
console.log(obj.__proto__ === Object.prototype) // true

每個(gè)對(duì)象都有一個(gè)__proto__屬性,指向創(chuàng)建該對(duì)象的函數(shù)的prototype

function Foo(){}
Foo.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true 
Function.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

注意,Object.prototype.__proto__是一個(gè)特例,它指向的是null

5、instanceof

由于typeof在判斷引用類型時(shí),返回值只有objectfunction,這時(shí)我們可以用到instanceof

function Foo(){}
var f = new Foo()

console.log(f instanceof Foo) // true
console.log(f instanceof Object) // true

用法:A instanceof B,變量A是一個(gè)待判斷的對(duì)象,變量B通常是一個(gè)函數(shù)。

判斷規(guī)則:沿著A.__proto__B.prototype查找,如果能找到同一個(gè)引用,即同一個(gè)對(duì)象,則返回true

由以上判定規(guī)則,我們可以解釋許多奇怪的判定結(jié)果,例如:

Object instanceof Function // true
Function instanceof Object // true
Function instanceof Function // true

instanceof表示的是一種繼承關(guān)系 - 原型鏈

6、繼承

JavaScript中的繼承通過(guò)原型鏈來(lái)體現(xiàn)。

function Foo(){}
var f = new Foo()

f.a = 10

Foo.prototype.a = 100
Foo.prototype.b = 200

console.log(f.a) // 10
console.log(f.b) // 200

上例中,f是Foo函數(shù)new出來(lái)的對(duì)象,f.a是對(duì)象f的基本屬性,因?yàn)?b>f.__proto__ === Foo.prototype,所以f.b是從Foo.prototype中繼承而來(lái)的。

在JavaScript中,訪問一個(gè)對(duì)象的屬性時(shí),先在基本屬性中查找,如果沒有,再沿著__proto__這條鏈向上找,這就是原型鏈

通過(guò)hasOwnProperty,我們可以判斷出一個(gè)屬性到底是基本屬性,還是從原型中繼承而來(lái)的。

function Foo(){}
var f_1 = new Foo()

f.a = 10

Foo.prototype.a = 100
Foo.prototype.b = 200

var item

for(item in f){
  console.log(item) // a b
}

for(item in f){
  if(f.hasOwnProperty(item){
    console.log(item) // a
  })
}

hasOwnProperty方法是從Object.prototype中繼承而來(lái)的

每個(gè)函數(shù)都有applycall方法,都有lengtharguments等屬性,這些都是從Function.prototype中繼承而來(lái)的

由于Function.prototype.__proto__指向Object.prototype,所以函數(shù)也會(huì)有hasOwnProperty方法

7、原型的靈活性

首先,對(duì)象屬性可以隨時(shí)改動(dòng)

其次,如果繼承的方法不合適,可以隨時(shí)修改

var obj = { a: 10, b: 20 }
console.log(obj.toString()) // [object Object]

var arr = [1, 2, true]
console.log(arr.toString()) // 1, 2, true

從上例中可以看出,ObjectArraytoString()方法是不一樣的,肯定是Array.prototype.toString()作了修改。

同理,我們也可以自己定義一個(gè)函數(shù)并修改toString()方法。

function Foo(){}
var f = new Foo()

Foo.prototype.toString = function(){
  return "嚴(yán)新晨"
}

console.log(f.toString) // 嚴(yán)新晨

最后,如果缺少需要的方法,也可以自己創(chuàng)建

如果要添加內(nèi)置方法的原型屬性,最好做一步判斷,如果該屬性不存在,則添加。如果本來(lái)就存在,就沒必要再添加了。

8、簡(jiǎn)述 - 執(zhí)行上下文 - 上

執(zhí)行上下文,也叫執(zhí)行上下文環(huán)境

console.log(a) // 報(bào)錯(cuò),a is not undefined
console.log(a) // undefined
var a;
console.log(a) // undefined
var a  = 10;
console.log(this) // Window {...}
console.log(f_1) // function f_1({})
function f_1(){} // 函數(shù)聲明

console.log(f_2) // undefined
var f_2 = function(){} // 函數(shù)表達(dá)式

在js代碼執(zhí)行前,瀏覽器會(huì)先進(jìn)行一些準(zhǔn)備工作:

變量、函數(shù)表達(dá)式 - 變量聲明,默認(rèn)賦值為undefined

this - 賦值;

函數(shù)聲明 - 賦值;

這三種數(shù)據(jù)的準(zhǔn)備工作我們稱之為“執(zhí)行上下文”或者“執(zhí)行上下文環(huán)境”。

JavaScript在執(zhí)行一個(gè)代碼段之前,都會(huì)進(jìn)行這些“準(zhǔn)備工作”來(lái)生成執(zhí)行上下文。這個(gè)“代碼段”其實(shí)分三種情況 - 全局代碼函數(shù)體eval代碼

首先,全局代碼,寫在

以下面代碼為例:

var a = 10, // 1、進(jìn)入全局上下文環(huán)境
    fn,
    bar = function(x){
      var x = 5
      fn(x+b) // 3、進(jìn)入fn()函數(shù)上下文環(huán)境
    }

fn = function(y){
  var c = 5
  console.log(y+c)
}

bar() // 2、進(jìn)入bar()函數(shù)上下文環(huán)境

執(zhí)行代碼前,首次創(chuàng)建全局上下文環(huán)境

a === undefined
fn === undefined
bar === undefined
this === window

代碼執(zhí)行時(shí),全局上下文環(huán)境中的各個(gè)變量被賦值

a === 10
fn === function
bar === function
this === window

調(diào)用bar()函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)新的函數(shù)上下文環(huán)境

b === undefined
x === 5
arguments === [5]
this === window

以上是一段簡(jiǎn)短代碼的執(zhí)行上下文環(huán)境的變化過(guò)程,一個(gè)完整的閉環(huán)。

但實(shí)際上,上述情況是一種理想的情況。而有一種很常見的情況,無(wú)法做到這樣干凈利落的說(shuō)銷毀就銷毀,那就是閉包。

12、簡(jiǎn)述 - 作用域

JavaScript沒有塊級(jí)作用域。所謂的“塊”就是“{}”中的語(yǔ)句,比如:if(){}或者for(){}之類的。

所以,編寫代碼時(shí)不要在“塊”里聲明變量。

重點(diǎn)來(lái)了:JavaScript除了全局作用域之外,只有函數(shù)可以創(chuàng)建的作用域

所以,在聲明變量時(shí),全局代碼要在代碼前端聲明,函數(shù)中要在函數(shù)體一開始就聲明好。除了這兩個(gè)地方,其他地方都不要出現(xiàn)變量聲明。而且建議用“單var”形式。

作用域有上下級(jí)的關(guān)系,上下級(jí)關(guān)系的確定就看函數(shù)是在哪個(gè)作用域下創(chuàng)建的

作用域最大的用處就是隔離變量,不同作用域下同名變量不會(huì)有沖突

13、作用域和上下文環(huán)境

在上文中已經(jīng)說(shuō)過(guò),除了全局作用域之外,每個(gè)函數(shù)都會(huì)創(chuàng)建自己的作用域。作用域在函數(shù)定義時(shí)就已經(jīng)確定了,而不是在函數(shù)調(diào)用時(shí)確定

var a = 10,
    b = 20;
    // 全局作用域:a=10,b=20

function fn(x){
  var a = 100,
      c = 300;
      // fn(10):a=100,c=300,x=10

  function bar(x){
    var a = 1000,
        d = 4000;
        // bar(100):a=1000,d=4000,x=100
        // bar(100):a=1000,d=4000,x=200
  }
  bar(100);
  bar(200);
}
fn(10)

作用域只是一個(gè)“地盤”,一個(gè)抽象的概念,其中沒有變量
要通過(guò)作用域?qū)?yīng)的執(zhí)行上下文環(huán)境來(lái)獲取變量的值
**同一個(gè)作用域下,不同的調(diào)用會(huì)產(chǎn)生不同的執(zhí)行上下文環(huán)境,繼而產(chǎn)生不同的變量的值。
所以,作用域中變量的值是在執(zhí)行過(guò)程中產(chǎn)生的確定的,而作用域是在函數(shù)創(chuàng)建時(shí)就確定了
所以,如果要查找一個(gè)作用域下某個(gè)變量的值,就需要找到這個(gè)作用域?qū)?yīng)的執(zhí)行上下文環(huán)境,再在其中尋找變量的值

14、從自由變量到作用域鏈

上文中有一種常見情況我們并沒有討論,那就是跨作用域取值的情況。

先說(shuō)明一個(gè)概念 - 自由變量

var a = 10
function fn(){
  var b = 20
  return a + b // 這里的a就是一個(gè)自由變量
}

很多人對(duì)此解釋為a是從父作用域取值的,這種說(shuō)法基本正確,但有些時(shí)候會(huì)產(chǎn)生歧義。

var x = 10;
function fn(){
  console.log(x) // 10
}

function show(f){
  var x = 20;
  (function(){
    f() // 10,而不是20
  })()
}

show(fn);

所以,更準(zhǔn)確的說(shuō)法是,我們要到創(chuàng)建這個(gè)函數(shù)的作用域中去取值

var a = 10;
function fn() {
  var b = 20;
  function bar() {
    console.log(a + b);
    // 創(chuàng)建函數(shù)bar()時(shí),b=20
    // 通過(guò)作用域鏈查找到a=10
  }
  return bar;
}

var x = fn(),
    b = 200;

x(); // 30
15、閉包

先回顧下前面章節(jié)講到的兩個(gè)重點(diǎn):

自由變量跨作用域取值時(shí),要去創(chuàng)建函數(shù)的作用域取值,而不是調(diào)用函數(shù)的作用域;

當(dāng)一個(gè)函數(shù)被調(diào)用完成之后,其執(zhí)行上下文環(huán)境將被銷毀,其中的變量也會(huì)被同時(shí)銷毀。

“閉包”這個(gè)詞的概念很不好解釋,但我們只需記住兩種情況即可:函數(shù)作為返回值和函數(shù)作為參數(shù)傳遞

首先,函數(shù)作為返回值,先看個(gè)例子

// 1、全局作用域,max=100,其他變量undefined
function fn() {
  // 2、fn()作用域,max=10(調(diào)用結(jié)束后銷毀),其他變量undefined
  var max = 10;
  return function bar(x) {
    // 3、bar()作用域,max=10,x=15(調(diào)用結(jié)束后銷毀)
    if (x > max) {
      console.log(x);
    }
  }
}
var f1 = fn(), // bar()作為返回值賦值給f1
    max = 100;
f1(15); // 15

然后,函數(shù)作為參數(shù)傳遞,再看個(gè)例子

// 全局作用域,max=10
var max = 10,
    fn = function (x) {
      if (x > max) {
        console.log(x) // 15
      }
    };
(function (f) {
  var max = 100;
  f(15); // max=10而不是100
})(fn);

先回顧下前面章節(jié)講到的兩個(gè)重點(diǎn):

自由變量跨作用域取值時(shí),要去創(chuàng)建函數(shù)的作用域取值,而不是調(diào)用函數(shù)的作用域;

當(dāng)一個(gè)函數(shù)被調(diào)用完成之后,其執(zhí)行上下文環(huán)境將被銷毀,其中的變量也會(huì)被同時(shí)銷毀。

16、完結(jié) - 這章沒干貨我也就不寫了o(╯□╰)o 17、補(bǔ)充 - this - 我直接寫在10、this那一篇里了就不贅述了 18、補(bǔ)充 - 上下文環(huán)境和作用域的關(guān)系

本篇主要是解釋一下上下文環(huán)境和作用域并不是一回事

上下文環(huán)境 - 可以理解為一個(gè)看不見摸不著的對(duì)象(有若干個(gè)屬性),在調(diào)用函數(shù)時(shí)創(chuàng)建,用來(lái)保存調(diào)用函數(shù)時(shí)的各個(gè)變量。

作用域 - 除了全局作用域,只有創(chuàng)建函數(shù)才會(huì)創(chuàng)建作用域,無(wú)論你是否調(diào)用函數(shù),函數(shù)只要?jiǎng)?chuàng)建了就有一個(gè)獨(dú)立的作用域。

兩者 - 一個(gè)作用域可能包含若干個(gè)上下文環(huán)境,也可能從來(lái)沒有過(guò)上下文環(huán)境(函數(shù)從未被調(diào)用),還可能函數(shù)調(diào)用完畢后上下文環(huán)境被銷毀了等多種情況。

以下面代碼為例:

// 全局作用域中x=100
var x = 100;
function fn(x) {
  // fn(x)作用域
  // 調(diào)用f1()時(shí)的上下文環(huán)境中,x=5
  // 調(diào)用f2()時(shí)的上下文環(huán)境中,x=10
  return function () {
    // 匿名function作用域
    console.log(x);
  }
}
var f1 = fn(5),
    f2 = fn(10);
f1(); // 5
f2(); // 10

所謂上下文環(huán)境就是調(diào)用函數(shù)時(shí)創(chuàng)建的一個(gè)臨時(shí)作用域,根據(jù)調(diào)用情況不同里面的變量會(huì)發(fā)生變化;而作用域是隨著函數(shù)的創(chuàng)建而創(chuàng)建,里面的變量可能會(huì)在調(diào)用時(shí)被上下文環(huán)境中相同變量覆蓋。

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

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

相關(guān)文章

  • 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ī)?lái)幫助....(據(jù)說(shuō)是阿里的前端妹子寫的) this 的值到底...

    blair 評(píng)論0 收藏0
  • 深入理解javascript原型閉包

    摘要:深入理解原型和閉包王福朋博客園深入理解原型和閉包一切都是對(duì)象原文鏈接本文要點(diǎn)一切引用類型都是對(duì)象,對(duì)象是屬性的集合。每個(gè)對(duì)象都有一個(gè),可稱為隱式原型。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。 深入理解javascript原型和閉包 王福朋 - 博客園 —— 《 深入理解javascript原型和閉包》 1. 一切都是對(duì)象 原文鏈接:http://www.cnblogs.com...

    jemygraw 評(píng)論0 收藏0
  • 深入理解JavaScript,這一篇就夠了

    摘要:也就是說(shuō),所有的函數(shù)和構(gòu)造函數(shù)都是由生成,包括本身。如果只考慮構(gòu)造函數(shù)和及其關(guān)聯(lián)的原型對(duì)象,在不解決懸念的情況下,圖形是這樣的可以看到,每一個(gè)構(gòu)造函數(shù)和它關(guān)聯(lián)的原型對(duì)象構(gòu)成一個(gè)環(huán),而且每一個(gè)構(gòu)造函數(shù)的屬性無(wú)所指。 前言  JavaScript 是我接觸到的第二門編程語(yǔ)言,第一門是 C 語(yǔ)言。然后才是 C++、Java 還有其它一些什么。所以我對(duì) JavaScript 是非常有感情的,畢...

    villainhr 評(píng)論0 收藏0
  • 深入理解javascript原型閉包

    摘要:情況構(gòu)造函數(shù)所謂構(gòu)造函數(shù)就是用來(lái)對(duì)象的函數(shù)。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。閉包但是你只需要知道應(yīng)用的兩種情況即可函數(shù)作為返回值,函數(shù)作為參數(shù)傳遞。如上代碼,函數(shù)作為返回值,賦值給變量。這就是需要理解閉包的核心內(nèi)容。 原文鏈接http://www.cnblogs.com/wangfupeng1988/p/3977924.html 對(duì)象是屬性的集合。 function ...

    _ang 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過(guò)程中的問題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<