js基础语法
html中使用javascript
将js插入html主要是用<script>
元素,这个元素有八个属性
- async: 表示应该立即下载脚本,但是不阻止其它页面动作(如加载页面,加载其他脚本等),只对外部脚本有效.async标记的脚本之间没有前后顺序关系。
- charset: 指定字符集,但是很少用
- crossorigin: 配置相关请求的CORS(跨源资源共享)设置。
crossorigin="anonymous"
表示配置文件请求不必设置凭据标识,而use-credentials表示出站请求会包含凭据 - defer: 表示文档解析和显示完成后再执行脚本也是可以的,即推迟执行。有时候会在DOMContentLoaded事件之前执行(此时已经解析完
</html>
了),并且推迟执行的脚本也会按顺序执行。但是都不是绝对的。 - integrity: 允许比对接收到的资源和指定的加密签名来验证子资源完整性
- src: 表示包含的外部文件地址
- type: 这个值始终是”text/javascript”
使用script时,一般把<script>
元素放在<head>
标签内,但是他会在文档载入前解析,如果解析很慢就会感觉载入时间很长。
插入脚本的方式有:
- 直接在html中插入
例如需要注意在代码块中不能使用<script>
function hello()
{
console.log("Hello");
}
</script></script>
即使时在log中用引号包围也不行,想要使用必须是<\/script>
- 外部引入
使用方法为<script src="example.js"></script>
.解释外部script时和解释行内script一样,也会阻塞。 - 使用js语句加载这种方式加载的script自带async属性。但是这种加载方式对浏览器预加载器是不可见的,这会严重影响它在资源队列中的优先级。如果想让预加载器知道这些动态请求文件的存在,可以显式声明。例如:
let script = document.createElement('script');
script.src = 'gibberish.js';
document.head.appendChild(script);<link rel="preload" href="gibberish.js">
语法
基础语法和c语言类似,并且变量命名添加了$
.并且操作符语法和python类似
变量
var
变量和c语言有很大不同。在c语言中,变量有int,long,short,char等类型。但是在js中并不区分这些类型,而统一使用var代替,他和python一样都是弱类型语言。
例如:var message = "hi";
message = 100;//合法,但不推荐
var表示的就是一个变量,它并不会随着赋值而将类型确定。
此外var声明时会自动提升到函数的顶部,例如:function foo()
{
console.log(age);
var age = 26;
}
这个可以运行,他相当于
function foo()
{
var age;
console.log(age);
age = 26;
}
let
let和var都是声明变量,不同在于let只作用于某个块,而var作用于整个函数,例如:if(true)
{
var name = 'a';
console.log(name);
}
console.log(name);//输出a
if(true)
{
let age = 26;
console.log(26);
}
console.log(age);//出错
也就是说,let与c语言中的局部变量类似。
此外let不允许在同一个块中出现两次声明,例如:var name;
var name;//允许
let age;
let age;//出错
如果不在同一个作用域中就没有问题了
let age = 30;
console.log(age);
if(true)
{
let age = 26;
console.log(age);//26
}
console.log(age);//30
这里和c语言还有点不一样,外层变量可以传递到里层,而里层变量对外层没有任何影响
let age = 30;
console.log(age);//30
if(true)
{
age = 26;
console.log(age);//26
}
console.log(age);//30
此外,let和var声明的其实是相同类型的变量,只是作用域不同,因此这两个的变量名不能相同var name;
let name;//错误
并且let声明的变量不会再作用域中提升,并且不能使用let进行全局声明var name = 'a';
console.log(window.name);//'a'
let age = 26;
console.log(window.age);//undefined
条件声明
因为let作用于块作用域,所以无法检测前面是否使用了同名变量,但是由于var会自动提升变量,所以它可以在首部合并为一个声明,例如:<script>
var name = 'a';
let age = 26;
</script>
<script>
var name = 'b';
let age = 20;//出错,前面已经声明过
let经常用于for循环中
在let出现之前,使用var进行循环变量定义有时候会出现问题
for(var i=0; i<5; i++) |
const
const和let基本相同,但是它在声明时必须同时初始化变量,并且禁止修改const声明的变量,否则会报错。
但是const声明限制只适用于变量的引用。也就是说,如果修改一个对象内部变量,它是管不了的
const person = {}; |
数据类型
我们可以使用typeof操作符来查看数据类型,typeof会返回这些类型
- undefined: 表示值未定义.也就是var或let声明但没有初始化时的值
- boolean:
- string: 可以通过num.tostring()转换为字符串.可以使用单引号(‘), 双引号(“),反引号(`)表示。其中反引号可以跨行定义字符串,跨行字符串会保留反引号内部的空格
- number: 数值,可以表示整型和浮点型,并且表示范围几乎无穷大
- object: 表示值是对象或null(null表示空对象,但是null == undefined会返回true)。我们还可以使用
instanceof
来具体判断是哪种对象 - function:
- symbol: 表示值是符号
let message = "string"; |
字符串插值与模板字面量
他和linux中echo的用法类似,使用${}
将一个其他类型的值转换成字符串并插入某一个字符串中
let value = 5; |
此外,模板也可以插入之前的值let value = '';
function append()
{
value = `${value}abc`;
console.log(value);
}
append();//abc
append();//abcabc
append();//abcabcabc
此外,我们使用模板自变量传参时还可以让他每个插入当成一个参数let a = 6
let b = 9
function simpleTag(strings, aValExpression, b, sum)
{
console.log(strings);
console.log(aValExpression);
console.log(b);
console.log(sum);
return 'foobar';
}
let result = `${a} + ${b} = ${a+b}`;
let tag_result = simpleTag`${a} + ${b} = ${a+b}`;
/*
输出
[ '', ' + ', ' = ', '' ]
6
9
15
*/
console.log(result);//6 + 9 = 15
console.log(tag_result);//foobar
我们可以使用String.raw标签函数来获取原始的模板字面量内容console.log(`first line\nsecond line`);
//first line
//second line
console.log(String.raw`first line\nsecond line`);
//first line\nsecond line
但是对于实际的换行符不会转义
console.log(String.raw`first line
second line`);
//first line
//second line
Symbol
符号是原始值,并且符号实例是唯一且不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
定义: 使用Symbol()函数初始化
let fooSymbol = Symbol('foo'); |
可以通过Symbol.for()创建全局符号let symbol = Symbol.for('foo');
console.log(typeof(symbol));//symbol
这个函数会将符号添加到全局符号表中,如果没有那么它会创建这个符号,如果有将会直接引用
并且全局符号和局部符号不等同let local_symbol = Symbol('foo');
let global_symbol = Symbol.for('foo');
console.log(local_symbol == global_symbol);//false
可以使用Symbol.keyFor()
查询全局符号.例如Symbol.keyFor(123);
Symbol的作用就是标识属性,下面来看一下它的使用场景let Person =
{
name: 'a'
};
let People =
{
name: 'b'
};
let target = {};
Object.assign(target, Person, People);
console.log(target);//{ name: 'b' }a的name消失了
//使用Symbol
let Person =
{
[Symbol('name')]: 'a'
};
let People =
{
[Symbol('name')]: 'b'
};
let target = {};
Object.assign(target, Person, People);
console.log(target);//{ [Symbol(name)]: 'a', [Symbol(name)]: 'b' }
这样合并时就可以保存两个对象的同名属性了,因为Symbol之间必定不相同,所以不会冲突
循环和with语句
基础的循环语句和c语言相同,
for-in
for-in是一种严格的迭代语句,用于枚举对象中非符号键属性(遍历一个对象中的属性)
语法: for(property in expression)
for (const propName in window) |
这里使用for-in遍历了window的所有属性,这里的const不是必须的,但是为了保证局部变量不被修改,推荐使用const
对象的属性是无序的,所以多次遍历可能每次结果都不同
for-of
这个是用来遍历多个对象
for(const e of [2, 4, 6, 8]) |
for-of会使用可迭代对象的next()方法按顺序迭代多个元素
此外,for循环中的break和continue可以使用标号,作用相当于goto,但是它不能任意跳转,只能跳出某个循环let num = 0;
let num = 0;
out://表示第一层for循环,break out就是跳出这层循环
for(let i=0; i<10; i++)
{
for(let j=0; j<10; j++)
{
if(i == 5 && j == 5)
{
break out;
}
num++;
}
}
console.log(num);
with
with作用是把代码作用域设定为特定的对象.严格模式不允许使用with
例如with(location)
{
let qs = search.substring(1);
let hostName = hostname;
let url = href;
}
否则要写
let qs = location.search.substring(1);
let hostName = hostname;
let url = href;