JavaScript
Dionysen

📒 JavaScript学习笔记

基础概念

与HTML的交互

  • 可以在 HTML 文档中放入不限数量的脚本。

  • 脚本可位于 HTML 的<body><head> 部分中,或者同时存在于两个部分中。

  • 通常的做法是把函数放入<head>部分中,或者放在页面底部。这样就可以把它们安置到同一处位置,不会干扰页面的内容。

第一个程序

<body>
<h1>我的第一段 JavaScript</h1>
<p id="demo">
JavaScript 能改变 HTML 元素的内容。
</p>
<script>
document.write("<h1>TITLE</h1>");
function myFunction() {
x = document.getElementById("demo"); // 找到元素
x.innerHTML = "Hello JavaScript!"; // 改变内容
}
</script>
<button type="button" onclick="myFunction()">点击这里</button>
</body>
  • HTML 输出流中使用 document.write,相当于添加在原有html代码中添加一串html代码。而如果在文档加载后使用(如使用函数),会覆盖整个文档。

使用函数来执行document.write代码如下:

<script>
function myfunction(){
document.write("使用函数来执行document.write,即在文档加载后再执行这个操作,会实现文档覆盖");
}
document.write("<h1>这是一个标题</h1>");
document.write("<p>这是一个段落。</p>");
</script>
<p>
您只能在 HTML 输出流中使用 <strong>document.write</strong>
如果您在文档已加载后使用它(比如在函数中),会覆盖整个文档。
</p>
<button type="button" onclick="myfunction()">点击这里</button>

引入外部js文件

<!DOCTYPE html>
<html>
<body>
<script src="myScript.js"></script>
</body>
</html>

外部 javascript 文件不使用 <script> 标签,直接写 javascript 代码。

简单学习

数字、字符、操作符

  • 分号可以省略,但特殊情况会引起错误

  • Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double),有52位表示尾数,可以精确到9x10^15的整数

// 有三种非数字的数字类型
Infinity; // 1/0 的结果
-Infinity; // -1/0 的结果
NaN; // 0/0 的结果
  • 单引号或双引号构建字符串,字符串用+拼接,字符串也可以用<>号来比较

  • 使用==比较时会进行类型转换,'5'==5返回truenull==undefined返回true;但如果用===则不会转换类型,上述两种会返回false

  • 不同类型的变量相加会导致奇怪的行为:

    13 + !0; //14
    "13" + !0; // '13true'
  • charAt(int num)可以得到字符串中位于num的字符

  • substring(int startPos, int length)可以得到从startPos开始的length长度的子串,

  • length是一个属性,不要用()"hello".lenght

// 还有两个特殊的值:`null`和`undefined`
null; // 用来表示刻意设置的空值
undefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值
// false, null, undefined, NaN, 0 和 "" 都是假的;其他的都视作逻辑真
// 注意 0 是逻辑假而 "0"是逻辑真,尽管 0 == "0"。

变量、数组、对象

  • 变量声明用var,无需指定类型,不加var表示全局变量,未初始化且未被赋值的变量为undefined

  • 变量的计算没有别的特点(简写,自增自减)

  • 数组可以是任意类型的有序列表var myArray = ["Hello", 45, true];

  • 数组可以下标访问;数组长度可变,push(<\element>)

// javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。
var myObj = {key1: "Hello", key2: "World"};
  • 键值对,键是字符串,如何键本身是合法的js标识符,则可以不加引号;值可以是任意类型
  • 对象属性的访问可以通过下标,myObj["my other key"]; // = 4,也可以用myObj.myKey;
  • 对象是可变的,更改值,增加键,访问未定义的值,返回undefined

逻辑与控制结构

  • if、while、for与c无差别
// && 和 || 是“短路”语句,它在设定初始化值时特别有用 
var name = otherName || "default";
// `switch`语句使用`===`检查相等性。
// 在每一个case结束时使用 'break'
// 否则其后的case语句也将被执行。
grade = 'B';
switch (grade) {
case 'A':
console.log("Great job");
break;
case 'B':
console.log("OK job");
break;
case 'C':
console.log("You can do better");
break;
default:
console.log("Oy vey");
break;
}

函数、作用域、闭包

// JavaScript 函数由`function`关键字定义
function myFunction(thing){
return thing.toUpperCase();
}
myFunction("foo"); // = "FOO"
  • 被返回的值必须开始用return关键字的那一行,否则由于分号的自动补齐,会返回undefined
// 在使用Allman风格的时候要注意.
function myFunction()
{
return // <- 分号自动插在这里
{
thisIsAn: 'object literal'
}
}
myFunction(); // = undefined
  • 函数是一等对象,也可以赋值给一个变量,并且可以作为参数传递
// 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中
setTimeout(function(){
// 这段代码将在5秒钟后被调用
}, 5000);
  • 函数有自己的作用域,而其他代码没有

    if (true){
    var i = 5;
    }
    i; // = 5 - 并非我们在其他语言中所期望得到的undefined

    // 这就导致了人们经常使用的“立即执行匿名函数”的模式,
    // 这样可以避免一些临时变量扩散到全局作用域去。
    (function(){
    var temporary = 5;
    // 我们可以访问修改全局对象("global object")来访问全局作用域,
    // 在web浏览器中是`window`这个对象。
    // 在其他环境如Node.js中这个对象的名字可能会不同。
    window.permanent = 10;
    })();
    temporary; // 抛出引用异常ReferenceError
    permanent; // = 10
  • 闭包: 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权,即使在外部函数结束之后。

    function sayHelloInFiveSeconds(name){
    var prompt = "Hello, " + name + "!";
    // 内部函数默认是放在局部作用域的,
    // 就像是用`var`声明的。
    function inner(){
    alert(prompt);
    }
    setTimeout(inner, 5000);
    // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出,
    // 而 setTimeout 会在后面调用inner
    // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的,
    // 所以inner在其最终被调用时仍然能够访问`prompt`变量。
    }
    sayHelloInFiveSeconds("Adam"); // 会在5秒后弹出 "Hello, Adam!"

对象、构造函数和原型

  • 对象中可以有成员函数,用.调用,this指针仍然有效
// 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。
// 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。
var myFunc = myObj.myFunc;
myFunc(); // = undefined
  • 可以在对象的定义之外定义一个函数,然后将函数指定为一个对象的函数:

    var myOtherFunc = function(){
    return this.myString.toUpperCase();
    }
    // myObj.myString == "hello world!";
    myObj.myOtherFunc = myOtherFunc;
    myObj.myOtherFunc(); // = "HELLO WORLD!"
// 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。
var anotherFunc = function(s){
return this.myString + s;
}
anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!"

// `apply`函数几乎完全一样,只是要求一个array来传递参数列表。
anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!"

// 当一个函数接受一系列参数,而你想传入一个array时特别有用。
Math.min(42, 6, 27); // = 6
Math.min([42, 6, 27]); // = NaN (uh-oh!)
Math.min.apply(Math, [42, 6, 27]); // = 6

// 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。
var boundFunc = anotherFunc.bind(myObj);
boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!"
// `bind` 也可以用来部分应用一个函数(柯里化)。
var product = function(a, b){ return a * b; }
var doubler = product.bind(this, 2);
doubler(8); // = 16
  • 构造函数:调用一个函数时前加上new关键字,会创建一个对象,这个函数一般是设计专门用来构造此对象的函数;此函数可以用this来访问对象

  • 原型:其实就是类的继承

    • 指定原型创建对象有两个方法
    // 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的,
    // 因此并不是所有的JS实现都有这个方法
    var myObj = Object.create(myPrototype);
    myObj.meaningOfLife; // = 43

    // 第二种方式可以在任意版本中使用,不过必须通过构造函数。
    // 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反,
    // 是通过构造函数和new关键字创建的新对象的原型。
    MyConstructor.prototype = {
    myNumber: 5,
    getMyNumber: function(){
    return this.myNumber;
    }
    };
    var myNewObj2 = new MyConstructor();
    myNewObj2.getMyNumber(); // = 5
    myNewObj2.myNumber = 6
    myNewObj2.getMyNumber(); // = 6
    // 字符串和数字等内置类型也有通过构造函数来创建的包装类型
    var myNumber = 12;
    var myNumberObj = new Number(12);
    myNumber == myNumberObj; // = true

    // 但是它们并非严格等价
    typeof myNumber; // = 'number'
    typeof myNumberObj; // = 'object'
    myNumber === myNumberObj; // = false
    if (0){
    // 这段代码不会执行,因为0代表假
    }
// 不过,包装类型和内置类型共享一个原型,
// 所以你实际可以给内置类型也增加一些功能,例如对string:
String.prototype.firstCharacter = function(){
return this.charAt(0);
}
"abc".firstCharacter(); // = "a"

// 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性,
// 这样就可以在老的浏览器中使用新功能了。

// 比如,我们知道Object.create并没有在所有的版本中都实现,
// 但是我们仍然可以通过“代码填充”来实现兼容:
if (Object.create === undefined){ // 如果存在则不覆盖
Object.create = function(proto){
// 用正确的原型来创建一个临时构造函数
var Constructor = function(){};
Constructor.prototype = proto;
// 之后用它来创建一个新的对象
return new Constructor();
}
}

更多概念

ansyc与await

async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个语法错误。

显示评论