js组装知识(待续……)
object.assign()
這個方法回使源對象上的[[Get]]取得屬性的值,然后使用目標對象上的[[Set]]設置屬性的值
實際上對每個源對象執行的是淺復制,如果多個源對象都有相同的屬性,則使用最后一個賦值的值
Object.is()
和===很像,接收兩個參數
console.log(+0 === -0) //true console.log(+0 === 0) //true console.log(-0 === 0) //true // 判斷NaN console.log(NaN === NaN)//false console.log(isNaN(NaN))//true // 用object.is()輕松解決 console.log(Object.is(NaN, NaN))//true console.log(Object.is(+0, -0))//false // 要檢查超過兩個值,利用遞歸即可 function deep(x, ...rest) {// 傳入的值為 1,[1,1,4]; 1,[1,4] ; 1,[4]return Object.is(x, rest[0]) && (rest.length < 2 || deep(...rest)) } let a = deep(1, 1, 1, 4) console.log(a) //falsees6增強的對象語法
//1, 屬性名簡寫 let a = 1; let obj = {a}; console.log(obj) //{a:1} // 代碼壓縮程序會在不同的作用域間保留屬性名,以防找不到引用 ------這句話還不理解//2,可計算屬性 // 有了計算屬性,就可以在對象字面量中完成動態屬性賦值.中括號運算符包圍 //的對象屬性鍵告訴運行時將其作為JavaScript表達式而不是字符串來求職 // 例 const a = 'name'; const b = 'sex'; const c = 'age'; let obj = { [a]: '小紅', [b]: '女', [c]: 10 } console.log(obj) //{name:'小紅',sex:'女',age:10} // 當然[]里也可以是一個復雜的函數// 3,簡寫方法名 let obj = {// 舊的寫法oldName: function (a) {console.log(a)},//新的寫法newName(a) {console.log(a)} }解構賦值
// 解構在內部使用ToObject()把源數據結構轉換為對象。這也意味著 //在對象結構的上下文中,原始值會被當成對象,這也意味著 // (根據ToObject()的定義),null和undefined不能被結構,否則會拋出錯誤。 // 例 let { length } = 'foobar'; let { constructor } = 'foobar' // // 這里一定要切記 源對象轉為對象就能看懂了 console.log(length, constructor) //6,? String() { [native code] } console.log(constructor === String) //true //嵌套結構 //解構可以使用嵌套結構,以匹配嵌套的屬性: let obj = {name: '小明',age: 11,job: {title: 'web前端'} } let { job: { title } } = obj console.log(title) // web前端 // 參數解構---對參數進行解構不會影響arguments對象 let data = {b: 2, c: 3 } function aaa(a, { b, c }, d) {console.log(arguments) // 1,[2,3],4console.log(b, c) // 2,3 } aaa(1, data, 2)try catch 語句
如果try中的代碼沒有出錯,則程序正常運行try中的內容后,不會執行catch中的內容,
如果try中的代碼一但出錯,程序立即跳入catch中去執行代碼,那么try中出錯代碼后的
所有代碼就不再執行了.
工廠函數
這種工廠模式雖然可以解決創建多個類似對象的問題,但沒有解
決對象標識問題(即新創建的對象是什么類型)
構造函數
定義構造函數可以確保實例被標識為特定類型
構造函數也是函數,和普通函數的唯一區別在于調用方式不同
構造函數和工廠函數的區別
1、沒有明顯的創建對象
2、屬性和方法直接賦值給了this
3、沒有return
構造函數需要注意的事項?
首字母大寫,有助于和普通函數進行區分。
要創建Person實例,需要使用new操作符,以這種方式調用構造函數會進行如下操作。
1> 在內存中創建一個新對象;
2> 這個新對象內部的[[prototype]]特性被賦值為構造函數的prototype屬性。
3> 構造函數內部的this被賦值為這個新對象(即this指向新對象)。
4> 執行構造函數內部的代碼(給新對象添加屬性)
5> 如果構造函數返回非空對象,則返回該對象;否則,返回剛創建的新對象。 ——————不太明白
原型模式
每個函數都會創建prototype屬性,這個屬性是一個對象,
包含應該由特定引用類型的實例共享的屬性和方法。
好處是 在它上面的屬性或方法可以被對象實例共享
高階函數
符合以下一個條件即可
- 若A函數,接收到的參數是一個函數,那么A就可以稱之為高階函數。
- 若A函數,調用的返回值依然是一個函數,那么A就可以稱之為高階函數
常見的有Promist setTimeout 、arr.map()……
函數的柯里化
通過函數調用繼續返回函數的方式,實現多次接收參數最后統一處理的函數編碼形式
例 :
純函數
- 一類特別的函數:只要是同樣的輸入(實參),必定得到同樣的輸出(返回)
- 必須遵守以下一些約束
- 不得改寫數據
- 不會產生任何副作用,例如網絡請求,輸入和輸出設備
- 不能調用Date.now()或者Math.random()等不純的方法
nanoid(現在這放著,懶得開新的了)
- 安裝 yarn add nanoid
- 使用 import {nanoid} from ‘nanoid’;
- 語法 nanoid()即可生成隨機字符
instanceof
檢查實例的原型鏈中,是否包含指定構造函數的原型
function Person(name) {this.name = name}const p1 = new Person('小紅');console.log(p1 instanceof Person) //trueconsole.log(p1 instanceof Object) //trueconsole.log(Person.prototype instanceof Object) //trueisPrototypeOf()
本質上,會在傳入參數的[[prototype]]指向調用它的對象時返回true
function Person(name) {this.name = name}const p1 = new Person('小紅');const p2 = new Person('小明');console.log(Person.prototype.isPrototypeOf(p1)) //trueconsole.log(Person.prototype.isPrototypeOf(p2)) //trueObject.getPrototypeOf(obj)
可以方便的取得一個對象的原型。
function Person(name) {this.name = name}const p1 = new Person('小紅');console.log(Object.getPrototypeOf(p1)) //{constructor:f}console.log(Object.getPrototypeOf(p1)==Person.prototype) //trueObject.setPrototypeOf()
可以向實例的私有屬性[[prototype]]寫入一個新值,這樣就可以重寫一個對象的原型繼承關系
【注意】這個方法可能會影響代碼性能,會涉及所有訪問了拿些修改過[[prototype]]的對象的代碼
Object.create()
來創建一個新對象,同時為其指定原型
let biped = { numLegs: 2 };let person = Object.create(biped)person.name = 'Matt';console.log(person.name); //'Matt'console.log(person.numLegs); //2console.log(Object.getPrototypeOf(person) === biped); //true原型層級
- 在通過對象訪問屬性時,會按照這個屬性的名稱開始搜索,搜索開始對象實例本身。
如果在這個實例上發現了給定的名稱,則返回該對象名稱對應的值 - 如果沒有找到屬性,則搜索會沿著指針進入原型對象,找到則返回該屬性對應的值,
這也就是原型用于在多個對象實例間共享屬性的原理。
【注意】通過實例讀取原型對象的值是不可更改的,如果在實例上添加一個與
原型對象同名的屬性,則會在實例上創建這個屬性,這樣會遮住原型對象的屬性
delect操作符
可以完全刪除實例上的屬性
function Person(name) {this.name = name;}let p1 = new Person('小紅');Person.prototype.name = '小明';console.log(p1.name) //'小紅'delete p1.name;console.log(p1.name) //'小明'hasOwnProperty()
檢測是否為實例屬性
function Person() {}let p1 = new Person();let p2 = new Person();Person.prototype.name = '小明';p1.name = '小紅';console.log(p1.hasOwnProperty('name')) //trueconsole.log(p2.hasOwnProperty('name')) //falseObject.getOwnPropertyDescriptor()
取得原型屬性的描述符(只對實例屬性有效)
function Person() {}let p1 = new Person();let p2 = new Person();Person.prototype.name = '小明';p1.name = '小紅';console.log(Object.getOwnPropertyDescriptor(p1, 'name')) //{value: "小紅", writable: true, enumerable: true, configurable: true}console.log(Object.getOwnPropertyDescriptor(p2, 'name')) //undefinedin操作符
function Person(name) {}let p1 = new Person();console.log('name' in p1) //falsep1.name = '小明'console.log('name' in p1) //truelet p2 = new Person();console.log('name' in p2) //falsePerson.prototype.name = '小紅'console.log('name' in p2) //true//結論,無論屬性在實例自身還是原型上都會返回true利用in和hasOwnProperty的特性實現檢測屬性是否存在于原型上
function detectionP(obj, k) {return !obj.hasOwnProperty(k) && ([k] in obj)}console.log(detectionP(p2, 'name'))for-in循環中使用in操作符時,可以通過對象訪問且可以被枚舉的屬性都會返回,
包括實例屬性和原型屬性
Object.keys()
接收一個對象作為參數,返回包含該對象所有可枚舉屬性名稱的字符串數組
function Person(name) {this.name = name}let p1 = new Person('小紅');Object.defineProperties(p1, {"school": {value: 'bgs',enumerable: true //默認false},"class": {value: '1908'}})console.log(Object.keys(p1)) //['name']Object.getOwnPropertyNames()
只要是實例屬性(包含原型),無論是否可以枚舉,返回對象所有屬性名稱的字符串數組
function Person(name) {this.name = name}let k1 = Symbol('k1')let p1 = new Person('小紅');Object.defineProperties(p1, {"school": {value: 'bgs',enumerable: true //默認false},"class": {value: '1908'},[k1]: {value: 1}})console.log(Object.getOwnPropertyNames(p1)) //["name", "school", "class"]Object.getOwnPropertySymbols()
只針對符號,類似getOwnPropertyNames
語法Object.getOwnPropertySymbols(obj)
屬性枚舉的順序
- for-in和Object.keys()的枚舉順序是不確定的,取決于javascript引擎,
可能因瀏覽器而異 - Object.getOwnPropertyName()、Object.getOwnPropertySymbols()
和object.assign()的枚舉順序是確定性的。 - 先以升序枚舉數值鍵,然后以插入順序枚舉字符串和符號鍵,
在對象字面量中定義的鍵以它們逗號分隔的順序插入。
ECMAScript2017新增兩個靜態方法
Object.values()
接收一個對象,返回對象值的數組(淺復制)
Object.entries()
接收一個對象,返回鍵值對數組(淺復制)。非字符串屬性會被轉換為字符串輸出,
符號屬性會被忽略
原型的語法
之前每次給原型上增加屬性都要通過Person.prototype.key=value
function Person() { }//錯誤的寫法1,會丟失constructor屬性Person.prototype = {name: '小紅',age: 10}const p1 = new Person()console.log(Person.prototype.constructor) //? Object() { [native code] }//錯誤的寫法2,這樣會得到一個[[Enumberable]]為true的constructor屬性Person.prototype = {constructor: Person,name: '小紅',age: 10}const p1 = new Person()console.log(p1.constructor) for (let k in p1) {console.log(k) //name,age,constructor}//正確的寫法Person.prototype = {name: '小紅',age: 10}Object.defineProperty(Person.prototype, 'constructor', {value: Person,enumerable: false})const p1 = new Person()for (let k in p1) {console.log(k) //name,age}實例只有指向原型的指針,沒有指向構造函數的指針.
重寫構造函數上的原型之后在創建的實例才會引用引得原型。而再次之前創建的實例仍然會引用最初的原型
toString()
方法可把一個 Number 對象轉換為一個字符串,并返回結果。
一個參數:可以返回2~32進制的字符串
檢查數據類型
Object.prototype.toString.call()
繼承
原型鏈繼承的問題
- 主要問題出現在原型中包含引用值的時候(相同引用)
- 子類型在實例化時不能給父類型的構造函數傳參
盜用構造函數(也叫“經典繼承”或“對象偽裝”)
使用apply()和call()方法以新創建的對象為上下文執行構造函數
缺點不能訪問父類原型上定義的方法
組合繼承
就是綜合了原型鏈和盜用構造函數,將兩者的優點結合。
基本思路就是使用原型鏈繼承原型上的屬性和方法,而通過盜用構造函數繼承實例屬性
調用過程中會執行兩次SuperType函數
寄生式組合繼承(效果最佳) (紅寶石248頁)
只會調用一次SuperType函數
總結
以上是生活随笔為你收集整理的js组装知识(待续……)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka精华问答 | kafka的使
- 下一篇: OpenStack精华问答 | Open