前言
这是一次简单的JavaScript基础语法的重新学习,只记录JavaScript与C\C++的不同之处,相同的不再赘述。
一、输出
使用 window.alert() 弹出警告框。
使用 document.write() 方法将内容写到 HTML 文档中。
使用 innerHTML 写入到 HTML 元素。
使用 console.log() 写入到浏览器的控制台。(常用)
二、变量
1.声明
var name
或var num = 1
。 不用说明变量的类型,编译器会自行判断。若初始化,则是初始化值的类型;若未初始化,则是undefined数据类型。每当该变量再次被赋值或再次被声明定义时,会被转换成新的数据类型。let name
。 声明的是块级作用域变量,只在块级作用域内有效,不能被块外部访问,且不可重名。块级指{....}之内的内容,如for{}中。const name = 'jek'
。 声明常量,块级作用域,必须初始化,不可修改。
后两种声明方式为ES6
特性。
练习代码:
//----------var、let、const声明变量-------------
// var声明变量后,赋不同类型的值和重新声明定义
var v1 = 1;
console.log(v1, typeof v1);
v1 = 'ssss';
console.log(v1, typeof v1);
var v1 = false;
console.log(v1, typeof v1);
// 函数局部
function myFunction() {
// var局部变量,外部可访问,但不能访问到局部变量的值。按理来说局部是不可访问的,此处笔者也很迷惑
var name = 'bbbb';
}
console.log(name, typeof name); // 输出 空字符 + string
// 块级区域
for (var i = 0; i < 5; i++) {
var x = i; // var声明块级变量,外部可以访问且值相同
}
console.log(x);
for (var i = 0; i < 5; i++) {
let y = i; // let声明块级变量,外部不可访问
}
console.log(y);
输出结果:
1 "number"
ssss string
false "boolean"
string
4
Uncaught ReferenceError: y is not defined
(注:js有变量提升的特性,即允许先使用(如赋值)再声明,但不建议使用)
2.数据类型(6种值类型+3种引用类型)/(6种原始类型+对象类型)
1)string
字符串:var str = 'hello'
。 可以用双引号或单引号包裹,如"hello"
和'hello'
都可以(建议用单引号)。可以通过下标访问字符串中的字符。
两个字符串之间可以通过 +
拼接。
ES6
中新增了字符串模板的特性。字符串需用``包裹起来,字符串中需要替换的变量用${}
包裹。示例:
var name="zzw";
console.log(`hello ${name}`);
输出hello zzw
2)number
数字:var num = 1
。 包括整数、浮点数、科学计数法表示的数(2.1e10)。js中浮点数的精度是个问题。数字可以与字符串通过 +
拼接,此时数字会被转换成字符串。
3)boolean
布尔类型:var bo = true
。
4)undefined
无定义类型:var name
。 变量声明时没有被定义,或者输出一个未声明的变量,则为undefined类型。
5)null
空类型:var name = null
或name = null
。 用来将变量置空,其实表示一个空对象引用。
6)symbol
symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
7)array
数组:var arr = [1,2,3]
或者var arr = new Array(1,2,3)
。 在js中数组类型其实算作一种对象类型。 而且,js数组与C数组还有几个不同点:
- js数组的每一项可以用来保存任何类型的数据,也就是说,可以用数组的第一个位置来保存字符串,第二个位置保存数值,第三个位置保存对象。
- 数组的大小是可以动态调整的。
- 访问超限时,输出undefined。
8)function
函数。在js中,函数也可以是变量,后面详细介绍。
9)object
对象。也算变量,后面再详细介绍。
练习代码:
//----------变量------------
// number类型
var num = 3;
console.log(num, typeof num);
// string类型
var str = 'hello';
console.log(str, typeof str);
// 拼接字符串和数字
console.log(str+' '+num);
// boolean类型
var bo = true;
console.log(bo, typeof bo);
// undefined类型
var udf;
console.log(udf, typeof udf);
// null类型
var nu = null;
console.log(nu, typeof nu);
// 数组
var arr = [1,2,3];
// var arr = new Array(1,2,3);
console.log(arr, typeof arr);
console.log(arr[9]); // 访问超限,输出undefined
arr = [1, 'hello', [2, 3]];
console.log(arr, typeof arr);
// 函数类型
var fun = function() {
console.log('this is a function');
}
console.log(fun, typeof fun);
// 对象类型
var obj = {
name: 'tomcat',
getName: function() {
return name;
}
};
console.log(obj, typeof obj);
输出结果:
3 "number"
hello string
hello 3
true "boolean"
undefined "undefined"
null "object"
[1, 2, 3] "object"
undefined
[1, "hello", Array(2)] "object"
ƒ () {
console.log('this is a function');
} "function"
{name: "tomcat", getName: ƒ} "object"
三、运算符
特别注意:在js中有相等==
和绝对相等===
,不相等!=
和不绝对相等!==
。区分如下:
-
==
。 值相等,类型可以不相等 -
===
。 值和类型都必须相等 -
!=
。 ==取反,即类型相等时,值不相等 -
!==
。 ===取反,即值或类型都可以不相等
其它运算符与c的相同。
四、语句
if、for、while、switch等,与c相同。
五、函数(重要)
1.函数定义
1)函数语句定义(常规)
参数,可有可无,不用指定数据类型(js中,变量本就不需指定类型),默认为undefined类型。传入参数个数不定,按顺序未传入的参数为undefined。ES6
中参数可以设定默认值。
返回值,可有可无。
function funA (a, b) {
console.log('a is ' + a);
console.log('b is ' + b);
console.log('a+b is ' + (a+b));
}
funA(2, 4);
funA(2);
// ES6 函数参数可以设定默认值
function funB (a, b = 10) {
console.log('默认值 || ' + (a+b));
}
funB(3);
输出:
a is 2
b is 4
a+b is 6
a is 2
b is undefined
a+b is NaN
默认值 || 13
2)函数表达式(函数变量)定义
将匿名函数赋给一个变量,该变量可以跟函数一样使用,其数据类型为函数类型。
var vB = function (a, b) {
return a*b;
};
vB(2, 3);
在《JavaScript权威指南》中说:
以表达式定义的函数只适用于它作为一个大的表达式的一部分。
其实,我觉得表达式定义形式也可以用于一般函数。感觉两者没什么太大区别,可能也是我不了解js的内部实现。
2.匿名函数
不带函数名的函数,即为匿名函数,如:
function () {
console.log('this is an anonymous function');
}
可单单定义一个匿名函数是无法调用的,因为它没有名字。但,我们可以通过将匿名函数赋给变量(该变量成为函数类型变量),或函数自调用的方式,来调用匿名函数。
ES6
新增用箭头函数来表示匿名函数:
// ES6 新增箭头函数来表示匿名函数,一个参数时可以省略圆括号,一条语句可以省略花括号
var vB = (a, b) => {
console.log('箭头函数 || a-b is ' + (a-b));
};
vB(6, 3);
3.函数自调用
其形式为 (...匿名函数定义...)(...参数...);
。作用是在函数定义后立即调用该函数:
(function (a, b) {
console.log('函数自调用 || a-b is ' + (a-b));
})(6, 2);
或
((a, b) => {
console.log('箭头函数 || a-b is ' + (a-b));
})(6, 2);
输出:
函数自调用 || a-b is 4
箭头函数 || a-b is 4
4.函数作为值
在js中,函数也是变量,那么函数就可以当作一个变量来进行传递。
1)函数作为返回值(函数闭包)
函数返回一个子函数(嵌套函数),那接受这个返回值的变量即是函数类型变量。
function fa (first) {
return function (second) {
return first += second;
};
}
var son = fa(0); // son变量接受一个返回函数
/*相当于
var son = function (second) {
return first += second
};
只是这样定义时,不能使用函数fa()的局部变量first
*/
console.log(son(1)); // 输出 1
console.log(son(1)); // 输出 2
或
function fa (first) {
return (second) => {
return first += second;
};
}
var son = fa(0);
console.log(son(1));
console.log(son(1));
或
// 直接将fa函数写成自调用的匿名函数,自调用后返回一个函数给son变量
var son = (((first) => {
return (second) => {
return first += second;
};
})(0));
console.log(son(1));
console.log(son(1));
输出:
1
2
从第一个代码示例中,我们可以发现:返回一个函数(fa)的内部函数(son)时,我们可以通过这个返回的函数(son)来使用外函数(fa)中的局部变量。而且在不断调用内部函数(son)的过程中,外函数(fa)并没有被销毁(出栈)。由于这种机制,我们就可以让函数拥有私有变量,不能被全局使用,但又可以一直保持值不被销毁。而这就是闭包。
代码:
//函数闭包。使函数可以拥有私有变量(外部不可访问,同时也不会因为函数调用而刷新)
var add = (() => {
var counter = 0;
return () => {return counter += 1;}
})();
add(); // add()实际调用的是上述匿名主函数中返回的匿名子函数
add();
add();
console.log('函数闭包 || ', add());
输出:
函数闭包 || 4
2)函数作为参数(多态性/Lambda表达式)
将一个自定义函数作为参数传入另一个函数中,这个传入函数可以根据不同情况自行定义,从而让被传入函数实现不同效果。
// 函数作为参数。使多态性得以体现
function appendDiv (callback) {
for(var i=0;i<10;i++){
var div = document.createElement('div');
div.innerHTML = i;
document.body.appendChild(div);
// 如果传入的参数是一个函数类型的变量
if(typeof callback == 'function'){
callback(div); // 将该形参作为函数变量使用
console.log(callback);
}
}
}
// 将一个自定义的匿名函数作为参数传入appendDiv()函数
appendDiv((node) => {
node.style.display='block'; // 让该元素以块元素展示(独占一行)
});
appendDiv((node) => {
node.style.display='inline'; // 让该元素以行内元素展示
});
显示结果:
函数作为参数传入另一个函数的方式,常用于将自定义的回调函数传入接口函数中。但,在传入自定义参数到接口函数的这种场景中,常常是将回调函数作为对象中的一个方法传入的。
如微信小程序开发中常用的网络请求接口函数:
wx.request({
url: wx.getStorageSync('requestUrl') + '/small/config',
method: 'GET',
data: {
},
header: {
'content-type': 'application/json'
},
success: (res) => {
console.log('get config: ', res.data.WeCosUrl)
wx.setStorageSync('wecosUrl', res.data.WeCosUrl)
}
});
wx.request()是微信提供的用于网络请求的接口函数,其参数是一个对象。对象中的success方法,是wx.request()函数执行访问成功后调用的函数,由用户自定义。而这就是一种多态性。
六、对象(重要)
1.js中的对象
在js中,大部分事物都是一个对象。引用《JavaScript权威指南》中的话说:
除了字符串、数字、true、false、null和undefined之外,JavaScript中的值都是对象。尽管字符串、数组和布尔值不是对象,但它们的行为和不可变对象非常类似。
字符串有对象的部分特性,如:
var message='Hello World!';
console.log(message.length); // 获取字符串的长度属性
但,字符串“对象”的属性是不可修改的,如修改message.length的大小是无效的。同时,字符串还有很多常用的自带方法,如:内容匹配match()、内容替换replace()、转换大小写toUpperCase()/toLowerCase()等等。
2.对象创建
js中,对象用{...}
将属性和方法包裹起来。每个属性和方法都有唯一的名字,而且名字和值之间是通过:
一一映射的。如:
var obj = {
name: 'tomcat',
getName: function() {
return this.name;
}
};
console.log(obj.getName()); // 输出 tomcat
this的注意点:
this关键字指向的是调用该函数的对象。如果不使用this.name
,可能会返回全局中的name变量。如:
var obj = {
name: 'tomcat',
getName: function() {
return name;
}
};
var name = 'tom';
console.log(obj.getName()); // 输出 tom
另外,箭头函数虽然是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:this指针的指向。匿名函数中this指向调用者对象,而箭头函数中的this指向再上一层调用者对象。如:
var name = 'tom';
var obj = {
name: 'tomcat',
getName: () => {
console.log(this); // 输出 window对象
// 由于箭头函数,this指针指向上一层对象,即全局对象,因此这里的this.name是全局中的name变量
return this.name;
}
};
console.log(obj.getName()); // 输出 tom
所以,在对象的方法定义中,不建议使用箭头函数。
对象还可以通过new + 构造函数的方法来创建,如:
var o = new Object(); // Object()是Object这个js“原型”对象的构造函数。返回一个空对象
3.js对象属性和方法的动态性
可以动态增加与删除对象中的属性和方法,如:
// 动态增加属性 方法
var book = {};
// var book = new Object();
book.author = 'es6';
book.title = 'JavaScript';
book.changeTitle = function () {
this.title = 'python';
return this.title;
};
console.log(book.author, book.title, book.changeTitle()); // 输出 es6 JavaScript python
// 删除属性、方法
delete book.author;
console.log(book.author); // 输出 undefined
4. js对象的引用与赋值
js中对象值是引用类型,相当于指针。
// 对象的引用与赋值
var obj1 = {
a : 1
}
var obj2 = obj1;
obj2.a = 2;
console.log(obj1.a); // 输出2
var obj2 = obj1;
相当于把obj1
的指针赋给obj2
,所以obj1
和obj2
指向同一对象的数据。
同时,若函数参数为对象,并在函数中修改对象中数据,那也会影响到函数外的对象。
那js应该如何正确的进行对象赋值呢,代码如下:
// 对象间赋值的正确方法
var obj3 = {
a:1,
b:2,
c:3,
d:[0,1,2,3]
};
var jsonStr = JSON.stringify(obj3);
var obj4 = JSON.parse(jsonStr);
obj4["e"] = 4;
obj4["d"][0] = 11;
console.log(obj3); //Object {a: 1, b: 2, c: 3, d: [0,1,2,3]}
console.log(obj4); //Object {a: 1, b: 2, c: 3, d: [11,1,2,3], e: 4}