How to code in JavaScript笔记

266 阅读5分钟

网站地址:www.digitalocean.com/community/t…

第一篇:How To Use the JavaScript Developer Console

  • Cmd + option + J 打开chome浏览器控制台
  • let today = new Date(); 可以获取系统当前时间
  • 控制台直接进行dom操作(更改是临时的):
    • 修改页面内容:
      • document.body.innerHTML = “<h1>whatever</h1>”
    • 元素样式修改(相当于body元素的inline style):
      • document.body.style.backgroundColor = “lightblue”
    • 添加段落元素标签:
        1. let p = document.createElement(“P”)
        1. let t = document.createTextNode(“Paragraph text.”)
        1. p.appendChild(t)
        1. document.body.appendChild(p)
  • 更多关于Network Tab的东西:developer.chrome.com/docs/devtoo…
  • 更多关于Responsive Design的东西:developer.chrome.com/docs/devtoo…

第二篇:How To Add JavaScript to HTML

  • <script>元素标签中可以放置JS代码,取决于你想这些code snippets在什么时候加载,可以分别放在<head>或<body>中
    • 放head中,浏览器在剩余页面加载前运行JS代码
    • 防body中,。。。加载后运行。。。
    • 当然为了分离html和js以及css内容,一般都是放在独立文件中再引入,通过:
      • <link rel="stylesheet" href="css/style.css" />
      • <script src="js/script.js" />

第三篇:How To Write Your First JavaScript Program

  • let name = prompt(“greeting msg”); 可以获取用户的输入,相当于python的input

第六篇:Understanding Data Types in JavaScript

  • JS只有一种数字类型number(无论是整数类型还是浮点类型),所以let num1 = 93和let num2 = 93.00是一样的
  • JS中有正/负无穷(除以零)和NaN(不合法类型,不同于undefined)
  • JS中如果string可以被解析为数字,那么可以进行运算:let y = 20 / “5”
  • JS中object并不是hashMap,只是一系列的键值对,当然实现方式可以是hashMap,object的key只能是string(会在添加kv pair时被强转)

第七篇:How To Work with Strings in JavaScript

  • JS中`xxx ${variable} yyy`可以被用于在字符串中加变量(template literals)
  • String literal vs. String value的区别,前者是源码中的,后者是显示输出
  • 为了使代码更易读,多行的string文本,一般也使用template literal(即``)

第八章:How To Index, Split, and Manipulate Strings in JavaScript

  • String primitives vs. String objects:后者指new String(“ddd”)出来的字符串,用JS中的typeof来查看各自类型的话,会发现前者是string,后者是object;一般情况下都是使用原生string,因为又一些内置的特性更方便
  • JS中String相关的函数:charAt,indexOf,lastIndexOf,slice,toUpperCase,split,trim,replace,toString,includes等内置方法(其中replace中还可以使用正则表达式进行匹配,更多可看regexr.com/)

第九章:How To Convert Data Types in JavaScript

  • JS中可以通过String(),Number(),Boolean()进行强转type coercion

第十章:Understanding Variables, Scope, and Hoisting in JavaScript

  • JS规范:ECMAScript 2015(ES6):262.ecma-international.org/6.0/
  • var, let, const的不同点:
    • Keyword.png
  • JS中的Hoisting(变量提升):
    • 两个结果都是undefined
      •  The code we wrote.png
      • Initialize x in the global scope.png
  • JS中const变量一般都是全大写

第十二章:Understanding Comparison and Logical Operators in JavaScript

  • JS中的==表示相等(equality),但3==‘3’也是真,===表示严格相等(identity),需要包括类型在内也相等

第十三章:Understanding Arrays in JavaScript

  • 跳过index对数组进行赋值:比如0-4位置都有内容,但是现在在6位置赋值,那么5位置就会有一个undefined
  • JS中数组常见的函数:push,unshift,pop,shift,splice,slice,concat,reverse,fill,sort,join,indexOf,lastIndexOf等
    • push, unshift是 尾/前 添加元素,pop, shift是 尾/前 移除元素
    • splice可以最多接收3个参数
    • sort中使用的比较函数cmp可以定义在外边
    • Join的默认delimiter是逗号,并且其中没有空格
  • JS中的数组或string等iterable对象的新遍历方式:
    • for … of,比如 for (let a of arr) {};(另外for (let [index, a] of arr.entries()) {}还可以把下标也带上)
    • forEach + 箭头函数,比如 arr.forEach(a => { doSthWithItem(a) })
    • 函数式编程:map, reduce, filter, find, findIndex…

第十四章:How To Use Array Methods in JavaScript: Mutator Methods

  • 测试一个object是否是Array:Array.isArray(obj)

第十七章:Understanding Objects in JavaScript

  • delete关键字可以删除一个JS中object对象的一个特性property,比如delete obj.prop,如果存在prop,返回true
  • 遍历JS中object特性:for … in,比如 for (key in obj) {}
  • Object.keys(obj)会返回一个对象的key的数组

第十八章:Understanding Date and Time in JavaScript

  • JS中new一个Date类,格式是:周几 月 日 年 时:分:秒 时区;date.getTime()获得一个Unix时间(另外还有getFullYear, getMilliseconds等,另外除了get方法还有set方法);当然new Date的时候也可以传入多参数

第十九章:Understanding Events in JavaScript

  • 给element分配event的三种方式:
    • Inline event handlers(一般不推荐使用)
      • 比如:<button onclick="changeText()">Click me</button>,然后在changeText函数中写上:
      const p = document.querySelector(‘p’);
      p.textContent = “something…”
      
    • Event handler properties(即在JS代码中给元素设置event这一property特性而非在直接在HTML中)
      const button = document.querySelector('button');
      button.onclick = changeText;
      
    • Event listeners(优点:可以在同一个element上设置多个event)
      button.addEventListener('click', changeText);
      
      • 第二个参数可以设置成匿名函数() => {}
      • 另外可以removeEventListener()
  • 常用的事件:
    • 鼠标事件:dblclick, mouseenter, mouseleave, mousemove(其中mousemove指鼠标在元素内部每次移动的时候)
    • 表格事件:submit, focus, blur
    • 键盘事件:keydown, keyup, keypress(第三个指长按),keydown和keypress的区别在于前者会响应每一个key,而后者会忽略不产生字符的key(比如shift, alt, delete键)
      • 键盘事件有特殊的特性可以接入单个key,如果一个参数event被传入一个event listener中,我们就能获得刚发生的event的更多信息。比如在键盘这里,可以获取键的key(e.g. a)和code(e.g. KeyA)两个property),比如:
        document.addEventListener('keydown', event => {
          console.log('key: ' + event.key);
          console.log('code: ' + event.code);
        });
        
    • 另外event的另一个property,target经常被使用,它指向事件的发生者element

第二十章:How To Work with JSON in JavaScript

  • JSON的其他信息:
  • JSON和JS object的区别:
    • JS object中的keys是不放在quotes里面的
    • JS object中可以有function作为value
    • JSON可以被任何编程语言使用,因为它是text-based
  • 处理JSON的函数:JSON.stringify(), JSON.parse()

第二十二章:How To Use the Switch Statement in JavaScript

  • JS中存在switch range,即case中可以写一个区间,比如:case grade >= 90: xxx; break;

第二十五章:How To Define Functions in JavaScript

  • 函数表达式function expression,比如:const sum = function(x, y) {…}
  • 当箭头函数中函数主题只有一句返回语句时,可以简写,比如:const square = x => xx; (原本是 const square = (x) => { return xx; })

第二十六章:Understanding Prototypes and Inheritance in JavaScript

  • JS是基于原型的语言(prototype-based, meaning object properties and methods can be shared through generalised objects that have the ability to be cloned and extended.),意味着它不同于类继承的其他语言,是prototypical inheritance的
  • JS中每一个obj都有一个内部特性[[Prototype]],这个特性无法在代码中被直接使用,需要使用Object.getPrototypeOf方法获取);prototype将两个或者多个object给联系起来
  • 有些浏览器可以通过__proto__来查看当前obj是基于哪一个object的(但是一般还是最好使用getPrototypeOf),比如:
    let y = [];
    // method1
    y.__proto__.__proto__ === Object.prototype;
    // method2
    Array.prototype.isPrototypeOf(y);
    // method3
    y instanceof Array
    
  • 自定义构造函数可以通过new的方式,比如:
    function Hero(name, level) {…}
    let hero1 = new Hero(‘name’, 1)
    // Add method to the Eg prototype
    Hero.prototype.greet = function () {…}
    
  • 使用call方法复制一个构造函数中的所有properties到另一个构造函数中,比如:
    function Warrior(name, level, weapon) {
      Hero.call(this, name, level);
      this.weapon = weapon;
    }
    
    • 但call并不会把prototype properties和methods也都复制过来,需要使用Object.setPrototypeOf(Warrior.prototype, Hero.prototype);来复制
  • 全部代码块:
    // 通过ES6之前默认构造函数的方式
    // Initialize constructor functions
    function Hero(name, level) {
      this.name = name;
      this.level = level;
    }
    
    function Warrior(name, level, weapon) {
      Hero.call(this, name, level);
      this.weapon = weapon;
    }
    
    // Link prototypes and add prototype methods
    Object.setPrototypeOf(Warrior.prototype, Hero.prototype);
    
    Hero.prototype.greet = function () {
      return `${this.name} says hello.`;
    }
    
    Warrior.prototype.attack = function () {
      return `${this.name} attacks with the ${this.weapon}.`;
    }
    
    // Initialize individual character instances
    const hero1 = new Warrior('Bjorn', 1, 'axe');
    hero1.attack();
    hero1.greet();
    
    • JS中的Class语法源自ES6,其实本质上只是一种语法糖,底层仍使用函数
    // 通过ES6新加入的class语法的方式
    // Initializing a class
    class Hero {
      constructor(name, level) {
        this.name = name;
        this.level = level;
      }
      // Adding a method to the constructor
      greet() {
        return `${this.name} says hello.`;
      }
    }
    
    // Creating a new class from the parent
    class Mage extends Hero {
      constructor(name, level, spell) {
        // Chain constructor with super
        super(name, level);
        // Add a new property
        this.spell = spell;
      }
    }
    

第二十七章:Understanding Classes in JavaScript

  • JS中的Class语法源自ES6,其实本质上只是一种语法糖,底层仍使用JS原生的函数作为实现方式

第二十八章:How To Use Object Methods in JavaScript

  • 一些常用的缩写或者技术词汇:www.digitalocean.com/community/t…
  • 常用的内置object methods对象方法:Object.create(), Object.keys(), Object.values(), Object.entries(), Object.assign(), Object.freeze(), Object.seal(), Object.getPrototypeOf(), Object.setPrototypeOf()

第二十九章:Understanding This, Bind, Call, and Apply in JavaScript

  • JS中,this有四种隐式(Implicit Context)指代的东西,区分于应用场景:
    • the global context 全局的上下文
      • 在浏览器中时,全局对象就是window;Node.js中则是global
      • 为了规避很多JS的sloppy问题,比如this的指向问题(作用域),有时可以使用strict mode编写JS代码(即use strict),详见:developer.mozilla.org/en-US/docs/…
    • As a method within an object 作为对象内部的一个方法
      • 在对象内部时,this指向离当前this最近的一层object
    • As a constructor on a function or class 作为一个函数或类的构造器
      • 当使用关键字new进行新对象创建时,this指向新的对象实例
    • As a DOM event handler 作为一个文件对象模型的事件处理器
      • 在添加event监听时,那个this指向当前发生事件的element(即event.currentTargetevent.target
  • JS中,this的显式上下文(Explicit Context),通过call, apply, bind
    • Call和apply除了接受额外参数时,后者使用列表不同外,其他都类似。它们的作用主要是将一个调用函数的this联系到一个给定的上下文,比如:
      const book = {
        title: 'Brave New World',
        author: 'Aldous Huxley',
      }
      
      function summary() {
        console.log(`${this.title} was written by ${this.author}.`)
      }
      
      summary.call(book)
      // or:
      summary.apply(book)
      
    • 不同于call和apply的一次性使用(调用时生效,原函数不变),bind可以用于创建一个与给定context永久绑定的新函数;重新绑定别的context是不行的
      const braveNewWorldSummary = summary.bind(book)
      
      braveNewWorldSummary()
      
    • 箭头函数是没有自己的this绑定的,而是指向箭头函数之外的一层context
      const whoAmI = {
        name: 'Leslie Knope',
        regularFunction: function() {
          console.log(this.name)
        },
        arrowFunction: () => {
          console.log(this.name)
        },
      }
      
      whoAmI.regularFunction() // "Leslie Knope"
      whoAmI.arrowFunction() // undefined
      
      react等框架中箭头函数的常见的用法
      const button = document.createElement('button')
      button.textContent = 'Click me'
      document.body.append(button)
      
      class Display {
        constructor() {
          this.buttonText = 'New text'
      
          // 这里如果是写 function(event) {...},那么里面的this
          // 就是指发生event的element,而用箭头函数的话,this的指
          // 向就是outer context,在这里就是外层的class的context
          button.addEventListener('click', event => {
            event.target.textContent = this.buttonText
          })
        }
      }
      
      new Display()
      

第三十章:Understanding Map and Set Objects in JavaScript

  • JS中Map的建立通过new,Map变量会有set, get, has, delete, clear等函数
  • 可以通过函数Objects.entries()Object.fromEntries()来进行对象object和映射Map的相互转化,比如:
    const map = new Map(Object.entries(obj));
    const obj = Object.fromEntries(map)
    
  • 可以使用Array.from(map)将一个映射对象转化为数组对象
  • Map中key可以不同的语言原始类型primitives,比如map.set(‘1’, ‘String one’)和map.set(1, ‘Number one’)是不同的(Set中是add)
  • 在object中,由于对象中将所有key都转换成了string类型,所以诸如const obj = { 1: ‘One’ },其中obj[1] === obj[‘1’]是返回true的;但是在Map中,object是可以不转化为string直接作为key的
  • 注意当使用object或者array作为key时,Map实际上时使用这些对象的引用reference来作为对比,而非是对象的字面值,比如:{} === {}是返回false的,因为它们并不是同一个对象,所以诸如map.set({}, ‘One’}; map.set({}, ‘Two’)实际上设置了两个pair
  • Map的遍历:
    • Map.prototype.forEach((value, key, map) = () => {})
      • 对比于Array.prototype.forEach((item, index, array) = () => {})
    • map.forEach((value, key) => {…} 注意这个value在前
    • for (let [key, value] of map) {…}

第三十一章:Understanding Generators in JavaScript

  • 生成器函数定义是带星的,比如:function* generatorFunc() {},且该函数会返回一个生成器对象
  • generator function不可以通过new关键字构建,也不可以和arrow function联用
  • 生成器函数返回的迭代器有一个next函数,next函数会返回一个valuedone
  • 用for…of或spread操作符时,只会遍历yield的返回,return不会打印
  • 生成器函数可以通过return和throw方法马上中断,比如:
    • generator.return()
    • generator.throw(new Error())
  • yield* 可以用作更好的组织代码结构
  • generators可以用于代替async/await,但一般还是用async/await吧

第三十三章:Understanding Destructuring, Rest Parameters, and Spread Syntax in JavaScript

  • Spread语法是shallow copy浅拷贝的,嵌套的对象使用spread时只复制引用
  • Spread用于字符串转字符数组很有用,比如:
    const string = ‘hello’;
    const stringArray = […string]; // [“h”, “e”, “l”, “l”, “o”]
    

第三十四章:Understanding Template Literals in JavaScript

  • 创建HTML元素的时候可以使用template interpolation + trim的方式,比如:
    const menuItem = (url, link) =>
    `
    <li>
      <a href="${url}">${link}</a>
    </li>
    `.trim()
    
    menuItem('https://google.com', 'Google')
    
  • taged template literals (i.e. template tags)
    function tag(strings, ...expressions) {
      console.log(strings)
      console.log(expressions)
    }
    
    const string = tag`This is a string with ${true} and ${false} and ${100} interpolated inside.`
    // ["This is a string with ", " and ", " and ", " interpolated inside."
    // [true, false, 100]
    

第三十五章:Understanding Arrow Functions in JavaScript

  • arrow functions do not have their own this binding or prototype and cannot be used as a constructor. 箭头函数没有自己的prototype和binding,不能作为构造器使用
  • Lexical this:箭头函数中的this的值取决于其所处的作用域(即the lexical environment,或者说lexical scope指当一个变量定义在你当前的作用域外部时,可以直接的在你当前所在的作用域里调用而无需作为参数传入)。也是因为这个原因,箭头函数适合用作行参函数,而不适合用作对象object的直接方法method
  • 创建一个对象object是不会定义一个lexical scope的,所以在object内部定义arrow函数作为Method,箭头函数中的this就不会指向当前的object。所以一般都是用传统函数定义作为method
  • 箭头函数的异样语法:
    • 函数体内返回一个object作为返回值时,需要加(),否则{}会被看作是函数体,比如:
    const sum = (a, b) => ({result: a + b})
    sum(1, 2)
    

第三十六章:Understanding the Event Loop, Callbacks, Promises, and Async/Await in JavaScript

  • 浏览器环境下的JS的异步特性的许多概念和后端Node.js的大同小异,可以参考:www.digitalocean.com/community/t…
  • 浏览器环境下使用event loop机制来处理并发,因为JS只能一次执行一行代码,它需要event loop这个机制通过call stack或queue的手段来达到何时执行特定哪一行的代码的要求
  • Queue是在call stack为空的时候被检查的,如果此时Q中有等待的消息,把该条msg加入到stack,然后开始执行,执行完毕后从stack中移出。比如setTimeout(() => {}, 0)这个函数,第二个时间参数的设置其实是指将该条msg放入q中的时间,而非事实的该条msg的执行时间
  • 因为使用callback时的嵌套(本质上是使用setTimeout来达成异步编码)会导致pyramid of doom或者叫callback hell,让代码的维护变得困难,也不利于阅读。因此ES6中引入了promises机制,但是一些开发者更喜欢使用同步的方式去编写异步的代码,所以ES7又引入了async/await机制
  • promise机制
    • promise初始化
    // Initialize a promise
    const promise = new Promise((resolve, reject) => {})
    
    • 一个promise可以有三种可能状态:pending, fulfilled, rejected,后两者表示promise已经被解决
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => resolve('Resolving an asynchronous request!'), 2000)
    })
    
    // Log the result
    promise.then((response) => {
      console.log(response)
    })
    
    • promise还可以被链接起来
    // Chain a promise
    promise
      .then((firstResponse) => {
        // Return a new value for the next then
        return firstResponse + ' And chaining!'
      })
      .then((secondResponse) => {
        console.log(secondResponse)
      })
    
    • 错误处理:
    function getUsers(onSuccess) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // Handle resolve and reject in the asynchronous API
          if (onSuccess) {
            resolve([
              {id: 1, name: 'Jerry'},
              {id: 2, name: 'Elaine'},
              {id: 3, name: 'George'},
            ])
          } else {
            reject('Failed to fetch data!')
          }
        }, 1000)
      })
    }
    
    // then()处理resolve,catch()处理reject
    getUsers(false)
      .then((response) => {
        console.log(response)
      })
      .catch((error) => {
        console.error(error)
      })
    
    • Fetch API with promises
    // Fetch a user from the GitHub API
    fetch('https://api.github.com/users/octocat')
      .then((response) => {
        return response.json()
      })
      .then((data) => {
        console.log(data)
      })
      .catch((error) => {
        console.error(error)
      })
    
  • aync/await机制 + try catch
    // Handle fetch with async/await
    async function getUser() {
      const response = await fetch('https://api.github.com/users/octocat')
      const data = await response.json()
    
      console.log(data)
    }
    
    // Execute async function
    getUser()
    

第三十七章:Understanding Modules and Import and Export Statements in JavaScript

  • Modules和JS普通script脚本的区别:
    • Modules不会往global作用域里添加任何东西
    • Modules总是在strict mode之下的
    • 多次加载同一个Module是无效的,因为Module只加载一次
    • Modules需要在服务器环境下(因为CORS策略)
    <script type="module" src="functions.js"></script>
    <script type="module" src="script.js"></script>