先舉一個非常簡單的例子,我有一個類叫Humans(人類),然后我有一個對象叫Tom(一個人)和另一個對象叫Merry(另一個人),很明顯Tom和Merry都是由Humans這一個類實例化之后得到的,然后可以把這個例子寫成如下代碼:functionHumans(){this.foot=2;}Humans.prototype.ability=true;varTom=newHumans();varMerry=newHumans();alert(Tom.foot);//結果:2alert(Tom.ability);//結果:truealert(Merry.foot);//結果:2alert(Merry.ability);//結果:true以上是一個非常簡單的面向對象的例子,相信都能看懂,如果嘗試修改Tom的屬性ability,則functionHumans(){this.foot=2;}Humans.prototype.ability=true;varTom=newHumans();varMerry=newHumans();Tom.ability=false;alert(Tom.foot);//結果:2alert(Tom.ability);//結果:falsealert(Merry.foot);//結果:2alert(Merry.ability);//結果:true以上可以看出Tom的ability屬性的值改變了,但并不影響Merry的ability屬性的值,這正是我們想要的結果,也是面向對象的好處,由同一個類實例化得到的各個對象之間是互不干擾的;OK,接下來給ability換成object對象又如何?代碼如下:functionHumans(){this.foot=2;}Humans.prototype.ability={run:'100米/10秒',jump:'3米'};varTom=newHumans();varMerry=newHumans();Tom.ability={run:'50米/10秒',jump:'2米'};alert(Tom.ability.run);//結果:'50米/10秒'alert(Tom.ability.jump);//結果:'2米'alert(Merry.ability.run);//結果:'100米/10秒'alert(Merry.ability.jump);//結果:'3米'以上代碼就是在原型鏈上使用了對象,但從以上代碼可以看出Tom的ability屬性的改變依然絲毫不會影響Merry的ability的屬性,于是乎你會覺得這樣的做法并無不妥,為什么說不能在原型鏈上使用對象?接下來的代碼就會顯得很不一樣,并且可以完全表達出原型鏈上使用對象的危險性:functionHumans(){this.foot=2;}Humans.prototype.ability={run:'100米/10秒',jump:'3米'};varTom=newHumans();varMerry=newHumans();Tom.ability.run='50米/10秒';Tom.ability.jump='2米';alert(Tom.ability.run);//結果:'50米/10秒'alert(Tom.ability.jump);//結果:'2米'alert(Merry.ability.run);//結果:'50米/10秒'alert(Merry.ability.jump);//結果:'2米'沒錯,從以上代碼的輸出結果可以看出Tom的ability屬性的改變影響到Merry的ability屬性了,于是就可以明白在原型鏈上使用對象是非常危險的,很容易會打破實例化對象之間的相互獨立性,這就是為什么不能在原型鏈上使用對象的原因?是的,但我想說的可不只如此,而是其中的原理,看完后面JS原型鏈的深層原理之后,相信你會完全明白。在以下第二部份解釋JS原型鏈的深層原理之前,先來明確一個概念:原型鏈上的屬性或方法都是被實例化對象共用的,正因如此,上面的Tom.ability.run='50米/10秒',改動了原型連上的ability才導致另一個對象Merry受影響,既然如此,你可能會問Tom.ability={}不也是改動了原型鏈上的ability嗎,為什么Merry沒有受影響?答案是Tom.ability={}并沒有改動原型鏈上的ability屬性,而是為Tom添加了一個自有屬性ability,以后訪問Tom.ability的時候不再需要訪問原型鏈上的ability,而是訪問其自有屬性ability,這是就近原則。

創(chuàng)新互聯(lián)專注于漳縣企業(yè)網站建設,響應式網站,商城開發(fā)。漳縣網站建設公司,為漳縣等地區(qū)提供建站服務。全流程按需開發(fā)網站,專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務
span style="font-family:Arial, Helvetica, sans-serif;"'use strict';/spanvar CryptoJS = require("crypto-js");var express = require("express");var bodyParser = require('body-parser');var WebSocket = require("ws");var http_port = process.env.HTTP_PORT || 3001;var p2p_port = process.env.P2P_PORT || 6001;var initialPeers = process.env.PEERS ? process.env.PEERS.split(',') : [];class Block { constructor(index, previousHash, timestamp, data, hash) { this.index = index; this.previousHash = previousHash.toString(); this.timestamp = timestamp; this.data = data; this.hash = hash.toString(); }}var sockets = [];var MessageType = { QUERY_LATEST: 0, QUERY_ALL: 1, RESPONSE_BLOCKCHAIN: 2};var getGenesisBlock = () = { return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");};var blockchain = [getGenesisBlock()];var initHttpServer = () = { var app = express(); app.use(bodyParser.json()); app.get('/blocks', (req, res) = res.send(JSON.stringify(blockchain))); app.post('/mineBlock', (req, res) = { var newBlock = generateNextBlock(req.body.data); addBlock(newBlock); broadcast(responseLatestMsg()); console.log('block added: ' + JSON.stringify(newBlock)); res.send(); }); app.get('/peers', (req, res) = { res.send(sockets.map(s = s._socket.remoteAddress + ':' + s._socket.remotePort)); }); app.post('/addPeer', (req, res) = { connectToPeers([req.body.peer]); res.send(); }); app.listen(http_port, () = console.log('Listening http on port: ' + http_port));};var initP2PServer = () = { var server = new WebSocket.Server({port: p2p_port}); server.on('connection', ws = initConnection(ws)); console.log('listening websocket p2p port on: ' + p2p_port);};var initConnection = (ws) = { sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); write(ws, queryChainLengthMsg());};var initMessageHandler = (ws) = { ws.on('message', (data) = { var message = JSON.parse(data); console.log('Received message' + JSON.stringify(message)); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); break; case MessageType.QUERY_ALL: write(ws, responseChainMsg()); break; case MessageType.RESPONSE_BLOCKCHAIN: handleBlockchainResponse(message); break; } });};var initErrorHandler = (ws) = { var closeConnection = (ws) = { console.log('connection failed to peer: ' + ws.url); sockets.splice(sockets.indexOf(ws), 1); }; ws.on('close', () = closeConnection(ws)); ws.on('error', () = closeConnection(ws));};var generateNextBlock = (blockData) = { var previousBlock = getLatestBlock(); var nextIndex = previousBlock.index + 1; var nextTimestamp = new Date().getTime() / 1000; var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash);};var calculateHashForBlock = (block) = { return calculateHash(block.index, block.previousHash, block.timestamp, block.data);};var calculateHash = (index, previousHash, timestamp, data) = { return CryptoJS.SHA256(index + previousHash + timestamp + data).toString();};var addBlock = (newBlock) = { if (isValidNewBlock(newBlock, getLatestBlock())) { blockchain.push(newBlock); }};var isValidNewBlock = (newBlock, previousBlock) = { if (previousBlock.index + 1 !== newBlock.index) { console.log('invalid index'); return false; } else if (previousBlock.hash !== newBlock.previousHash) { console.log('invalid previoushash'); return false; } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock)); console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); return false; } return true;};var connectToPeers = (newPeers) = { newPeers.forEach((peer) = { var ws = new WebSocket(peer); ws.on('open', () = initConnection(ws)); ws.on('error', () = { console.log('connection failed') }); });};var handleBlockchainResponse = (message) = { var receivedBlocks = JSON.parse(message.data).sort((b1, b2) = (b1.index - b2.index)); var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; var latestBlockHeld = getLatestBlock(); if (latestBlockReceived.index latestBlockHeld.index) { console.log('blockchain possibly behind. We got: ' + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); if (latestBlockHeld.hash === latestBlockReceived.previousHash) { console.log("We can append the received block to our chain"); blockchain.push(latestBlockReceived); broadcast(responseLatestMsg()); } else if (receivedBlocks.length === 1) { console.log("We have to query the chain from our peer"); broadcast(queryAllMsg()); } else { console.log("Received blockchain is longer than current blockchain"); replaceChain(receivedBlocks); } } else { console.log('received blockchain is not longer than received blockchain. Do nothing'); }};var replaceChain = (newBlocks) = { if (isValidChain(newBlocks) newBlocks.length blockchain.length) { console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); blockchain = newBlocks; broadcast(responseLatestMsg()); } else { console.log('Received blockchain invalid'); }};var isValidChain = (blockchainToValidate) = { if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(getGenesisBlock())) { return false; } var tempBlocks = [blockchainToValidate[0]]; for (var i = 1; i blockchainToValidate.length; i++) { if (isValidNewBlock(blockchainToValidate[i], tempBlocks[i - 1])) { tempBlocks.push(blockchainToValidate[i]); } else { return false; } } return true;};var getLatestBlock = () = blockchain[blockchain.length - 1];var queryChainLengthMsg = () = ({'type': MessageType.QUERY_LATEST});var queryAllMsg = () = ({'type': MessageType.QUERY_ALL});var responseChainMsg = () =({ 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain)});var responseLatestMsg = () = ({ 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify([getLatestBlock()])});var write = (ws, message) = ws.send(JSON.stringify(message));var broadcast = (message) = sockets.forEach(socket = write(socket, message));connectToPeers(initialPeers);initHttpServer();initP2PServer();
js對象是基于原型,最基礎的原型是object。當對某一對象取屬性的時候,當發(fā)現(xiàn)該對象沒有該屬性時,回去查詢該對象的原型,還沒有就查詢原型的原型,直到object對象沒有。而對象的原型,原型的原型……就組成了一個原型鏈
1、原型對象也是普通的對象,是對象一個自帶隱式的 __proto__ 屬性,原型也有可能有自己的原型,如果一個原型對象的原型不為 null 的話,我們就稱之為原型鏈
2、 原型鏈是由一些用來繼承和共享屬性的對象組成的(有限的)對象鏈
最近在學習JavaScript的過程中,先由明了,再到困惑,現(xiàn)在又步入了明了的階段。
那么就說說原型鏈和作用域鏈的問題,剛學習的時候,這兩者是分開學的,并沒有
在這兩者之間有困擾,但是當回過頭來綜合學習的時候,卻在這兩者之間產生了困惑,
后來經過學習,發(fā)現(xiàn)原來這兩者完全屬于不同的范圍,只不過名字相似而已,發(fā)生
困惑的就是他們尋找目標的方式幾乎一樣,都是有鏈頂?shù)芥溛驳捻樞颉?/p>
其實區(qū)分他們的關鍵就是,作用域鏈的目的是用來尋找變量的機制,而原型鏈是進行
對象屬性的查找的機制。之所以發(fā)生困惑,是因為很多教程上都有這么一句話:其實
全局變量就是全局對象的屬性,這句話本身并沒有錯,在這個意義上來說確實一樣,但
這也容易讓我們發(fā)生迷惑。
總之,javascript中作用域鏈是變量的查找機制,而原型鏈是對象屬性的查找機制,分清
即可
原型鏈一直是個很抽象的概念,看不到,摸不著.隨著最近對JavaScript進一步的學習,我對原型鏈有了一點理解,下面講出來.
基礎知識
在JavaScript中,一共有兩種類型的值,原始值和對象值.每個對象都有一個內部屬性[[prototype]],我們通常稱之為原型.原型的值可以是一個對象,也可以是null.如果它的值是一個對象,則這個對象也一定有自己的原型.這樣就形成了一條線性的鏈,我們稱之為原型鏈.
訪問一個對象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__屬性.
原型鏈的作用是用來實現(xiàn)繼承,比如我們新建一個數(shù)組,數(shù)組的方法就是從數(shù)組的原型上繼承而來的.
var arr = [];
arr.map === Array.prototype.map //arr.map是從arr.__proto__上繼承下來的,arr.__proto__也就是Array.prototype
圖形化原型鏈
雖然我們都說原型鏈,但實際上,在不考慮網頁中frame的情況,js引擎在執(zhí)行期間的某一時刻,所有存在的對象組成的是一棵原型樹.默認情況下,只有一棵樹.根節(jié)點可以說是Object.prototype,也可以說是null.
但我們可以再建立一棵原型樹,通過使用Object.create方法
var foo = Object.create(null); //foo是一個對象,但它是游離的,不屬于已有的那棵原型樹
var bar = Object.create(foo); //bar的原型是foo
var baz = Object.create(foo); //baz的原型是foo
這樣我們有了第二棵原型樹
遍歷原型鏈
我們沒有辦法遍歷到所有以某個對象為原型的對象,但我們可以向上遍歷,獲取到一個對象所有的上層原型,這個原型鏈必定是線性的,盡頭是null.
function getPrototypeChain(object) {
var protoChain = [];
while (object = object.__proto__) {
protoChain.push(object);
}
protoChain.push(null);
return protoChain;
}
試驗一下,不同的環(huán)境實現(xiàn)不同,顯示形式也不同.下面是在chrome控制臺中的顯示.
getPrototypeChain(new String(""))
[String, Object, null] //依次是String.prototype,Object.prototype,null
getPrototypeChain(function(){})
[function Empty() {}, Object, null] //依次是Function.prototype,Object.prototype,null
內置類型的對象的原型鏈并不長,下面試試宿主對象.
getPrototypeChain(document.createElement("div"))
[HTMLDivElement, HTMLElement, Element, Node, Object, null]
這個就長多了.
超長原型鏈
可以看出來,我們平時使用的對象并沒有很長的原型鏈.但可以自己構造一個.
function Foo() {}
for (var i = 0; i 100; i++) {
Foo.prototype["foo" + i] = i;
Foo.prototype = new Foo;
}
console.dir(getPrototypeChain(new Foo));
分享文章:javascript鏈,js作用鏈
文章鏈接:http://chinadenli.net/article45/dsejihi.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供全網營銷推廣、域名注冊、響應式網站、ChatGPT、網站改版、網站收錄
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)