《你不知道的JavaScript(上卷)》讀書筆記

第一次嘗試用思維導圖記筆記,感覺還不錯~~~不過還是改不了我讀書筆記寫成抄書筆記的毛病 =。=

因為開始學JS的時候,一般瀏覽器就已經支持ES6了,所以比較喜歡使用ES6語法,let,=>等,文中代碼不是抄書的,都用了ES6。

?

作用域和閉包

?

this和對象原型?

1. 屬性描述符(ES5開始)

獲取屬性描述符:?

var myObject = { a:2
};
Object.getOwnPropertyDescriptor( myObject, "a" );
// {// value: 2,// writable: true,// enumerable: true,// configurable: true 
// }

設置屬性描述符,被設置的屬性可以定義過,也可以未定義過,

var myObject = {};
Object.defineProperty( myObject, "a", {value: 2,writable: false, // 不可寫! configurable: true, enumerable: true
});

?

其中:

writable 決定是否可以修改屬性的值,如果設置為 false。修改屬性值會靜默失敗(silently failed),嚴格模式會報錯,TypeError。

configurable 決定屬性是否可以配置。很顯然,把configurable設置為false是單項的。并且無法撤銷。

? ? ? ? ? ? ? ? ??即便屬性是 configurable:false,我們還是可以 把 writable 的狀態由 true 改為 false,但是無法由 false 改為 true。

? ? ? ? ? ? ? ? ??configurable:false 還會禁止刪除這個屬性,導致刪除靜默失敗。

enumerable?控制屬性是否會出現在對象的屬性枚舉中,默認為true。for..in 遍歷的是可枚舉屬性。

?

2. 訪問描述符

當給一個屬性定義 getter、setter 或者兩者都有時,這個屬性會被定義為“訪問描述 符”(和“數據描述符”相對)。對于訪問描述符來說,JavaScript 會忽略它們的 value 和 writable 特性,取而代之的是關心 set 和 get(還有 configurable 和 enumerable)特性。

var myObject = {// 給 a 定義一個setter
    get a() {return 2}
}Object.defineProperty(myObject,       // 目標對象'b',            // 屬性名{               // 描述符// 給 b 設置一個 getterget: function() {   return this.a * 2},// 確保 b 會出現在對象的屬性列表中enumerable: true}
)console.log(myObject.a) // 2
console.log(myObject.b) // 4

a = 3
b = 5console.log(myObject.a) // 2
console.log(myObject.b) // 4

getter 和 setter 一般是成對出現,如果只出現一個,會導致 set 不生效 / get 到 undefined。

?

有個getter和setter,就可以在設置數據的同時,做一些其他的事情了,vue的雙向綁定,就是在數據set()里更新dom元素,同時在dom的input事件更新數據,實現雙向綁定。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><!-- HTML --><div id="app"><input type="text" v-model="number"><button v-click="incre">+</button><button v-click="minus">-</button><button v-click="incre4">+4</button><span v-bind="number"></span></div><!-- JavaScript --><script>function MyVue(options) {// 先綁定基本數據this.$el = document.querySelector(options.el) // vue 綁定的 dom 元素this.$data = options.datathis.$methods = options.methods// 根據 dom 獲取數據都綁定了哪些 dom 元素 并記錄 以便數據更新的時候 同步更新domthis._binding = {}// 初始化為空數組
            Object.keys(this.$data).forEach((item) => {this._binding[item] = []})this._complie(this.$el)console.log(this._binding)Object.keys(this.$data).forEach((item) => {// 這里對value的使用是一個閉包?...
                let value = this.$data[item]Object.defineProperty(this.$data, item, {get: () => {console.log(`獲取${item}: ${value}`)return value},set: (val) => {// 更新 data 的時候要把相關 dom 節點全部更新
                        console.log(`更新${item}: ${val}`)if (val !== value) {value = valthis._binding[item].forEach((meth) => {meth()})}}})})}/*** @param {HTMLElement} root: vue 綁定的 dom 元素節點**/MyVue.prototype._complie = function(root) {// 如果有子節點
            const nodes = root.childrenfor (let i = 0; i < nodes.length; i++) {const node = nodes[i]if (node.children.length) {this._complie(node)}// 如果是bind 證明綁定了某個數據 那么改數據更改時 更改該處 domif (node.hasAttribute('v-bind')) {const dataName = node.getAttribute('v-bind')const attr = (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA') ? 'value' : 'innerHTML'node[attr] = this.$data[dataName] // 初始化頁面this._binding[dataName].push(() => {console.log('v-bind: ', node, attr, dataName)node[attr] = this.$data[dataName]})}// 如果有 v-click 就在點擊事件中執行methods中對應的那個函數if (node.hasAttribute('v-click')) {const methName = node.getAttribute('v-click')const method = this.$methods[methName]node.onclick = method.bind(this.$data) // method是對data中的數據進行操作,這里記得要把this綁到data上
                }// 數據更改時更新 dom 節點 dom 節點更改時也更新 dataif (node.hasAttribute('v-model')) {const dataName = node.getAttribute('v-model')node.value = this.$data[dataName] // 初始化頁面this._binding[dataName].push(() => {node.value = this.$data[dataName]})node.addEventListener('input', () => {console.log('v-model', node)this.$data[dataName] = node.value})}}}window.onload = function() {const app = new MyVue({el: '#app',data: {number: 0,c: 1},methods: {incre: function() {console.log('incre...', this)this.number++},minus: function() {console.log('minus...', this)this.number--},incre4: function() {console.log('incre4...', this)this.number = Number(this.number) + 4}}})}</script>
</body>
</html>
View Code

詳見:https://juejin.im/post/5acc17cb51882555745a03f8

?

?

3. call、apply、bind 的聯系和區別

他們都是定義在Function.prototype里面的函數,都有綁定this的功能。原型如下:

call(thisArg: any, args...: any)

apply(thisArg: any, argArray: Array)

apply可以把存放參數數組直接傳遞,如果參數存在一個數組里,使用apply將很方面。

可以通過call來將某個對象的函數應用在其他對象:?Object.prototype.toString.call(something)?

bind也可以綁定this,并返回一個函數,同時bind還有一個功能,就是綁定傳入的函數。

function sayHello(arg1, arg2) {console.log(arg1, arg2)console.log('hello, i am ' + this.name)
}name = 'global'let p1 = { name: 'xiaoming' }
let p2 = { name: 'hanmeimei' }sayHello('arg1', 'arg2')                    // i am global
sayHello.apply(p1, ['apply1', 'apply2'])    // i am xiaoming
sayHello.apply(p2, ['apply1', 'apply2'])    // i am hanmeimei
sayHello.call(p1, 'call1', 'call2')         // i am xiaoming
sayHello.call(p2, 'call1', 'call2')         // i am hanmeimei

let sayHelloWithBind = sayHello.bind(p1, '參數1')sayHelloWithBind('參數2') // 參數1 參數2 hello, i am xiaoming

如果使用內置的 .bind(..) 函數來生成一個硬綁定函數的話, 該函數是沒有 .prototype 屬性的。在這樣的函數上使用 instanceof 的話, 目標函數的 .prototype 會代替硬綁定函數的 .prototype。

function Foo() {}
Bar = Foo.bind({})
a = new Bar()
console.log(a instanceof Foo) // true
console.log(a instanceof Bar) // true

?

4. import和export

有點多,不想寫了。。。。參考?Module 的語法

?

?

5. 類與對象?

JavaScript沒有構造函數,只有函數的構造調用,

JavaScript沒有類,只有對象

?

了解一下隨意的?constructor?

function Foo() { ... }
var a = new Foo();
a.constructor === Foo; // true

constructor,所謂的“構造函數”,其實是Foo.prototype的,a本身并沒有這個屬性?a.hasOwnProperty('constructor') // false?

也就是說?Foo.prototype.constructor === Foo; // true?而和a是怎么生成的沒有什么關系。

如果先設置?Foo.prototype={ ... }?那么?var a = new Foo();?生成的a對象的constructor也就是Object。

a在new的時候,關聯到了Foo.prototype,如果你修改了?Foo.prototype = ...?? a所關聯的對象是不變的。

?

.constructor 并不是一個不可變屬性。它是不可枚舉的,但是它的值是可寫的。此外,你可以給任意 [[Prototype]] 鏈中的任意對象添加一個名 為 constructor 的屬性或者對其進行修改,你可以任意對其賦值。

綜上,.constructor 是一個非常不可靠并且不安全的引用。通常來說要盡量避免使用這些引用。

?

原型繼承

function Foo(name) {this.name = name
}Foo.prototype.myName = function() {return this.name
}function Bar(name, label) {Foo.call(this, name)this.label = label
}// 為 Bar.prototype 從新賦值一個 [[Prototype]] 為 Foo.prototype 的對象
// 此時 Bar.prototype 是 沒有constructor 屬性的
Bar.prototype = Object.create(Foo.prototype)Bar.prototype.myLabel = function() {return this.label
}var a = new Bar('a', 'obj a')console.log(a.myName())
console.log(a.myLabel())

我們來對比一下兩種把 Bar.prototype 關聯到 Foo.prototype 的方法:

// ES6 之前需要拋棄默認的 Bar.prototype
Bar.ptototype = Object.create( Foo.prototype )
// ES6 開始可以直接修改現有的 Bar.prototype
Object.setPrototypeOf( Bar.prototype, Foo.prototype )

?

JavaScript中沒有類,只有對象,所以沒有類繼承,只有對象的委托,通過 b=Object.create(a) 可以將 b 的[[Prototype]] 屬性設為 a,這樣當在b中查找屬性找不到的時候就可以找到a。a中查找不到就繼續沿原型鏈查找。最終一般會查找到Object.prototype。默認字面量對象的[[Prototype]]是Object.prototype。這樣,只要在Object.prototype上定義一些函數toString(), valueOf()等,所有對象都可以使用。

new Foo() 操作可以生成一個對象,然后將對象的[[Prototype]] 綁定到Foo.prototype,并將Foo的this綁定為這個新函數,如果Foo()沒有返回值的話,該函數將作為返回值。可以看出new像是一個輔助功能,來方面在JS中模擬類似類的操作。注意,如果Foo返回了一個對象,那個new返回的也就是那個對象,新生成的對象將被拋棄。而那個對象,可能和Foo沒有任何關系。

?

對象關聯(OLOO, objects linked to other objects)

Task = {setID: function(ID) {this.id = ID;},outputID: function() {console.log(this.id);}
};
// 讓XYZ委托Task
XYZ = Object.create(Task);
XYZ.prepareTask = function(ID, Label) {this.setID(ID);this.label = Label;
};
XYZ.outputTaskDetails = function() {this.outputID();console.log(this.label);
};
// ABC = Object.create( Task ); 
// ABC ... = ...

XYZ.prepareTask('123', 'Task-xyz')
XYZ.outputTaskDetails()

在上面的代碼中,id 和 label 數據成員都是直接存儲在 XYZ 上;在委托行為中我們會盡量避免在 [[Prototype]] 鏈的不同級別中使用相同的命名,否則就需要使用笨拙并且脆弱的語法來消除引用歧義。你無法在兩個或兩個以上互相(雙向)委托的對象之間創建循環委托。

?

其實對象關聯的風格更容易理解,而原型模式反而像是為了“模擬類”而出現的風格。直接通過new操作符來執行函數的內容,同時將對象的原型鏈接到函數的prototype。instanceof 專門用來檢查通過這個方法創建對象后兩這的關聯。

?

理解了這本書講的內容,其實這張圖也不是很難看懂……

?

?

Function.prototype = Function.__proto__ = Object.__proto__
Function.prototype.__proto__ = Function.__proto__.__proto__ = Object.__proto__.__proto__ = Object.prototypeObject.prototype.__proto__ = null // Object.prototype 是對象

Function.prototype.prototype = undefined // Function.prototype 是函數

?

?

?

轉載于:https://www.cnblogs.com/wenruo/p/9329352.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251160.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251160.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251160.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ES5-15 數組基礎、數組方法、數組排序

創建數組 字面量 var arr []構造函數 var arr new Array()不使用new var arr Array() 所有數組都繼承于Array.prototype&#xff0c;能使用其中的數組方法 數組是另一種形式的對象&#xff0c;訪問機制相同數組的empty項打印出來是undefined&#xff0c;empty不是值只是一個…

Centos 7 配置 NFS

安裝NFS包 yum install nfs-utils.x86_64 啟動NFS服務需要首先啟動rpcbind服務&#xff0c;這個rpcbind包已經在上面安裝好了 先配置 /etc/exports 文件 vi /etc/exports /etc/exports文件內容格式&#xff1a; <輸出目錄> [客戶端1 選項&#xff08;訪問權限,用戶映射,其…

數學期望筆記

基礎知識點 首先明確期望公式:\[E(X)∑_ip_i*x_i\] 其中 \(p\) 代表概率 , \(x\) 代表發生貢獻。 然后期望的幾點性質: 對于數學期望&#xff0c;我們還應該明確一些知識點&#xff1a; (1) 期望的“線性”性質 對于所有滿足條件的離散型的隨機變量\(X,Y\)和常量\(a,b\)有: \[E…

vue --- vue中的幾個鉤子屬性

1.創建前:beforeCreate <div id"app">{{name}}</div><script>let app new Vue({el:#app,data:{name:31231312},beforeCreate(){console.log(掛在前);console.log(this.$data);console.log(this.$el);}})</script>// beforeCreate()是在Vue掛…

ES5-16【utils】數組方法、類數組

數組方法 concat 返回值是拼接后的數組 toString 將數組轉成字符串&#xff0c;用逗號隔開 slice(a&#xff0c;b) [a&#xff0c;b) 不傳值&#xff0c;拷貝了一份不傳b&#xff0c;截取到最后一位傳b&#xff0c;截取到b之前的那位a/b是負數&#xff08;和splice一樣&a…

Catalan卡塔蘭數

卡塔蘭數 卡塔蘭數是組合數學中一個常出現在各種計數問題中出現的數列。由以比利時的數學家歐仁查理卡塔蘭 (1814–1894)命名。 卡塔蘭數的一般項公式為 另類遞歸式&#xff1a; h(n)((4*n-2)/(n1))*h(n-1); 前幾項為: 1, 1, 2, 5, 14, 42, 132, 429, …

vue --- v-html、v-bind

v-html // 有時候,我們需要展示<strong>,但直接使用下面的語法并不會顯示 <div id "app">{{name}}</div><script>let app new Vue({el:#app,data:{name:<strong>啦啦啦</strong>}}); </scritp> // 結果當然沒讓人失望此…

在樹莓派是安裝并配置NTP服務

我們都知道樹莓派的小巧和省電節省空間等太多的優勢&#xff0c;這里就不一一列舉了&#xff0c;那么樹莓派就需要長時間的運行&#xff0c;可以724的方式運行&#xff0c;那么我們就把樹莓派當作一個小的服務器來運行&#xff0c;可以跑一些小的應用&#xff0c;例如可以在局域…

Oracle使用總結

1. 在ORACLE中Service Name即為數據庫名稱&#xff1b; 2. 在做刪除操作時&#xff0c;需要加Commit進行操作提交&#xff1b; 3. 使用sqlldr將數據進行批量導入到ORACLE中&#xff1a; 3.1 Sqlldr命令的用法&#xff1a; sqlldr useridLoginName/PasswordTNSName controlC:\U…

ES5-17/18 錯誤信息、try_catch、嚴格模式

錯誤信息 語法錯誤 標識符名稱&#xff08;變量、函數名&#xff09;不規范對關鍵字賦值基本語法錯誤&#xff0c;如分號打錯 引用錯誤 變量、函數未聲明給無法賦值的對象賦值var a 1 2 范圍錯誤 數組長度為負數方法參數超出可行范圍toFixed(-1) 類型錯誤 調用不存在…

vue --- v-text、v-show、v-if、v-else

v-text: <div id "app"><p v-text"msg"></p> </div> <script>let app new Vue({el:#app,data:{msg:Hello Vue}}) </script>// 可見v-text在某種程度上等價于 {{}}v-show: <div id "app"><div…

查找mac下騰訊視頻下載地址

mac 騰訊視頻下載的視頻是不可見的&#xff0c;也許是因為版權原因吧。使用以下方法可以在文件中找到緩存的視頻&#xff08;不過都是被斷開的很多短視頻&#xff09;。 在terminal輸入&#xff1a; cd Library/Containers/ 然后ls查看。查看當前的所有文件夾&#xff0c;你會看…

JS 新建web sql 數據表

//新建web sql數據庫數據表var tbName"tableName";var strSQL"create table if not exists tableName (id unique,th1,th2,th3)";function creatBDTable(strSQL,tbName){db openDB();db.transaction(function(tr) {tr.executeSql(strSQL,[],//SQL語句出成…

vue --- v-for、v-on、v-model、v-once

v-for: <div id "app"><ul><li v-for"item in list">{{item}}</li></ul> </div> <script>let app new Vue({el:#app,data:{list:[B,A,T]}}) </script>拿到索引index: <div id"app">&…

ES5-19 變量聲命周期、垃圾回收原理、arguments

變量聲命周期 垃圾回收 找出不再使用的變量釋放其占用內存固定的時間間隔運行 解除由于閉包產生的對fn AO的引用 標記清除 排除全局變量、排除閉包引用的AO中的變量進入環境 → 離開環境常用 引用計數 引用計數為0時清除對循環引用的情況&#xff0c;如果不手動接觸引用…

bzoj 1801: [Ahoi2009]chess 中國象棋【dp】

注意到一行只能放012個炮&#xff0c;我們只需要知道列的狀態&#xff0c;不用狀壓行 所以設f[i][j][k]表示前i行有j列有1個炮&#xff0c;有k列有2個炮的方案數 然后分情況討論轉移就行了 #include<cstdio> #include<iostream> using namespace std; const int N1…

vue --- compoent妙用

首先利用寫一個靜態模板的組件 <div id "app"><my-arti></my-arti> </div> <script>Vue.component(my-arti,{template:<div style"border:1px solid black"><span>date:2019年06月14日</span><br>…

ES5-20 復習

3-1 變量單一聲明方式String Boolean undefined Number nullundefined nulltypeof(null) ‘object’typeof(方法) ‘function’typeof() 是運算符&#xff0c;不是數據類型 報錯0 -0 trueInfinity -Infinity falseNaN和誰都不等原始值沒有屬性 要打印屬性、調用方法得經過基…

eclipse中去掉警告提示

有時候我們要去掉這些不必要的提示 下面我們來設置去掉這些警告提示 轉載于:https://www.cnblogs.com/xiaostudy/p/9370016.html

vue --- vue-router

vue-router的CDN <script src "https://unpkg.com/vue-router2.5.3/dist/vue-router.js"></script>// 當然還需要導入vue的cdn <script src"https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>使用router-link(to)添加點擊鏈…