摘要:客觀別急,今天真的是要說一個,也許你早已知曉,也許你時常躺槍于他手,悄悄地,我們慢慢開始。使用案例源碼用到了前面已經寫好的函數,所以認為獲取的屬性值,不包括原型返回一個副本,使其鍵和值對換。
前言
underscore.js源碼分析第四篇,前三篇地址分別是,如果你對這個系列感興趣,歡迎點擊watch,隨時關注動態。
教你認清這8大殺手锏
那些不起眼的小工具?
(void 0)與undefined之間的小九九
原文地址
源碼地址
逗我呢?哥!你要說什么bug,什么bug,什么bug,我最討厭bug。去他妹的bug。
客觀別急,今天真的是要說一個bug,也許你早已知曉,也許你時常躺槍于他手,悄悄地,我們慢慢開始。
for in 遍歷對象屬性時存在bug
for in 遍歷對象屬性時存在bug
for in 遍歷對象屬性時存在bug
使用for in去遍歷一個對象俺們再熟悉不過了,經常干這種事,那他到底可以遍歷一個對象哪些類型的屬性呢? 長得帥的還是看起來美美的,瞎說,它能夠遍歷的是對象身上那些可枚舉標志([[Enumerable]])為true的屬性。
對于通過直接的賦值和屬性初始化的屬性,該標識值默認為即為 true
對于通過 Object.defineProperty 等定義的屬性,該標識值默認為 false
舉個例子哪些屬性可以被枚舉
let Person = function (name, sex) { this.name = name this.sex = sex } Person.prototype = { constructor: Person, showName () { console.log(this.name) }, showSex () { console.log(this.sex) } } Person.wrap = { sayHi () { console.log("hi") } } var p1 = new Person("qianlongo", "sex") p1.sayBye = () => { console.log("bye") } p1.toString = () => { console.log("string") } Object.defineProperty(p1, "info", { enumerable: false, configurable: false, writable: false, value: "feDev" });? for (var key in p1) { console.log(key) } // name // sex // sayBye // constructor // showName // showSex // toString
可以看到我們手動地用defineProperty,給某個對象設置屬性時,enumerable為false此時該屬性是不可枚舉的
Person繼承自Object構造函數,但是for in并沒有枚舉出Object原型上的一些方法
手動地覆蓋對象原型上面的方法toString也是可枚舉的
如何判斷一個對象的屬性是可枚舉的方式其實很簡單,使用原生js提供的Object.propertyIsEnumerable來判斷
let obj = { name: "qianlongo" } let obj2 = { name: "qianlongo2", toString () { return this.name } } obj.propertyIsEnumerable("name") // true obj.propertyIsEnumerable("toString") // false obj2.propertyIsEnumerable("name") // true obj2.propertyIsEnumerable("toString") // true
為什么obj判斷toString為不可枚舉屬性,而obj2就是可枚舉的了呢?原因很簡單,obj2將toString重寫了,而一個對象自身直接賦值的屬性是可被枚舉的
說了這么多,接下來我們來看一下下劃線中涉及到遍歷的部分對象方法,come on!!!
_.has(object, key)判斷對象obejct是否包含key屬性
平時你可能經常這樣去判斷一個對象是否包含某個屬性
if (obj && obj.key) { // xxx }
但是這樣做有缺陷,比如某個屬性其對應的值為0,null,false,""空字符串呢?這樣明明obj有以下對應的屬性,卻因為屬性值為假而通過不了驗證
let obj = { name: "", sex: 0, handsomeBoy: false, timer: null }
所以我們可以采用下劃線中的這種方式
源碼
var hasOwnProperty = ObjProto.hasOwnProperty; _.has = function(obj, key) { return obj != null && hasOwnProperty.call(obj, key); };_.keys(object)
獲取object對象所有的屬性名稱。
使用示例
let obj = { name: "qianlongo", sex: "boy" } let keys = _.keys(obj) // ["name", "sex"]
源碼
_.keys = function(obj) { // 如果obj不是object類型直接返回空數組 if (!_.isObject(obj)) return []; // 如果瀏覽器支持原生的keys方法,則使用原生的keys if (nativeKeys) return nativeKeys(obj); var keys = []; // 注意這里1、for in會遍歷原型上的鍵,所以用_.has來確保讀取的只是對象本身的屬性 for (var key in obj) if (_.has(obj, key)) keys.push(key); // Ahem, IE < 9. // 這里主要處理ie9以下的瀏覽器的bug,會將對象上一些本該枚舉的屬性認為不可枚舉,詳細可以看collectNonEnumProps分析 if (hasEnumBug) collectNonEnumProps(obj, keys); return keys; };collectNonEnumProps函數分析
該函數為下劃線中的內部函數一枚,專門處理ie9以下的枚舉bug問題,for in到底有啥bug,終于可以說出來了。
簡單地說就是如果對象將其原型上的類似toString的方法覆蓋了的話,那么我們認為toString就是可枚舉的了,但是在ie9以下的瀏覽器中還是認為是不可以枚舉的,又是萬惡的ie
源碼
// 判斷瀏覽器是否存在枚舉bug,如果有,在取反操作前會返回false var hasEnumBug = !{toString: null}.propertyIsEnumerable("toString"); // 所有需要處理的可能存在枚舉問題的屬性 var nonEnumerableProps = ["valueOf", "isPrototypeOf", "toString", "propertyIsEnumerable", "hasOwnProperty", "toLocaleString"]; // 處理ie9以下的一個枚舉bug function collectNonEnumProps(obj, keys) { var nonEnumIdx = nonEnumerableProps.length; var constructor = obj.constructor; // 讀取obj的原型 var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; // 這里我有個疑問,對于constructor屬性為什么要多帶帶處理? // Constructor is a special case. var prop = "constructor"; if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); while (nonEnumIdx--) { prop = nonEnumerableProps[nonEnumIdx]; // nonEnumerableProps中的屬性出現在obj中,并且和原型中的同名方法不等,再者keys中不存在該屬性,就添加進去 if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { keys.push(prop); } } }
代碼看起來并不復雜,但是有一個小疑問,對于constructor屬性為什么要多帶帶處理呢?各個看官,如果知曉,請教我啊
_.allKeys(object)獲取object中所有的屬性,包括原型上的。
舉個簡單的例子說明
let Person = function (name, sex) { this.name = name this.sex = sex } Person.prototype = { constructor: Person, showName () { console.log(this.name) } } let p = new Person("qianlongo", "boy") _.keys(p) // ["name", "sex"] 只包括自身的屬性 _.allKeys(p) // ["name", "sex", "constructor", "showName"] 還包括原型上的屬性
接下來看下源碼是怎么干的
源碼
// 獲取對象obj的所有的鍵 // 與keys不同,這里包括繼承來的key // Retrieve all the property names of an object. _.allKeys = function(obj) { if (!_.isObject(obj)) return []; var keys = []; // 直接讀遍歷取到的key,包括原型上的 for (var key in obj) keys.push(key); // Ahem, IE < 9. if (hasEnumBug) collectNonEnumProps(obj, keys); // 同樣處理一下有枚舉問題的瀏覽器 return keys; };
可以看到和_.keys的唯一的不同就在于遍歷obj的時候有沒有用hasOwnProperty去判斷
_.values()返回object對象所有的屬性值。
使用案例
let obj = { name: "qianlongo", sex: "boy" } _.values(obj) // ["qianlongo", "boy"]
源碼
// Retrieve the values of an object"s properties. _.values = function(obj) { // 用到了前面已經寫好的keys函數,所以values認為獲取的屬性值,不包括原型 var keys = _.keys(obj); var length = keys.length; var values = Array(length); for (var i = 0; i < length; i++) { values[i] = obj[keys[i]]; } return values; };_.invert(object)
返回一個object副本,使其鍵(keys)和值(values)對換。
使用案例
let obj = { name: "qianlongo", secName: "qianlongo", age: 100 } _.invert(obj) // {100: "age", qianlongo: "secName"}
注意喲,如果對象中有些屬性值是相等的,那么翻轉過來的對象其key取最后一個
源碼
_.invert = function(obj) { var result = {}; // 所以也只是取對象本身的屬性 var keys = _.keys(obj); for (var i = 0, length = keys.length; i < length; i++) { // 值為key,key為值,如果有值相等,后面的覆蓋前面的 result[obj[keys[i]]] = keys[i]; } return result; };_.functions(object)
返回一個對象里所有的方法名, 而且是已經排序的(注意這里包括原型上的屬性)
源碼
_.functions = _.methods = function(obj) { var names = []; for (var key in obj) { // 是函數,就裝載進去 if (_.isFunction(obj[key])) names.push(key); } return names.sort(); // 最后返回經過排序的數組 };結尾
夜深人靜,悄悄地說一個bug這個鬼故事講完了,各位good night。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/82939.html
摘要:從最大的同性社交平臺獲取數據好了,言歸正傳,回到題目。烏云密布的爬蟲百度網盤這件事,是我不想看到的,這類安全問題的一個共同特點用戶自身確實存在問題。 本文作者:夏之冰雪,i春秋簽約作家 《我在百度網盤上看到上萬條車主個人信息,企業、政府高官信息、各種數據庫和無窮無盡的盜版》,一時間,這篇文章就火了,火爆程度另百度猝不及防。 其實呢,這事真不能全怪百度,畢竟用戶分享出去了。之所以引起這么...
摘要:蘋果公司也參與進來蘋果將在新版上取消耳機插孔,取而代之的可能是一對無線。蘋果在上線之前就建立了全世界第一個數據中心,耗資億美元,用來進行的計算。它是一個蜷縮在你的耳膜附近的或者。外加你還得忍受耳廓的疼痛。整體滿意度將只能徘徊在或。 多希望我可以觸碰你。 西奧多躺在床上,靜靜地說。他的生活中充滿了沉默與拒絕,但這一次,塞曼莎溫柔地問:你想怎樣觸碰我呢? showImg(https://s...
摘要:類似地,輸入中的大規模特征將主導網絡并導致下游發生更大的變化。因此,使用神經網絡庫的自動規范化往往是不夠的,這些神經網絡庫會在每個特征的基礎上盲目地減去平均值并除以方差。 如果你的神經網絡不工作,該怎么辦?作者在這里列出了建神經網絡時所有可能做錯的事情,以及他自己的解決經驗。忘記規范化數據忘記檢查結果忘記預處理數據忘記使用正則化使用的batch太大使用了不正確的學習率在最后層使用了錯誤的激活...
摘要:前端開發在年依然持續火熱,本文將對熱點事件做一個總結。版的和協議在前端領域,一直獨占鰲頭。年又發布了一個重大的版本更新。主要是配合使用了服務工作線程。而且還提供了供前端開發者接入。快速發布了和在悄悄地跳過之后,在月號正式發布。 譯者按: 老技術日趨成熟,新技術層出不窮。 原文: A recap of front-end development in 2017 譯者: Fundebu...
閱讀 1688·2021-10-13 09:39
閱讀 3163·2021-10-12 10:11
閱讀 557·2021-09-28 09:36
閱讀 2640·2019-08-30 15:55
閱讀 1391·2019-08-30 13:04
閱讀 634·2019-08-29 17:08
閱讀 1911·2019-08-29 14:14
閱讀 3407·2019-08-28 18:23