js知识点

122 阅读8分钟

函数

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

设置的属性在访问它们时才会计算属性的值 getclass中设置的属性将被定义在实例的原型上 definePropertyclass实例自身上

// 创建
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]

箭头函数表达式 =>

没有自己的thisargumentssupernew.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) : 意味着操作失败。

静态方法

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

判断可枚举属性是否在对象或其原型链中 左边为 字符串类型或者 symbolsymbol类型将强制转换成字符串。右操作数必须是一个对象值

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