JavaScript基础学习之一
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() // 不报错
脚本调用
尽量不要将JS函数绑定元素写在HTML中,以便于维护。
外部引用JS文件时加上属性
async
(“异步”属性)来解决这一问题,它告知浏览器在遇到<script>
元素时不要中断后续 HTML 内容的加载。例:
<script src="script.js" async></script>
这种情况下,脚本和HTML将一起加载。内部示例:
document.addEventListener("DOMContentLoaded", function(){
...
});
注:“外部”示例中
async
属性可以解决调用顺序问题,因此无需使用DOMContentLoaded
事件。而async
只能用于外部脚本,因此不适用于“内部”示例。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()
- 返回删除的元素
语句块
if...else
switch(){case :...break;}
... ? ... : ...
三元运算符for( ; ; )
continue breakfor ... 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
while(){} / do{}while();
function 函数名(参数名){return ;}
如没有返回值不需要加return语句。匿名函数
function(){}
匿名函数也称为函数表达式。函数表达式与函数声明有一些区别。函数声明会进行声明提升(declaration hoisting),而函数表达式不会。
函数作用域
所有函数的最外层被称为全局作用域。 在全局作用域内定义的值可以在任意地方访问。
函数内定义的变量和其他东西都在它们自己的单独的范围内(函数作用域), 意味着它们不能被函数外的代码访问。调用全局函数时,函数调用与访问变量在同一作用域内。
JavaScript基础学习之一的更多相关文章
- JavaScript 基础学习1-day14
JavaScript 基础学习1 知识预览JavaScript概述二 JavaScript的基础三 JavaScript的对象BOM对象DOM对象实例练习js扩展 JavaScript概述 JavaS ...
- 48.javascript基础学习
javascript基础学习: http://www.w3school.com.cn/jsref/index.asp jS的引入方式: 1.行间事件:为某一个具体的元素标签赋予js内容,oncli ...
- JavaScript 基础学习(二)js 和 html 的结合方式
第一种 使用一个标签 <script type="text/javascript"> js代码; </script> 第二种 使用 script 标签,引入 ...
- JavaScript 基础 学习 (四)
JavaScript 基础 学习 (四) 解绑事件 dom级 事件解绑 元素.on事件类型 = null 因为赋值的关系,所以给事件赋值为 null 的时候 事件触发的时候,就没有事件处理 ...
- JavaScript 基础 学习(三)
JavaScript 基础 学习(三) 事件三要素 1.事件源: 绑定在谁身上的事件(和谁约定好) 2.事件类型: 绑定一个什么事件 3.事件处理函数: 当行为发生的时候,要执行哪一个函数 ...
- JavaScript 基础 学习 (二)
JavaScript 基础 学习 节点属性 每一个节点都有自己的特点 这个节点属性就记录着属于自己节点的特点 1. nodeType(以一个数字来表示这个节点类型) 语法:节点.nodeT ...
- JavaScript 基础 学习 (一)
JavaScript 基础 学习 获取页面中的元素的方法 作用:通过各种方式获取页面中的元素 比如:id,类名,标签名,选择器 的方式来获取元素 伪数组: 长的和数组差不多,也是按照索引排 ...
- 几张非常有意义的JavaScript基础学习思维图
分享几张对于学习JavaScript基础知识非常有意义的图,无论你的JavaScript级别如何,“温故而知新”完全可以从这些图中得到. 推荐理由:归类非常好,非常全面 JavaScript 数组 J ...
- HTML JavaScript 基础学习
HTML 中肯定会用到 JavaScript 的知识点,会点 JavaScript 的基础知识不会吃亏,其实打算去买JavaScript的教程去专门学习一下,但是交给我的时间不多了,记录一点,能会一点 ...
- javascript基础学习--HTML DOM
写在前面的话:由于学校没有开过javascript这门课,所以平时用javascript时都是用到什么就去搜什么样的代码,但是在工作中有时候搜来的代码总是有那么点小问题,而当自己想去修改时,却又无从下 ...
随机推荐
- 关于pytorch一些基础知识的备份
压缩conda环境用于备份目的实际上没有意义,因为还有其他方法可以做到这一点,这可能更合适,并使用专为此而设计的内置功能. 您可以创建一个环境.txt版本conda,详细说明其中的每个模块和版本,然后 ...
- vue store用法
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) 首字母不能大写 export default new Vuex.Store({ ...
- 使用layui时遇到的问题以及解决文章链接
1.斜线表头效果 2.表格嵌套使用 3.layui数据表格跨行自动合并 4.layui表格数据变更的处理方式 5.layer弹窗动态添加KindEditor编辑器 6.layer弹出层自动调节位置 7 ...
- PLSQL REPLACE 函数替换操作
oracle REPLACE 函数是用另外一个值来替代串中的某个值. 例如,可以用一个匹配数字来替代字母的每一次出现. REPLACE 的格式如下: REPLACE ( char, search_st ...
- Path Manipulation安全漏洞处理方法
1 public static String pathManipulation(String path) { 2 HashMap<String, String> map = new Has ...
- EOVS 83开局
目录 公司筹备阶段 第一季 公司筹备阶段 第一季
- mysql5.7主从多线程同步
数据库复制的主要性能问题就是数据延时 为了优化复制性能,Mysql 5.6 引入了 "多线程复制" 这个新功能 但 5.6 中的每个线程只能处理一个数据库,所以如果只有一个数据库, ...
- MySQL 【CAST】函数,类型转换使用
Cast(字段名 as 转换的类型 ),其中类型可以为: 1.CHAR[(N)] 字符型 2.DATE 日期型3.DATETIME 日期和时间型4.DECIMAL float型5.SIGNED int ...
- Python使用requests和requests_toolbelt上传文件
1.requests-toolbelt官方文档:https://pypi.org/project/requests-toolbelt/ 2.环境安装 pip install requests-tool ...
- STM32自学笔记
1位带操作 第一种位带操作 #define BITBAND_REG(Reg,Bit) (*((uint32_t volatile*)(0x42000000u + (((uint32_t)&(R ...