函数
function在非严格模式中无块级作用域
arguments
arguments ❌后期停止支持:在函数中使用 arguments对象是个类似Array只有length属性以及索引。非严格模式中的函数有包含剩余参数、默认参数、解构赋值时参数会浅拷贝arguments对象中的值不会跟踪参数的值
function func(a) {
a = 99; // 更新了a 同样更新了arguments[0]
console.log(arguments[0]);
}
func(10) //99
function func(a = 55) {
arguments[0] = 99; // updating arguments[0] does not also update a
console.log(a);
}
func(10); // 10
function func(a = 55) {
a = 99; // updating a does not also update arguments[0]
console.log(arguments[0]);
}
func(10); // 10
构造函数
构造函数返回的默认值是 this 所指的那个对象如果手动返回的值不是一个对象,则返回 this 对象
getter setter
设置的属性在访问它们时才会计算属性的值
get在class中设置的属性将被定义在实例的原型上
defineProperty在class实例自身上
// 创建
const obj = {
firstName:"h",
lastName:"hh",
ids:[],
get name() {
return this.firstName+this.lastName;
},
set id(val){
this.ids.push(val)
}
}
console.log(obj.name) // hhhh
obj.id=1
console.log(obj.id) // undefined
console.log(obj.ids) // [1]
// 删除
delete obj.latest
console.log(obj.name) // undefined
delete obj.id
obj.id=1
console.log(obj.id) // 1
console.log(obj.ids) // [1]
//定义现有对象
Object.defineProperty(obj, 'name', {
get: function () {
return this.firstName+this.lastName;
},
set:function (val) {
return this.ids.push(val);
}
});
console.log(obj.name) // hhhh
obj.name=2
console.log(obj.ids) // [1,2]
箭头函数表达式 =>
没有自己的this,arguments,super或new.target 不能做函数生成器
this
函数的调用方式决定了 this 的值(运行时绑定)
全局执行环境中this都指向全局对象 globalThis任何环境下都是指向全局对象
在类中基本与函数表现一致但不包括静态的方法
绑定优先级new > 显示绑定bind > 显示绑定call、apply > 隐式绑定obj. > 默认绑定。
var a = 'Global';
function New(){
this.a="new"
}
obj=new New()
console.log(obj.a) // new
var b = 'Global';
function New(){
this.b="new"
console.log(this)
}
obj=new New() // {b: "new"}
var foo = New.bind({a:"bind"})
foo() // {a: "bind", b: "new"}
foo.call({a:"call"}) //{a: "bind", b: "new"}
foo.apply({a:"apply"}) //{a: "bind", b: "new"}
new foo() // {b: "new"}
var obj = {foo}
obj.foo() // {a: "bind", b: "new"}
var obj = {foo:New}
obj.foo() //{b: "new", foo: ƒ}
obj.foo.call({a:"call"}) //{a: "call", b: "new"}
-
类中
class B { constructor() { // 无return或非对象 会隐式retutn this; } } class Base {} class Good extends Base {} class AlsoGood extends Base { constructor() { // // 执行super()时会隐式调用this = new Base(); super() } } class Bad extends Base { constructor() { // 无super()并且无return,ReferenceError // 无super()并且return 非对象,TypeError } } new Good(); new AlsoGood(); new Bad(); // ReferenceError -
函数中 取决于函数被调用的方式
var obj = {a: 'Custom'}; // 声明一个变量,并将该变量作为全局对象 window 的属性。 var a = 'Global'; function whatsThis(a,b) { return this.a; // this 的值取决于函数被调用的方式 } // 在非严格模式下会将非对象尝试转换为对象 // whatsThis.call(7)// new Number(7) whatsThis(1); // 'Global' whatsThis.call(obj,1,2); // 'Custom' whatsThis.apply(obj,[1,2]); // 'Custom' // 会创建一个与 whatsThis 具有相同函数体和作用域的函数this将永久地被绑定到了bind的第一个参数 whatsThis.bind(obj)(1); // 'Custom' -
箭头函数 与封闭词法环境的
this保持一致,设置为他被创建时的环境。在全局代码中,它将被设置为全局对象var obj = { bar: function() { var x = (() => this); return x; } }; // obj.bar()执行时 bar函数的this为obj,箭头函数在bar函数中创建this为function的this obj var fn = obj.bar() console.log(fn() === obj); // true // fn2()执行时 bar函数this为window,箭头函数在bar函数中创建this为function的this window var fn2 = obj.bar; console.log(fn2()() == window); // true -
DOM addEventListener中的函数指向触发事件的元素
-
内联事件处理函数 指向触发事件的元素所在的DOM元素
<button onclick="alert(this.tagName.toLowerCase());"> Show this </button>
异步及迭代
Promise
符合以下规则
- 在本轮 事件循环 运行完成之前,回调函数是不会被调用的。
- 即使异步操作已经完成(成功或失败),在这之后通过
then()添加的回调函数也会被调用。 - 通过多次调用
then()可以添加多个回调函数,它们会按照插入顺序进行执行。
// 即使是resolve 状态的 Promise,传递给 `then()` 的函数也总是会被异步调用
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
// then()中的函数会进入到一个微任务队列中
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
Promise对象状态
- 待定(pending) : 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled) : 意味着操作成功完成。
- 已拒绝(rejected) : 意味着操作失败。
静态方法
Promise.resolve(value)如果该value带有then方法,最终状态由then方法执行决定否则返回的Promise对象状态为fulfilled- [
Promise.reject(reason)](developer.mozilla.org/zh- CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject) 返回一个状态为失败的Promise对象 Promise.all(iterable)其中有一个失败则会被catchPromise.allSettled(iterable)所有异步都完成了调用then()Promise.any(iterable)任何一个先成功resolve 值Promise.race(iterable)任何一个先成功或失败的值
generator 生成器函数 function*
GeneratorFunction构造器的实例对象。GeneratorFunction不是全局对象可以通过(function*(){}).__proto__.constructor获取。
调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器对象当这个迭代器的 next() 方法被调用时才会执行,执行到一个yield开始下一条yield开始之前。
var res=0;
function *increasing(){
let index =0
while(true){
yield index++;
if(index>2){
return index;
}
}
}
function *gen(){
const x=yield 'foo';
yield x;
res = yield* increasing();
yield "end";
}
const g = gen()
// 使用console.log(g.return()) 将结束迭代 {value: 'undefined', done: true}
console.log(g.next()); // {value: 'foo', done: false}
// 当yield左边有=时下次的next操作可以添加参数赋给=左边的变量
console.log(g.next("x")); // {value: 'x', done: false}
// yield* 表示将执行权移交给另一个生成器函数
console.log(g.next()); // {value: 0, done: false}
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
// 另一个结束切回gen
console.log(g.next()); // {value: 'end', done: false}
console.log(g.next()); // {value: 'undefined', done: true}
console.log(res); // 3
可迭代协议
符合协议可以有迭代行为。一个对象或原型链上必须实现 @@iterator 方法
属性为[Symbol.iterator]值为一个无参数的函数返回值为符合迭代器协议的对象
var myIterator = {
[Symbol.iterator]: function() {
return {
next: function() {
let done = this.done
if(!done){
this.done = true
}
return { value:"my",done };
},
done: false
};
}
}
console.log([...myIterator]) // ["my"]
迭代器协议
拥有next() 方法的一个对象。next方法无参数返回{value: any, done: boolean}对象其中done为true时表示迭代完毕
function makeIterator(array) {
let nextIndex = 0;
return {
next: function () {
return nextIndex < array.length ? {
value: array[nextIndex++],
done: false
} : {
done: true
};
}
};
}
let it = makeIterator(['哟', '呀']);
console.log(it.next().value); // '哟'
console.log(it.next().value); // '呀'
console.log(it.next().done); // true
async函数
generator与Promise语法糖
返回值为一个Promise。返回非Promise将会被隐式地包装在一个promise中
async function foo() {
return 1
}
// 等价与
function foo() {
return Promise.resolve(1)
}
async function foo() {
await 1
}
//等价于
function foo() {
return Promise.resolve(1).then(() => undefined)
}
几种模式
var resolveAfter2Seconds = function() {
console.log("slow start");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("slow done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("fast start");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("fast done");
}, 1000);
});
};
// 按顺序启动
var sequentialStart = async function() {
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. this runs 3 seconds after 1.
}
/*
slow start
Promise {<pending>}
slow done
slow
fast start
fast done
fast
*/
sequentialStart()
// 并发执行 等待所有异步完毕后执行
var concurrentStart = async function() {
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second(); // starts timer immediately
// 1. Execution gets here almost instantly
console.log(await slow); // 2. this runs 2 seconds after 1.
console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
//Promise 写法 结果相同
var concurrentPromise = function() {
console.log('==CONCURRENT START with Promise.all==');
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
});
}
concurrentStart()
/*
slow start
fast start
Promise {<pending>}
fast done
slow done
slow
fast
*/
// 并行执行 哪个先完成就执行哪个
var parallel = async function() {
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
]);
}
// Promise 写法 执行顺序相同 但无函数返回值
var parallelPromise = function() {
resolveAfter2Seconds().then((message)=>console.log(message));
resolveAfter1Second().then((message)=>console.log(message));
}
parallel()
/*
slow start
fast start
Promise {<pending>}
fast done
fast
slow done
slow
*/
parallelPromise()
/*
slow start
fast start
undefined
fast done
fast
slow done
slow
*/
async function* 异步迭代生成器
异步迭代协议的对象
var asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < 2) {
return Promise.resolve({ value: this.i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
(async function() {
for await (num of asyncIterable) {
console.log(num);
}
})();
// 0
// 1
模块化
立即执行函数(IIFE)
利用函数作用域创建私有作用域全局变量和函数的命名冲突
CommonJS
非浏览器环境规范
require函数进行导入export或者module.exports导出- 有缓存 依据文件名进行缓存 如果不区分大小系统
require('./foo')和require('./FOO')返回两个不同的对象 - 在执行模块代码之前,Node.js对其进行封装
(function(exports, require, module, __filename, __dirname) { // 模块代码实际存在于此处 }); function require(/* ... */) { const module = { exports: {} }; ((module, exports) => { // 模块代码在这里。 在本例中,定义一个函数。 function someFunc() {} exports = someFunc; // 此时,exports 不再是 module.exports 的快捷方式, // 并且此模块仍然会导出空的默认对象。 module.exports = someFunc; // 此时,该模块现在将导出 someFunc, // 而不是默认对象。 })(module, module.exports); return module.exports; }
因此导出的写法为
exports.a=1
exports.b=2
// 完全等于
module.exports.a=1
module.exports.b=2
// ------------------
// 而node导出的是 module.exports exports只是引用因此
exports={a:1} // 并没有导出
module.exports={a:1} //导出
导入
AMD规范
- 导出
define('amdModule', ['dependencyModule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => { // 业务逻辑 return {} } }) - 导入
require(['amdModule'], amdModule => { amdModule.xxx })
UMD
- 导出
define('amdModule', ['dependencyModule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => { // 业务逻辑 return {} } }) - 导入
require(['amdModule'], amdModule => { amdModule.xxx })
es模块
在html中使用模块时需要指示type="module"引入的模块<script type="module" src="">
模块脚本与标准脚本区别
-
模块自动使用严格模式
-
需要HTTP 服务器运行,
file://引入会跨域 -
模块会自动延迟加载
-
他们无法在全局获得只能在导入这些功能的脚本文件中使用
-
导入导出
// a.mjs const b = 2; const c = { d:3 } export const a =1 export function FunctionName(){} export class ClassName {} export { b } export const { d:d1 } = c; export const { b as b1 } export default c // b.mjs // 无default导出必须使用*导出或者{}导出 import * as a from "./a.mjs"; // 或 import c,{a,FunctionName} from "./a.mjs" c为default导出 a.FunctionName() a.a===1 a.b===2 a.default.d===3 //重导出 / 聚合 // c.mjs // 将模块中的default重命名c导出 export { default as c } from "./a.mjs" // 导出ab export { a, b } from "./a.mjs"
其他
in
判断可枚举属性是否在对象或其原型链中
左边为 字符串类型或者 symbol 非symbol类型将强制转换成字符串。右操作数必须是一个对象值
Symbol.iterator in [] // true
0 in [1] // true
模板字符串
允许嵌入表达式的字符串字面量
带标签的模板字符串
function tag(strings,...rest) {
console.log(strings,rest);
}
String.raw`${1}a${2}` // '1a2'
tag`${1}a${{a:2}}` //['', 'a', '',length: 3, raw:['', 'a', '']] [1, {a:2}]
会发生转义
- Unicode字符以"\u"开头,例如
\u00A9 - Unicode码位用"\u{}"表示,例如
\u{2F804} - 十六进制以"\x"开头,例如
\xA9 - 八进制以""和数字开头,例如
\251