第一次尝试用思维导图记笔记,感觉还不错~~~不过还是改不了我读书笔记写成抄书笔记的毛病 =。=

因为开始学JS的时候,一般浏览器就已经支持ES6了,所以比较喜欢使用ES6语法,let,=>等,文中代码不是抄书的,都用了ES6。

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 设置一个 getter
get: function() {
return this.a * 2
}, // 确保 b 会出现在对象的属性列表中
enumerable: true
}
) console.log(myObject.a) //
console.log(myObject.b) // a = 3
b = 5 console.log(myObject.a) //
console.log(myObject.b) //

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.data
this.$methods = options.methods
// 根据 dom 获取数据都绑定了哪些 dom 元素 并记录 以便数据更新的时候 同步更新dom
this._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 = val
this._binding[item].forEach((meth) => {
meth()
})
}
}
})
}) } /**
* @param {HTMLElement} root: vue 绑定的 dom 元素节点
**/
MyVue.prototype._complie = function(root) {
// 如果有子节点
const nodes = root.children
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (node.children.length) {
this._complie(node)
} // 如果是bind 证明绑定了某个数据 那么改数据更改时 更改该处 dom
if (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 节点更改时也更新 data
if (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>

详见: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.prototype Object.prototype.__proto__ = null // Object.prototype 是对象 Function.prototype.prototype = undefined // Function.prototype 是函数

《你不知道的JavaScript(上卷)》读书笔记的更多相关文章

  1. csapp读书笔记-并发编程

    这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...

  2. CSAPP 读书笔记 - 2.31练习题

    根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1)  属于第一种情况 sum = x ...

  3. CSAPP读书笔记--第八章 异常控制流

    第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...

  4. CSAPP 并发编程读书笔记

    CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  7. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  8. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  9. C#刨根究底:《你必须知道的.NET》读书笔记系列

    一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...

  10. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

随机推荐

  1. IEC2017级_1-2班2次博客作业成绩说明

    一.博客作业内容 2018上IEC计算机高级语言(C)作业 第2次作业 二.评分规则说明 1.程序调试题,要描述出调试所遇到问题及修改内容,并表述清楚程序功能.流程图不规范的会减1-2分: 2.知识点 ...

  2. jquery学习总结1-12

    一.jquery入口函数的几种写法 1.$(document).ready(function()  { } ) ; 2.jquery(document).ready(function()  { } ) ...

  3. js group by

    var arr = ['Car', 'Car', 'Truck', 'Boat', 'Truck'];var hist = {};hist = arr.reduce((prev, item) => ...

  4. gulp打包工具

    首先安装全局gulp $ npm install --global gulp 下载成功后 新建一个项目或者一个文件夹(做测试) mkdir testgulp 在该文件或者项目下下载gulp工具 $ n ...

  5. 01 C语言程序设计--01 C语言基础--第1章 C语言概述&第2章 GCC和GDB

    走进嵌入式开发的世界,企业级项目课程让你达到企业嵌入式应用开发要求.名师在线答疑,解决疑难.科学评测体系,系统评估学习.核心项目实........ 30 门课程 241小时12分钟 824 人学习 学 ...

  6. Codeforces Round #536 (Div. 2) F 矩阵快速幂 + bsgs(新坑) + exgcd(新坑) + 欧拉降幂

    https://codeforces.com/contest/1106/problem/F 题意 数列公式为\(f_i=(f^{b_1}_{i-1}*f^{b_2}_{i-2}*...*f^{b_k} ...

  7. PAT乙级1003

    1003 我要通过! (20 point(s)) “答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”, ...

  8. Filter的使用(web作业)

    一:什么是过滤器 Filter:Servlet过滤器Fileter是一个小型的web组件,它们通过拦截请求和响应,以便查看.提取或以某种方式操作客户端和服务器之间交换的数据,实现“过滤”的功能.Fil ...

  9. Linux 查找文件内容、替换

    有的时候我们经常性的需要在 linux 某一个目录下查找那些文件里包含我们需要查找的字符,那么这个时候就可以使用一些命令来查找,比如说 grep 1.grep 查询 1.1. 主要参数 [option ...

  10. js every some 遍历函数理解

    1.every let arr = [0, 1, 2, 3, 4, 5]; let result = arr.every((item, index) => { return item >= ...