javascript 基础语法教程
javascript 基础语法教程
JavaScript let和var
在JavaScript中,let
和 var
都是用于声明变量的关键字,但它们之间有一些重要的区别。
作用域
var
: 具有函数作用域或全局作用域。在函数内部声明的var
变量在整个函数内部都可见。在全局作用域中声明的var
变量将成为全局对象的属性(在浏览器中是window
对象)。let
: 具有块作用域。在{}
块内声明的let
变量只在该块内可见。不会在外部作用域中泄漏。
function print(){
{
var a=10;
let b=20;
}
console.log(a);
console.log(b);
}
在上面的代码中,变量a能正确输出,但是变量b会输出 ReferenceError: b is not defined
。因为变量a使用 var
声明,在声明后会被提升到函数作用域,在整个函数内部都是可见的。变量b使用 let
声明,因此其作用域为声明变量的 {}
内,所以在后面的函数中输出时会报错。
隐式全局变量
在 JavaScript 中,即使没有显式声明变量,也可以直接赋值给一个变量,这被称为 隐式全局变量 。对于如下代码,执行后能正常输出数字10.
a = 10;
console.log(a); // 输出 10
在js中,当在全局作用域中直接赋值给一个未声明的变量时,JavaScript 引擎会自动在全局对象(在浏览器中是 window
对象)上创建一个属性。
因此,a = 10;
实际上等价于 window.a = 10;
。
变量提升
var
: 会被提升到其作用域的顶部。即使在声明之前使用var
变量也不会报错,但变量的值会是undefined
。let
: 也会被提升,但不会被初始化。在声明之前使用let
变量会导致引用错误(ReferenceError),因为它们处于“暂时性死区”(Temporal Dead Zone, TDZ)。
console.log(a);
var a = 10;
上面的代码能正常执行,但是打印结果为 undefined
。因为在执行时,变量a会被提升到作用域顶部,此时作用域内存在变量a的定义,但是变量提升只会提升变量定义,不提升变量赋值,因此最后变量a的值为 undefined
。上面的代码等价于:
var a;
console.log(a);
a = 10;
将上面的定义方式修改为 let
之后,会出现 ReferenceError: Cannot access 'a' before initialization 。let变量同样存在变量提升,但它们会在声明之前处于一个“暂时性死区”,在这个区域内访问变量会导致引用错误。
重复声明
var
: 允许在同一作用域内多次声明同一个变量。
var x = 10;
var x = 20; // 不会报错,但会覆盖之前的值
let
: 不允许在同一作用域内多次声明同一个变量。
let y = 10;
let y = 20; // 报错:Identifier 'y' has already been declared
JavaScript null和undefined
在JavaScript中,undefined
和 null
都表示“无”或“空”的概念,但它们在语义和用途上有明显的区别。
- undefined
- 通常用于表示一个变量已被声明但尚未赋值。
- 函数没有返回值时,默认返回
undefined
。 - 对象属性或数组元素不存在时,默认值为
undefined
。
- null
- 通常用于表示一个有意的空值或对象的缺失。
- 用于清空对象引用,表示对象不再需要。
简单地说,undefined
表示一个对象已经被定义,但是在使用时还没有为这个对象赋值。null
表示对象已经完成了定义和赋值,只是对象的值为空。
JavaScript 字符串模板
JavaScript 中的模板字符串是一种方便的字符串语法,允许你在字符串中嵌入表达式和变量。其基本语法是使用一组
定义一个字符串,在其中可以使用特定格式插入变量或函数。同时,字符串模板中可以出现单引号和双引号,并且不需要转义,但是对于其中出现的
则需要使用 \
进行转义
语法
// 基本用法
let text1 = `Hello RUNOOB!`;
// 转义字符
let text2 = `Hello\` RUNOOB!`;
// 无需转义
let text3 = `Hello "RUNOOB" '!'`;
// 模板字符串
let name = "zhangsan";
let info = `name: ${name}`;
// 函数
function sum(a, b) {
return a + b;
}
let result = `1+2=${sum(1, 2)}`;
// 多行文本
const multiLineText = `
This is
a multi-line
text.
`;
JavaScript this关键字
面向对象语言中 this 表示当前对象的一个引用。但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
- 在方法中,this 表示该方法所属的对象。
let person = {
name: 'John',
age: 30,
city: 'New York',
print: function () {
console.log(`Name: ${this.name}, Age: ${this.age}, City: ${this.city}`);
}
}
person.print();
Name: John, Age: 30, City: New York
在方法中,如果使用箭头函数定义方法,则方法中this指向的是定义 person 对象时的外层作用域,通常是全局对象。在浏览器中,这个对象通常是window。
如果要在对象中使用箭头函数定义方法,且方法中this指向对象中的属性,则可以使用闭包实现。
let person = {
name: 'John',
age: 30,
city: 'New York',
print: function () {
console.log(`Name: ${this.name}, Age: ${this.age}, City: ${this.city}`);
},
print2: () => {
console.log(`Name: ${this.name}, Age: ${this.age}, City: ${this.city}`);
},
print3: function () {
const self = this;
return () => {
console.log(`Name: ${self.name}, Age: ${self.age}, City: ${self.city}`);
}
}
}
person.print();
person.print2();
person.print3()();
输出结果:
Name: John, Age: 30, City: New York
Name: undefined, Age: undefined, City: undefined
Name: John, Age: 30, City: New York
- 如果单独使用,this 表示全局对象。
- 在函数中,this 表示全局对象。
// 直接声明变量,会绑定到全局作用域
name = 'John';
age = 30;
city = 'New York';
function print() {
console.log(`Name: ${this.name}, Age: ${this.age}, City: ${this.city}`);
}
print();
- 在函数中,在严格模式下,this 是未定义的(undefined)。
- 在事件中,this 表示接收事件的元素。
- 类似 call() 和 apply() 方法可以将 this 引用到任何对象。
let person = {
name: 'John',
age: 30,
city: 'New York',
print: function () {
console.log(`Name: ${this.name}, Age: ${this.age}, City: ${this.city}`);
}
}
let person2 = {
name: 'zhangsan',
age: 10,
city: 'bj',
}
person.print.call(person2);
JavaScript call()和apply()
在JavaScript中,call 和 apply 方法都用于调用函数,并且可以指定函数内部的 this 值。这两个方法的主要区别在于传递参数的方式不同。
call()
- 作用: call调用一个函数时,可以指定函数内部的this并向函数中传递参数。其中,参数以单个的形式传递到函数中
- 语法: myFunction.call(otherThis, "arg1", "arg2", ...)
apply()
- 作用: apply调用一个函数时,同样可以指定函数内部的this并向函数中传递参数,和call调用的区别在于,这里的参数是以数组的形式传递的。
- 语法: myFunction.apply(otherThis, ["arg1", "arg2", ...])
let person = {
name: 'John',
print: function (age, city) {
console.log(`Name: ${this.name}, Age: ${age}, City: ${city}`);
}
}
let person2 = {
name: 'zhangsan',
}
person.print.call(person2, );
person.print.apply(person2, [40, 'beijing']);
JavaScript 异步编程
setTimeout 函数
setTimeout()
函数接收两个参数:一个回调函数 callback
和一个延迟执行时间 delay
。其作用为,在触发 setTimeout()
函数之后,在经过 delay
毫秒之后将 callback
函数放到事件队列中,等待事件循环调用该函数。
function print() {
console.log("print function");
}
function myFunction() {
setTimeout(print, 3000);
dosmething() // 耗时 5000ms
console.log("hello world");
}
myFunction();
假设存在如上代码,这里实际打印结果为 hello world
- print function
。程序执行到setTimeout之后,会等待3000ms延时,之后将 print
函数放到事件队列中等待执行,而在执行setTimeout的同时,主线程不会等待延时事件之后执行,而是立即执行 myFunction
函数后面的代码。