网站建设入门教程视频教程,国产软件开发工具,施工企业信用综合评价系统,虚拟资源交易商城wordpress文章目录 第7章#xff1a;迭代器与生成器1. 迭代器模式2. 生成器 第8章#xff1a;对象、类与面向对象编程1. 理解对象2. 创建对象3. 继承#xff1a;依靠原型链实现4. 类class 第10章#xff1a;函数1. 函数定义的方式有#xff1a;函数声明、函数表达式、箭头函数… 文章目录 第7章迭代器与生成器1. 迭代器模式2. 生成器 第8章对象、类与面向对象编程1. 理解对象2. 创建对象3. 继承依靠原型链实现4. 类class 第10章函数1. 函数定义的方式有函数声明、函数表达式、箭头函数Function构造函数。2.箭头函数3. 函数名就是指向函数的指针。4. 理解参数5. 没有重载6. 默认参数值7. 参数扩展与收集8. 函数声明与函数表达式9. 函数作为值10. 函数内部11. 函数属性与方法12. 函数表达式13. 递归14. 尾调用优化15. 闭包16. 立即调用的函数表达式17. 私有变量 第7章迭代器与生成器
1. 迭代器模式
把实现了正式的Iterable接口的某些结构称为“可迭代对象”iterator可以通过迭代器Iterator消费。可迭代对象元素有限且具有无歧义的遍历顺序。可迭代协议实现Iterator接口 要求同时具备两种能力支持迭代的自我识别能力和创建实现Iterator接口的对象的能力。必须暴露一个属性作为“默认迭代器”而且这个属性必须使用特殊的Symbol.iterator作为键。默认迭代器属性必须引用一个迭代器工厂函数调用这个工厂函数必须返回一个新迭代器。不需要显式调用工厂函数来生成迭代器。接收可迭代对象的原生语言特性包括 for-of循环数组解构不懂看下面例子有点明白了 // 数组解构 let [a, b, c] arr; console.log(a, b, c); // foo, bar, baz扩展操作符Array.from()创建集合创建映射Promise.all()接收由期约组成的可迭代对象期约是什么见第11章Promise.race()接收由期约组成的可迭代对象yield*操作符在生成器中使用这个暂时也不懂 迭代器协议 迭代器API使用next()方法在可迭代对象中遍历数据。next()方法返回迭代器对象IteratorResult包含两个属性done和value。done是一个布尔值表示是否还可以再次调用next()取得下一个值value包含可迭代对象的下一个值。 自定义迭代器提前终止迭代器
2. 生成器
生成器基础 生成器的形式是一个函数函数名称前面加一个星号*表示它是一个生成器。标识生成器函数的星号不受两侧空格的影响。生成器函数声明function* generatorFn() { }调用生成器函数会产生一个生成器对象。 通过yield中断执行生成器可以用来作为默认迭代器。可以提前终止生成器。可选的return()方法用于提前终止迭代器。与迭代器不同所有的生成器对象都有return()方法只要通过它进入关闭状态就无法恢复了。后续调用next()会显示donetrue状态。throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理生成器就会关闭。如果生成器对象还没有开始执行那么调用throw()抛出的错误不会在函数内部被捕获因为这相当于在函数块外部抛出了错误。
第8章对象、类与面向对象编程
1. 理解对象
属性的类型[[ ]] 数据属性 包含一个保存数据值的位置。值会从这个位置读取也会写入到这个位置。四个特性[[Configurable]]、[[Enumerable]]、[[Writable]]、[[Value]]修改属性默认值方法Object.defineProperty()实际情况中不太用得到。 访问器属性 getter()读取访问器属性setter()设置访问器属性四个特性[[Configurable]]、[[Enumerable]]、[[Get]]、[[Set]]访问器属性是不能直接定义的必须使用Object.defineProperty() 定义多个属性Object.definedProperties() let book {}; Object.definedProperties(book,{ year_: { value: 2023 }, edition: { value: 1 } })读取属性的特性 使用Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。这个方法接收两个参数属性所在的对象和要取得其描述符的属性名。返回值是一个对象。 let descriptor Object.getOwnPropertyDescriptor(book, year_); console.log(descriptor.value); // 2023 console.log(descriptor.configurable); // false Object.getOwnPropertyDescriptors()静态方法。这个方法实际上会在每个自有属性上调用Object.getOwnPropertyDescriptor()并在一个新对象中返回它们。 合并对象Object.assign()方法对象标识及相等判定Object.is()方法增强的对象语法 属性值简写只要使用变量名就会自动被解释为同名的属性键。可计算属性简写方法名 对象解构 嵌套解构部分解构参数上下文匹配
2. 创建对象 工厂模式 function createPerson(name, age, job) {let o new Object();o.name name;o.age age;o.job job;o.sayName function() {console.log(this.name);};return o;
}构造函数模式 function Person(name, age, job){this.name name;this.age age;this.job job;this.sayName function() {console.log(this.name);};
}构造函数也是函数任何函数只要使用new操作符调用就是构造函数。如果没有使用new操作符调用会将属性和方法添加到window对象。通过call()调用函数的调用方式可以将特定对象指定为作用域。构造函数的问题是其定义的方法会在每个实例上都创建一遍。为解决这个问题可以把函数定义转移到构造函数外部。新问题全局作用域被搞乱了导致自定义类型引用的代码不能很好地聚集在一起解决方法是原型模式。 原型模式 function Person() {}
Person.prototype {name: Nicholas,age: 29,job: Software Engineer,sayName() {console.log(this.name);}
};每个函数都会创建一个prototype属性叫原型对象。它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值可以直接赋值给它们的原型。注意理解实例与构造函数原型之间有直接的联系但实例与构造函数之间没有。原型层级通过对象访问属性时会按照属性名称开始搜索从对象实例开始搜索如果没有找到搜索会沿着指针进入原型对象然后在原型对象上进行搜索。这就是原型用于在多个对象实例间共享属性和方法的原理。只要给对象实例添加一个属性这个属性就会遮蔽shadow原型对象上的同名属性不会修改但会屏蔽对原型对象的访问。使用delete操作符删除实例上的这个属性则可以继续搜索原型对象。原型和in操作符 in操作符只要通过对象可以访问就返回true。hasOwnProperty()只有属性存在于实例上时才返回true。 属性枚举顺序 for-in循环和Object.keys()的枚举顺序是不确定的。Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()和Objetc.assign()的枚举顺序是确定性的。 对象迭代 将对象内容转换为序列化的可迭代格式的两个静态方法Object.values()和Object.entries()。注意符号属性会被忽略。其他原型语法Person.prototype{};即使实例在修改原型之前已经存在任何时候对原型对象所做的修改也会在实例上反映出来。实例只有指向原型的指针没有指向构造函数的指针。原生对象原型也可以修改但是不建议这么做推荐做法是创建一个自定义类继承原生原型。原型的问题主要体现在操作包含引用值的属性时。
3. 继承依靠原型链实现
原型链 构造函数、原型和实例的关系每个构造函数都有一个原型对象原型有一个属性指回构造函数而实例有一个内部指针指向原型。当前原型是另一个原型的实例这样就组成了一个原型链。默认原型默认情况下所有引用类型都继承自Object。原型与继承关系原型与实例的关系可以通过instanceof操作符或者isPrototypeOf()方法来确定。子类增加父类没有的方法必须在原型赋值之后在添加到原型上。注意以字面量方式创建原型方法会破坏之前的原型链因为这相当于重写。原型链的问题 包含引用值时 子类型实例化时不能给父类型构造函数传参 盗用构造函数解决原型链的问题 思路在子类构造函数中调用父类构造函数。使用call()或者apply()方法。盗用构造函数的一个优点是可以在子类构造函数中向父类构造函数传参。盗用构造函数的缺点 必须在构造函数中定义方法因此函数不能重用。子类也不能访问父类原型上定义的方法因此所有类型只能使用构造函数模式。 组合继承原型式继承Object.create()第二个参数用来新增属性新增的属性会遮蔽原型对象上的同名属性。let person {name:wenshuo,friends:[yaya,xiaoxiao]
}
let anotherPerson Object.create(person,{name:{value:Greg}
});寄生式继承首倡的一种模式function object(o){function F(){}F.prototype o;return new F();
}
function createAnother(original){let clone object(original);clone.sayHi function (){console.log(Hi);}return clone;
}寄生式组合继承没看明白
4. 类class
类定义 类声明class Person { }类表达式const Animal class { }函数声明可以提升类声明不可以提升函数受函数作用域限制类受块作用域限制。 类构造函数 构造函数的定义不是必需的类实例化时传入的参数会用作构造函数的参数。如果不需要参数则类名后面的括号也是可选的。调用类构造函数必须使用new操作符把类当成特殊函数可以把类作为参数传递 实例、原型和类成员 实例成员每次通过new调用类标识符时都会执行类构造函数。原型方法与访问器为了在实例间共享方法类定义语法把在类块中定义的方法作为原型方法。静态类方法用于执行不特定于实例的操作也不要求存在类的实例。非函数原型和类成员class Person{sayName(){console.log(${Person.greeting} ${this.name})}
}
// 在类上定义数据成员
Person.greeting My name is;
// 在原型上定义数据成员
Person.prototype.name Jake;
let p new Person();
p.sayName();迭代器与生成器方法 继承 继承基础 使用extends关键字不仅可以继承一个类也可以继承普通的构造函数。构造函数、HomeObject和super()super的一些注意事项抽象基类可供其他类继承但本身不会被实例化。继承内置类型类混入好多js框架已经抛弃了混入模式转入了组合模式。组合胜过继承。
第10章函数
1. 函数定义的方式有函数声明、函数表达式、箭头函数Function构造函数。
2.箭头函数
不能使用arguments、super和new.target也不能用作构造函数也没有prototype属性。
3. 函数名就是指向函数的指针。
一个函数可以有多个名称。使用不带括号的函数名会访问函数指针而不会执行函数。所有函数对象都会暴露一个制度的name属性。如果函数是一个获取函数、设置函数或者使用bind()实例化那么标识符前面会加上一个前缀。
4. 理解参数
ECMAScript函数既不关心传入的参数个数也不关心这些参数的数据类型。使用function关键字定义非箭头函数时可以在函数内部访问arguments对象从中取得传进来的每个参数值。注意ECMAScript中的所有参数都是按值传递的。不可能按引用传递参数。如果把对象作为参数传递那么传递的值就是这个对象的引用。
5. 没有重载
如果在ECMAScript中定义了两个同名函数则后定义的会覆盖先定义的。
6. 默认参数值
显式定义默认参数在函数定义的参数后面用就可以为参数赋一个默认值。给参数传undefined相当于没有传值可以通过这种方式利用默认值。使用默认参数时arguments对象的值不反映参数的默认值只反映传给函数的参数。修改命名参数也不会影响arguments对象它始终以调用函数时传入的值为准。参数是按顺序初始化的遵循“暂时性死区”规则即前面定义的函数不能引用后面定义的。
7. 参数扩展与收集
扩展参数扩展操作符可以用于调用函数时传参。收集参数扩展操作符也可以用于定义函数参数。把不同长度的独立参数组合为一个数组。
8. 函数声明与函数表达式
在任何代码执行之前会先读取函数声明并在执行上下文中生成函数定义。这个过程叫做函数声明提升。函数表达式必须等到代码执行到它那一行才会在执行上下文中生成函数定义。
9. 函数作为值
函数名在ECMAScript中就是变量所以函数可以用在任何可以使用变量的地方。
10. 函数内部
arguments类数组对象。该对象有一个callee属性指向arguments对象所在函数的指针。// 让函数逻辑与函数名解耦
function factorial(num) {if (num 1) {return 1;} else {return num * arguments.callee(num - 1);}
} this 在标准函数中this引用的是把函数当成方法调用的上下文对象。在箭头函数中this引用的是定义箭头函数的上下文。 caller 函数的一个属性引用的是调用当前函数的函数如果是在全局作用域中调用的则为null。如果要降低耦合度可以通过arguments.callee.caller来引用相同的值。 new.target函数的一个属性检测函数是否使用new关键字调用的。
11. 函数属性与方法
每个函数都有两个属性length和prototype。 length保存函数定义的命名参数的个数。prototype是保存引用类型所有实例方法的地方。 函数的两个方法apply()和call()这两个方法都会以指定的this值来调用函数。 apply()两个参数函数内的this值和一个参数数组。call()与apply()作用一样传参形式不同。第一个参数也是this值剩下的要传给被调用函数的参数则是逐个传递的也就是说必须将参数一个一个地列出来。
12. 函数表达式
函数表达式与函数声明最大的区别就是函数声明可以提升函数表达式不可以。
13. 递归
递归函数通常的形式是一个函数通过名称调用自己。在编写递归函数时arguments.callee是引用当前函数的首选。严格模式下不可访问arguments.callee因此可以使用明明函数表达式named function expression严格模式和非严格模式下都可以使用。const factorial (function f(num){if(num 1){return 1;}else{return num*f(num-1);}
});14. 尾调用优化
尾调用外部函数的返回值是一个内部函数的返回值。
15. 闭包
参考链接闭包指的是那些引用了另一个函数作用域中变量的函数通常是在嵌套函数中实现的。闭包可以让开发者从内部函数访问外部函数的作用域。每个函数在调用时都会自动创建两个特殊变量this和arguments。内部函数永远不可能直接访问外部函数的这两个变量。先把外部函数的this保存到变量that中再访问就可以了。let that thisthat.xxx
16. 立即调用的函数表达式
立即调用的匿名函数又被称作立即调用的函数表达式IIFE, Immediately Invoked Function Expression。类似于函数声明但由于被包含在括号中所以会被解释为函数表达式。使用IIFE可以模拟块级作用域。(function(){// 块级作用域
})();17. 私有变量
任何定义在函数或块中的变量都可以认为是私有的因为在这个函数或块的外部无法访问其中的变量。私有变量包括函数参数、局部变量以及函数内部定义的其它函数。特权方法是能够访问函数私有变量及私有函数的公有方法。特权方法可以在构造函数中实现也可以使用静态私有变量来实现。每次调用构造函数都会重新创建一套变量和方法所以每个实例都会重新创建一遍新方法。静态私有变量可以利用原型更好地重用代码只是每个实例没有自自己的私有变量。模块模式 单例对象 let singleton {
name:value,
method(){
// 方法的代码
}
};模块模式是在单例对象基础上加以扩展使其通过作用域链来关联私有变量和特权方法。 模块增强模式 另一个利用模块模式的做法是在返回对象之前先对其进行增强。这适合单例对象需要是某个特定类型的实例但又必须给它添加额外属性或方法的场景。