重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
先举一个非常简单的例子,我有一个类叫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,这是就近原则。
创新互联专注于漳县企业网站建设,响应式网站,商城开发。漳县网站建设公司,为漳县等地区提供建站服务。全流程按需开发网站,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务
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。当对某一对象取属性的时候,当发现该对象没有该属性时,回去查询该对象的原型,还没有就查询原型的原型,直到object对象没有。而对象的原型,原型的原型……就组成了一个原型链
1、原型对象也是普通的对象,是对象一个自带隐式的 __proto__ 属性,原型也有可能有自己的原型,如果一个原型对象的原型不为 null 的话,我们就称之为原型链
2、 原型链是由一些用来继承和共享属性的对象组成的(有限的)对象链
最近在学习JavaScript的过程中,先由明了,再到困惑,现在又步入了明了的阶段。
那么就说说原型链和作用域链的问题,刚学习的时候,这两者是分开学的,并没有
在这两者之间有困扰,但是当回过头来综合学习的时候,却在这两者之间产生了困惑,
后来经过学习,发现原来这两者完全属于不同的范围,只不过名字相似而已,发生
困惑的就是他们寻找目标的方式几乎一样,都是有链顶到链尾的顺序。
其实区分他们的关键就是,作用域链的目的是用来寻找变量的机制,而原型链是进行
对象属性的查找的机制。之所以发生困惑,是因为很多教程上都有这么一句话:其实
全局变量就是全局对象的属性,这句话本身并没有错,在这个意义上来说确实一样,但
这也容易让我们发生迷惑。
总之,javascript中作用域链是变量的查找机制,而原型链是对象属性的查找机制,分清
即可
原型链一直是个很抽象的概念,看不到,摸不着.随着最近对JavaScript进一步的学习,我对原型链有了一点理解,下面讲出来.
基础知识
在JavaScript中,一共有两种类型的值,原始值和对象值.每个对象都有一个内部属性[[prototype]],我们通常称之为原型.原型的值可以是一个对象,也可以是null.如果它的值是一个对象,则这个对象也一定有自己的原型.这样就形成了一条线性的链,我们称之为原型链.
访问一个对象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__属性.
原型链的作用是用来实现继承,比如我们新建一个数组,数组的方法就是从数组的原型上继承而来的.
var arr = [];
arr.map === Array.prototype.map //arr.map是从arr.__proto__上继承下来的,arr.__proto__也就是Array.prototype
图形化原型链
虽然我们都说原型链,但实际上,在不考虑网页中frame的情况,js引擎在执行期间的某一时刻,所有存在的对象组成的是一棵原型树.默认情况下,只有一棵树.根节点可以说是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;
}
试验一下,不同的环境实现不同,显示形式也不同.下面是在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));