let和var之间的区别

作用域不同

let仅在块级作用域内有效,而var全局有效。

例:

var a = []
for(var i=0; i<10; i++){
a[i] = function(){
console.log(i);
}
}
a[6]()

如果是var,上述输出10,如果是let则输出6.

JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。

例2 let配合for循环的独特应用:

for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
// 输出结果
10 共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等 // i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9

补充:const定义块级作用域的变量,类似let,不能被重新声明,也无法重新赋值。

变量提升

var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。

由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫做“hoisting”。“hoisting”就像是把所有的变量声明移动到函数或者全局代码的开头位置

let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

例1:

// var 的情况
console.log(foo); // 输出undefined
var foo = 2; // let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

例2:

var x = y, y = 'A';
console.log(x + y); // undefinedA

相当于把x,y的声明提到前面,而赋值还是按原来的顺序。

例3:

var x = 0;

function f(){
var x = y = 1; // x在函数内部声明,y不是!
}
f(); console.log(x, y); // 0, 1
// x 是全局变量。
// y 是隐式声明的全局变量。

例4:

var x = 0;  // x是全局变量,并且赋值为0。

console.log(typeof z); // undefined,因为z还不存在。

function a() { // 当a被调用时,
var y = 2; // y被声明成函数a作用域的变量,然后赋值成2。 console.log(x, y); // 0 2 function b() { // 当b被调用时,
x = 3; // 全局变量x被赋值为3,不生成全局变量。
y = 4; // 已存在的外部函数的y变量被赋值为4,不生成新的全局变量。
z = 5; // 创建新的全局变量z,并且给z赋值为5。
} // (在严格模式下(strict mode)抛出ReferenceError) b(); // 调用b时创建了全局变量z。
console.log(x, y, z); // 3 4 5
} a(); // 调用a时同时调用了b。
console.log(x, z); // 3 5
console.log(typeof y); // undefined,因为y是a函数的本地(local)变量。

暂时性死区(temporal dead zone,简称 TDZ)

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

当某区块中存在let定义变量,则在此区域中,该变量定义之前都不能被使用(也不能使用Typeof),即使区块外存在var同名变量。

例:

var tmp = 123;
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError typeof tmp; // ReferenceError
typeof undeclared_variable; // undefined let tmp = tmp; // 报错
let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 345;
console.log(tmp); // 345
}

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

相同作用域下的重复声明

var变量可以重复声明,其值为最后一次修改的值。let变量不能重复声明。

function func(arg) {
let arg;
}
func() // 报错 function func(arg) {
{
let arg;
}
}
func() // 不报错

脚本调用

  1. 尽量不要将JS函数绑定元素写在HTML中,以便于维护。

  2. 外部引用JS文件时加上属性async(“异步”属性)来解决这一问题,它告知浏览器在遇到 <script> 元素时不要中断后续 HTML 内容的加载。

    例:<script src="script.js" async></script> 这种情况下,脚本和HTML将一起加载。

    内部示例:

    document.addEventListener("DOMContentLoaded", function(){
    ...
    });

    :“外部”示例中 async 属性可以解决调用顺序问题,因此无需使用 DOMContentLoaded 事件。而 async 只能用于外部脚本,因此不适用于“内部”示例。

  3. defer控制脚本的运行顺序,添加 defer 属性的脚本将按照在页面中出现的顺序加载。

    当有ABC3个脚本需要运行,而BC依赖于A时,可以使用defer让BC运行次序在A之后。

    例:

    <script defer src="js/vendor/jquery.js"></script>
    <script defer src="js/script2.js"></script>
    <script defer src="js/script3.js"></script>

数据类型

Number(不管是整数还是浮点数都是同一种数据类型)\String\Boolean(小写)\Array(中括号)

Boolean

任何不是 false, undefined, null, 0, NaN 的值,或一个空字符串('')在作为条件语句进行测试时实际返回true,因此您可以简单地使用变量名称来测试它是否为真,甚至是否存在(即它不是未定义的)

Object

//定义
let dog = {name:'Spot', breed:'Dalmatian', age:8};
//访问
dog.name

判断某变量是什么数据类型可用typeof

Note: 使用==!=来判断相等和不相等是有效的,但它们与===/!==不同,前者测试是否相同, 但是数据类型*可能不同,而后者的严格版本测试值和数据类型是否相同。

对象

对象 {name : value}

一个对象由许多的成员组成,每一个成员都拥有name和value。每一个名字/值(name/value)对被逗号分隔开,并且名字和值之间由冒号(:)隔开。

点表示法:对象名.属性名或方法名

括号表示法:对象名['属性名或方法名']

var person = {
name : ['Bob', 'Smith'],
age : 32,
gender : 'male',
interests : ['music', 'skiing'],
bio : function() {
alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
},
greeting: function() {
alert('Hi! I\'m ' + this.name[0] + '.');
}
}; //点表示法
person.name[0]
person.age
person.interests[1]
person.bio()
person.greeting()
//括号表示法
person['age']

当在成员函数中引用属性时可以通过 this.属性名 来得到属性值。

构造函数

通常以大写字母开头以区分普通函数。

function Person(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
}

调用

var person1 = new Person('Bob');

也可以使用Object()创建:

//先创建空对象再赋值
var person1 = new Object();
person1.name = 'Chris';
person1['age'] = 38;
person1.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
}
//将参数传给Object
var person1 = new Object({
name : 'Chris',
age : 38,
greeting : function() {
alert('Hi! I\'m ' + this.name + '.');
}
});

基于现有对象创建新对象 Object.create()

var person2 = Object.create(person1);

对象原型和继承的部分先暂时跳过,等需要用到时再做补充。

字符串和数组之间的转换

以逗号分隔的字符串为例:

//字符串转数组
//1 - split
let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
let myArray = myData.split(',');
console.log(myArray);
//2 - toString
let dogNames = ["Rocket","Flash","Bella","Slugger"];
console.log(dogNames.toString()); //Rocket,Flash,Bella,Slugger //数组转字符串 - join
let myNewString = myArray.join(',');
console.log(myNewString);

从结尾操作:

数组添加元素 push() - 返回数组的新长度

数组删除元素 pop() - 返回删除的元素

从开始操作:

数组添加元素 unshift() - 返回数组的新长度

数组删除元素 shift() - 返回删除的元素

语句块

  1. if...else

  2. switch(){case :...break;}

  3. ... ? ... : ... 三元运算符

  4. for( ; ; ) continue break

    for ... in 迭代数组元素及自定义属性

    for ... of 循环可迭代对象(包括Array、Map、Set、arguments 等等)

    let arr = [3, 5, 7];
    arr.foo = "hello"; for (let i in arr) {
    console.log(i); // 输出 "0", "1", "2", "foo"
    } for (let i of arr) {
    console.log(i); // 输出 "3", "5", "7"
    }

    foreach 语法:arr.forEach(callback(currentValue [, index [, array]])[, thisArg])

    forEach() 方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。

    将for循环转换成foreach:

    const items = ['item1', 'item2', 'item3'];
    const copy = []; // before
    for (let i=0; i<items.length; i++) {
    copy.push(items[i]);
    } // after
    items.forEach(function(item){
    copy.push(item);
    });

    如果数组在迭代时被修改了,则其他元素会被跳过。比如删除了一个元素,则后续元素向前移,跳过一个元素。

    var words = ['one', 'two', 'three', 'four'];
    words.forEach(function(word) {
    console.log(word);
    if (word === 'two') {
    words.shift();
    }
    });
    // one
    // two
    // four
    //跳过了three
  5. while(){} / do{}while();

  6. function 函数名(参数名){return ;} 如没有返回值不需要加return语句。

    匿名函数 function(){}

    匿名函数也称为函数表达式。函数表达式与函数声明有一些区别。函数声明会进行声明提升(declaration hoisting),而函数表达式不会。

    函数作用域

    所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。

    函数内定义的变量和其他东西都在它们自己的单独的范围内(函数作用域), 意味着它们不能被函数外的代码访问。调用全局函数时,函数调用与访问变量在同一作用域内。

JavaScript基础学习之一的更多相关文章

  1. JavaScript 基础学习1-day14

    JavaScript 基础学习1 知识预览JavaScript概述二 JavaScript的基础三 JavaScript的对象BOM对象DOM对象实例练习js扩展 JavaScript概述 JavaS ...

  2. 48.javascript基础学习

    javascript基础学习:   http://www.w3school.com.cn/jsref/index.asp jS的引入方式: 1.行间事件:为某一个具体的元素标签赋予js内容,oncli ...

  3. JavaScript 基础学习(二)js 和 html 的结合方式

    第一种 使用一个标签 <script type="text/javascript"> js代码; </script> 第二种 使用 script 标签,引入 ...

  4. JavaScript 基础 学习 (四)

    JavaScript 基础 学习 (四) 解绑事件 dom级 事件解绑 ​ 元素.on事件类型 = null ​ 因为赋值的关系,所以给事件赋值为 null 的时候 ​ 事件触发的时候,就没有事件处理 ...

  5. JavaScript 基础 学习(三)

    JavaScript 基础 学习(三) 事件三要素 ​ 1.事件源: 绑定在谁身上的事件(和谁约定好) ​ 2.事件类型: 绑定一个什么事件 ​ 3.事件处理函数: 当行为发生的时候,要执行哪一个函数 ...

  6. JavaScript 基础 学习 (二)

    JavaScript 基础 学习 节点属性 ​ 每一个节点都有自己的特点 ​ 这个节点属性就记录着属于自己节点的特点 1. nodeType(以一个数字来表示这个节点类型) ​ 语法:节点.nodeT ...

  7. JavaScript 基础 学习 (一)

    JavaScript 基础 学习 获取页面中的元素的方法 作用:通过各种方式获取页面中的元素 ​ 比如:id,类名,标签名,选择器 的方式来获取元素 ​ 伪数组: ​ 长的和数组差不多,也是按照索引排 ...

  8. 几张非常有意义的JavaScript基础学习思维图

    分享几张对于学习JavaScript基础知识非常有意义的图,无论你的JavaScript级别如何,“温故而知新”完全可以从这些图中得到. 推荐理由:归类非常好,非常全面 JavaScript 数组 J ...

  9. HTML JavaScript 基础学习

    HTML 中肯定会用到 JavaScript 的知识点,会点 JavaScript 的基础知识不会吃亏,其实打算去买JavaScript的教程去专门学习一下,但是交给我的时间不多了,记录一点,能会一点 ...

  10. javascript基础学习--HTML DOM

    写在前面的话:由于学校没有开过javascript这门课,所以平时用javascript时都是用到什么就去搜什么样的代码,但是在工作中有时候搜来的代码总是有那么点小问题,而当自己想去修改时,却又无从下 ...

随机推荐

  1. 关于pytorch一些基础知识的备份

    压缩conda环境用于备份目的实际上没有意义,因为还有其他方法可以做到这一点,这可能更合适,并使用专为此而设计的内置功能. 您可以创建一个环境.txt版本conda,详细说明其中的每个模块和版本,然后 ...

  2. vue store用法

    import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) 首字母不能大写 export default new Vuex.Store({ ...

  3. 使用layui时遇到的问题以及解决文章链接

    1.斜线表头效果 2.表格嵌套使用 3.layui数据表格跨行自动合并 4.layui表格数据变更的处理方式 5.layer弹窗动态添加KindEditor编辑器 6.layer弹出层自动调节位置 7 ...

  4. PLSQL REPLACE 函数替换操作

    oracle REPLACE 函数是用另外一个值来替代串中的某个值. 例如,可以用一个匹配数字来替代字母的每一次出现. REPLACE 的格式如下: REPLACE ( char, search_st ...

  5. Path Manipulation安全漏洞处理方法

    1 public static String pathManipulation(String path) { 2 HashMap<String, String> map = new Has ...

  6. EOVS 83开局

    目录 公司筹备阶段 第一季 公司筹备阶段 第一季

  7. mysql5.7主从多线程同步

    数据库复制的主要性能问题就是数据延时 为了优化复制性能,Mysql 5.6 引入了 "多线程复制" 这个新功能 但 5.6 中的每个线程只能处理一个数据库,所以如果只有一个数据库, ...

  8. MySQL 【CAST】函数,类型转换使用

    Cast(字段名 as 转换的类型 ),其中类型可以为: 1.CHAR[(N)] 字符型 2.DATE 日期型3.DATETIME 日期和时间型4.DECIMAL float型5.SIGNED int ...

  9. Python使用requests和requests_toolbelt上传文件

    1.requests-toolbelt官方文档:https://pypi.org/project/requests-toolbelt/ 2.环境安装 pip install requests-tool ...

  10. STM32自学笔记

    1位带操作 第一种位带操作 #define BITBAND_REG(Reg,Bit) (*((uint32_t volatile*)(0x42000000u + (((uint32_t)&(R ...