《你不知道的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.mzph.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)添加点击链…