美文网首页
JS科普帖

JS科普帖

作者: hellodyp | 来源:发表于2024-05-16 19:19 被阅读0次

    前言

    不同语言有不同的范式、思想
    了解不同的范式,有助于思路、思维的启发。所谓触类旁通
    computer语言始终是工具、武器,而不是拿来争论的谈资,可以为我所用,而不必为之所限

    口号: 学习js 为自己赋能

    简介

    一门非常灵活的 动态 、弱类型 语言

    反直觉:
    1 性能 2 难度

    语言热榜(只是排行和好坏无关)


    image.png

    跑个分:


    image.png

    参考(仅参考不必较真):
    https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html
    https://goodmanwen.github.io/Programming-Language-Benchmarks-Visualization/

    历史

    90年代, Brendan Eich 给 Netscape 开发的浏览器辅助语言 Mocha(后更名为 JavaScript),耗时10天出原型(包含了eval 函数),集成到 Netscape 2预览版里,Mocha 基于对象而非 Java 那样基于类。

    Mocha 的动态的对象模型,使用原型链的机制。

    Netscape 2 正式版将 Mocha 更名为 JavaScript,后简称 js。

    1.0 版本 js 语法大量借鉴 C 语言。行末可不加分号,一开始 js 就是支持的。

    1.1版 js 支持隐式类型转换,可以把任意对象转成数字和字符串。1.0版 js 对象不能继承,1.1 加入对象的 prototype 属性,prototype 的属性和实例的对象共享。
    为了加到 ISO 标准中,Netscape 找到了 Ecma,因为 ISO 对 Ecma 这个组织是认可的。接着 Ecma 组建了 TC39 技术委员会负责创建和维护 js 的规范。

    期间,微软为了能够兼容 js,组建了团队开发 JScript,微软自己摸索然后开发,并写了份规范 The JScript Language Specification, version 0.1 提交给 TC39,微软还将 VBScript 引入 IE。96年 Netscape 为 JavaScript 1.1 写了规范 Javascript 1.1 Specification in Winword format 作为 TC39 标准化 js 的基础。

    97年 TC39 发布了 ECMA-262 第一版规范。

    Netscape 3 发布后,Brendan Eich 重构了 js 引擎核心,加了嵌套函数、lambda、正则表达式、伪属性(动态访问修改对象)、对象和数组的字面量、基于标记和清除的 GC。lambda 的函数名为可选,运行时会创建闭包,闭包可递归引用自己作为参数。新 js 引擎叫 SpiderMonkey。增加break / continue 标签语句以及 switch。语言升级为 JavaScript 1.2,和 SpiderMonkey 一起集成到 Netscape 4.0。

    ES3 结合了 js 1.2 和 JScript 3.0,标准坚持了10年。

    2006年 Google 的 Lars Bak 开始了 V8 引擎的开发,2008 基于 V8 的 Chrome 浏览器发布,性能比 SpiderMonkey 快了10倍。

    Ryan Dahl 2009 开发了 Node.js ,提供标准库让 js 能够建立 HTTP 服务端应用。此后js就不再局限于前端领域了
    ES4 初期目标是希望能够支持类、模块、库、package、Decimal、线程安全等。

    这一版本ES4太激进, 很多特性无法通过,而没法通过标准,因此同步设计了10年多的 ES 3.1 最终改名为 ES5
    2015年,(ECMAScript 2015)[]发布。这是改动最多的一个版本,加入了大量的语法特性,此后每年发布一版标准

    ES6特性

    箭头函数、Promise、迭代器....

    应用场景

    前端、服务端、脚本工具

    基础语法

    变量声明

    const
    let
    var

    类型

    number、string、symbol、undefined、null、object、array、function

    常见编码规范

    switch、for、 if、new
    语法参考了C 家族的风格:
    条件判断、for循环都需要放到()里
    switch需要手动break

    for (let i =0 ; i<3; i++){
        // do something
    }
    
    switch ("some var") {
    case "some var":
        // logic
        break
    case "other":
        // ...
    }
    
    class A{}
    const a = new A();  // 符合直觉的创建对象
    

    解构

    let obj = {hello:"world"};
    let {hello} = obj;
    console.log(hello);
    
    let obj2 = {obj};
    console.log(obj2);
    

    遍历

    for

    let arr = [1,2,3];
    
    for (let i = 0; i < arr.length; i++){
        console.log(arr[i])
    }
    
    for (let i in arr){
        console.log(arr[i]);
    }
    
    for (let i of arr){  // es6 新增  实现迭代器接口即可 使用此种遍历方式
        console.log(i);  // 注意此处直接取到value
    }
    
    arr.forEach(i=> console.log(i));  // 闭包形式 不支持break、continue
    
    let arrMulti = arr.map(i=>i*i);  // 返回值
    
    let obj = {a:"a", b:3};
    
    for (let i in obj){
        console.log(i, "value", obj[i]);
    }
    
    for (let i of Object.keys(obj)){   // 对象未实现 iterator接口
        console.log(i, "value", obj[i]);
    }
    

    while、do...while

    函数

    1 复用代码

    2 构造对象

    function makeObj(){
        this.name = "new obj";
    }
    
    let o = new makeObj();
    console.log(o)
    
    

    3 箭头函数

    const arrow = (params1, params2) =>{
        console.log('abc');
    };
    // 简写
    arrow = (params1, params2) =>console.log('abc');
    
    // 单参数可忽略括号
    arrow = params =>console.log('abc');
    

    一般高阶函数的参数(闭包)可用箭头函数

    const pro = new Pormise(function(resolve, reject){ resolve('async resolve')});
    
    

    其次,也可以当做普通函数使用,且不可以当做构造函数

    const print = ()=> console.log('hello world');
    const obj = new print(); // error
    

    箭头函数没有自己的this

    闭包

    特征:

    1 闭包是(一种特殊的)function
    2 闭包一般作为高阶函数的参数或嵌套定义的function
    3 闭包[调用态]捕获(感知)所在作用域、作用域外层上下文

    js世界中的闭包应用非常广泛
    1 js最初是浏览器环境运行的,运行时单线程,早先异步都是通过回调函数来实现,回调函数即最常见的闭包运用场景

    request("baidu.com", function(err, response){
        if (err){
         throw "bad request";
        }
        console.log(response.status)
    })
    

    2 给DOM元素注册监听函数

    // 这里是 ctx  let someVar = ...
    document.addEventListener("foo", event => { // 在 document 上绑定 foo 事件的监听函数
          event.preventDefault()
          // do something ...
        }
    }
    

    应用:

    // 模拟私有变量
    function makeIncrement(){
        let __somePrivate = 1;  // 此变量外界无法干预
        return function(){
            // 有内存泄漏嫌疑
            return __somePrivate++;   // 注意前后缀++运算符区别
        }
    }
    
    let incementer = makeIncrement();
    let count = incrementer(); // 1
    count = incrementer(); // 2
    

    语法迷思

    js有很多操作其实都是反直觉的

    原型链

    如果用传统面向对象语言类比,那么原型链是类与类之间的关系,此处需要区别类 和实例

    领域关键字

    arguments
    this:
    传统面向对象语言中的this

    class MyObj{
        constructor(name: string){  // 构造器
            this.name = name;
        }
        say(){
            console.log(`my name is ${this.name}`);
        }
    }
    
    let obj = new MyObj("xiao zhang");
    obj.say();
    

    bind、call、apply
    slice、substr、substring

    this解谜

    1 this绑定

    四种绑定方式
    遵循以下优先级
    new绑定 > 显式绑定 > 隐式绑定 > 默认绑定

    new
    function A(){
        this.a = "a";
    }
    let a = new A();
    
    显式
    function Greeting(){
        this.name = 'zhansan';
        this.greeting = function(){
           console.log(`hello ${this.name}`)
        }
    }
    const obj = {name : "wangwu"};
    new Greeting().greeting.call(obj);
    
    隐式
    const obj = {
        name: 'zhangsan',
        greeting: function(){
           console.log(`hello ${this.name}`)
        }
    }
    obj.greeting();
    const obj2 = {name:"aaa"};
    obj2.hello = obj.greeting;
    obj2.hello();
    
    默认

    其他方式都算做默认绑定

    2 箭头函数this

    1 不准确的说法
    箭头函数指向外层
    箭头函数this始终不变

    let obj = {
        a: ()=> console.log(this),
    };
    obj.a();
    obj = function(){
        this.a = ()=> console.log(this);
    }
    new obj().a();
    
    obj = {
        a:  {
            b: ()=> console.log(this),
        },
    };
    obj.a.b();
    
    obj = {
        a:  function(){
            return ()=> console.log(this);
        },
    };
    obj.a()();
    // 箭头函数this始终指向外层【函数】所绑定的作用域
    // 箭头函数this始终不变 是错误的说法
    let b = {b:"b"};
    b.a = obj.a;
    b.a()();
    
    obj = {
        a:  function(){
            this.hello = 'world';
            this.b = ()=> console.log(this);
        },
    };
    new obj.a().b();
    

    3 规则

    this的值在函数被调用的时候才会指定

    应用解答

    前置知识

    var关键字

    1 挂载到window对象
    2 变量不经申明也挂载到window对象下
    坑点: 全局变量污染

    function b(){
        c = 18;
    }
    b();
    console.log(c);
    

    3 没有块级别作用域

    if (true){
        var hello = 'world';
    }
    console.log(hello);
    
    var和let区别

    1 不挂载window
    2 有块级别作用域

    var number = 5;
    var obj = {
        number: 3,
        fn1: (function () {
            var number;   // undefined
            this.number *= 2;  // 10
            number = number * 2;  // NaN
            number = 3;   // bibao.number = 3
            return function () {
                //  this == obj
                var num = this.number;  // num = 10  、3
                this.number *= 2;  // this.number = 20  、6
                console.log(num);  // print 10   3
                number *= 3;   // bibao.number = 9   、27
                console.log(number);  //print 9   27
            }
        })()
    }
    var fn1 = obj.fn1;
    fn1.call(null);  // window.fn1()
    obj.fn1();
    console.log(window.number);  // 20
    

    Promise API

    | 天不生ES6 JS万古如长夜
    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

    构造函数

    // 主意构造方法  比较独特
    const myPromise = new Promise((resolve, reject)=>{
        if (// 异步操作成功)  resolve('success');
        reject('error');
    })
    
    // then  方法接收两个函数 分别是成功和失败的处理
    myPromise.then(()=> console.log('hello world'))
    

    此时 myPromise 是一个thenable 对象, 且通过then方法返回的也是 promise对象

    特点

    对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
    一旦状态改变,就不会再变,任何时候都可以得到这个结果。

    实例方法

    所有promise 对象的实例方法均会返回promise对象,从而可以形成调用链

    const obj = new Promise(function(reslove, reject){
        // do somthing
        resolve();
    })
    obj.then(()=> consolt.log('hello world')).
    catch(e=> console.log(e)).finally(()=>console.log('over'));
    
    // then 方法接收两个参数
    obj.then((rst)=>console.log('success with result ', rst),
    err => console.log(err)
    )
    // catch 是 then(null, rejection)的快捷方式  一般推荐catch方式处理失败情况
    obj.then((rst)=>console.log('success with result ', rst)).
    catch(err => console.log(err));
    
    // catch 可以处理  构造函数里  reject 抛出的错误 
    // 也可以处理 resolve或 then 里通用代码抛出的异常
    obj.then(()=>{
        throw new Error('err')
    }).catch((e)=>console.log(`catch error ${e}`));
    

    // 此时如果没有catch 的话则会抛出运行时异常

    静态方法

    Promsie.all

     const p = Promise.all([p1, p2, p3]);
    

    Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

    p的状态由p1、p2、p3决定,分成两种情况。(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    Promise.race

    Promise.allSettled

    Promise.resolve

    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))
    // resolve方法相当于一个快捷方式  
    

    resolve的参数:
    1 promise对象则原封不动返回
    2 thenable 对象则立即执行then方法然后返回结果对象的promise包装
    3 其他则包装参数中内容为 resolve状态的promise对象

    何谓thenable
    let thenable = {
      then: function(resolve, reject) {
        resolve(42);
      }
    };
    

    Promise.reject

    相关文章

      网友评论

          本文标题:JS科普帖

          本文链接:https://www.haomeiwen.com/subject/ckcifjtx.html