1 js基础学习-基本数据类型+基本语法
请参考 https://blog.csdn.net/m0_48964052?type=blog
https://gitee.com/hongjilin/hongs-study-notes/blob/master/%E7%BC%96%E7%A8%8B_%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/HTML+CSS+JS%E5%9F%BA%E7%A1%80%E7%AC%94%E8%AE%B0/JavaScript%E7%AC%94%E8%AE%B0/javaScript%E5%88%9D%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md#%E7%AE%97%E6%95%B0%E8%BF%90%E7%AE%97%E7%AC%A6
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
- Object 对象
- 其中基本数据类型:String Number Boolean Null Undefined
1 typeof运算符检查数据类型
<!-- 使用typeof运算符检查字符串时,会返回"string"-->
var str = 'hello-word'
console.log(typeof str); /*sout-> string*/
var infinity_ = Infinity /*正无穷*/
console.log(typeof infinity_); /*number*/
2 String字符串
字符串对于保存以文本形式表示的数据很有用。 一些最常用的字符串操作是检查他们的长度,使用 + 和 += 字符串操作符构建和连接它们 ,使用 indexOf() 方法检查子字符串的存在或者位置,或使用 substring()方法提取子字符串。
1 从字符串字面量将字符串创建为原始值
const string1 = "A string primitive";
2 使用 String() 构造函数将字符串创建为对象
const str = new String('hello zhaoshuai-lc');
3 JavaScript 区分 String 对象和原始字符串值:
字符串字面量是原始字符串:在要对原始字符串调用方法或者发生属性查找的上下文中,JavaScript将自动的包装原始字符串并调用方法或在包装对象上执行属性查找
const strPrim = "foo"; // A literal is a string primitive
const strPrim2 = String(1); // Coerced into the string primitive "1"
const strPrim3 = String(true); // Coerced into the string primitive "true"
const strObj = new String(strPrim); // String with new returns a string wrapper object.
const strObj_ = new String('strPrim');
console.log(typeof strPrim); // "string"
console.log(typeof strPrim2); // "string"
console.log(typeof strPrim3); // "string"
console.log(typeof strObj); // "object"
console.log(typeof strObj_); // "object"
eval()
eval是Javascript内置函数,用于计算字符串表达式的值。例如eval("2+3") 返回的是5。
const s1 = "2 + 2"; // creates a string primitive
const s2 = new String("2 + 2"); // creates a String object
console.log(eval(s1)); // returns the number 4
console.log(eval(s2)); // returns the string "2 + 2"
String 对象始终可以使用 valueOf() 方法将其转换为它的原始值(字面量)。
const s2 = new String("2 + 2"); // creates a String object
console.log(eval(s2.valueOf())); // returns the number 4
3 Undefined 未定义
如果声明一个变量但是没有为变量赋值此时变量的值就是undefined 使用typeof检查一个Undefined类型的值时,会返回"undefined"
var obj
console.log(obj); /*undefined*/
console.log(typeof obj); /*undefined*/
4 Null 空值
空值专门用来表示为空的对象,Null类型的值只有一个 null 使用typeof检查一个Null类型的值时会返回"object"
var obj = null
console.log(typeof obj); /*object*/
console.log(obj); /*null*/
5 isNaN()
用来判断一个变量是否为非数字的类型,返回 true 或者 false, 首先会尝试将传入的值转化为Number
6 类型转换
<div id="类型转换">
类型转换就是指将其他的数据类型,转换为String Number 或 Boolean
<div>
调用被转换数据的toString()方法
例子:
var a = 123;
a = a.toString();
注意:这个方法不适用于null和undefined
由于这两个类型的数据中没有方法,所以调用toString()时会报错
<div>
var a
console.log(a); /*undefined*/
console.log(a.toString()); /*Cannot read properties of undefined (reading 'toString')*/
console.log(typeof a); /*undefined*/
</div>
<div>
var a = null
console.log(a); /*null*/
console.log(typeof a); /*object*/
console.log(a.toString()); /*Cannot read properties of null (reading 'toString')*/
</div>
调用String()函数
例子:
var a = 123;
a = String(a);
原理:对于Number Boolean String都会调用他们的toString()方法来将其转换为字符串,
对于null值,直接转换为字符串"null"。对于undefined直接转换为字符串"undefined"
隐式的类型转换:
为任意的数据类型 +""
例子:
var a = true;
a = a + "";
原理:和String()函数一样
</div>
<div>
转换为Number
<div>
方式一(强制类型转换):
调用Number()函数
例子:
var s = "123";
s = Number(s);
转换的情况:
字符串 -> 数字
如果字符串是一个合法的数字,则直接转换为对应的数字
如果字符串是一个非法的数字,则转换为NaN
如果是一个空串或纯空格的字符串,则转换为0
布尔值 -> 数字
true 转换为1
false 转换为0
空值 -> 数字
null 转换为0
未定义 -> 数字
undefined 转换为NaN
</div>
<div>
方式二(强制类型转换):
调用parseInt()或parseFloat()
这两个函数专门用来将一个字符串转换为数字的
如果对非String使用parseInt()或parseFloat()
例子:
var a = "123.456px";
a = parseInt(a); //123
例子:
var a = "123.456px";
a = parseFloat(a); //123.456
</div>
<div>
方式三(隐式的类型转换):
使用一元的+来进行隐式的类型转换
例子:
var a = "123";
a = +a;
console.log(a); /*123*/
console.log(typeof a); /*number*/
原理:和Number()函数一样
</div>
</div>
<div>
转换为布尔值
<div>
方式一(强制类型转换):
使用Boolean()函数
例子:
var s = "false";
s = Boolean(s); //true
转换的情况
字符串 -> 布尔
除了空串其余全是true
数值 -> 布尔
除了0和NaN其余的全是true
null、undefined -> 布尔
都是false
对象 -> 布尔
都是true
</div>
<div>
(隐式类型转换):
为任意的数据类型做两次非运算,即可将其转换为布尔值
例子:
var a = "hello";
a = !!a; //true
</div>
</div>
</div>
7 运算符
<div id="运算符">
<div id="typeof运算符">
typeof运算符
用来检查一个变量的数据类型
</div>
<div id="算数运算符">
做加法运算时,如果是两个字符串进行相加,则会做拼串操作,将两个字符连接为一个字符串。
任何值和字符串做加法,都会先转换为字符串,然后再拼串
</div>
<div id="一元运算符 +">
正号,不会对值产生任何影响,但是可以将一个非数字转换为数字
var a = true
console.log(+a) // 1
var a = '11'
console.log(+a) // 11
</div>
<div id="一元运算符 -">
负号,不会对值产生任何影响,但是可以将一个非数字转换为数字 然后对一个数字进行符号位取反
var a = '11'
console.log(-a) // 11
console.log(typeof -a); // number
var a = true
console.log(-a) // -1
console.log(typeof -a); // number
</div>
<div id="自增">
自增可以使变量在原值的基础上自增1
var a = 3
console.log(a++); // 3
var b =3
console.log(++b) // 4
</div>
<div id="逻辑运算符">
<div id="!">
非运算可以对一个布尔值进行取反,true变false false边true
当对非布尔值使用!时,会先将其转换为布尔值然后再取反
我们可以利用!来将其他的数据类型转换为布尔值
var a = 'niaho'
console.log(!a); // false
console.log(!!a); // true
console.log(typeof !a); // Boolean
</div>
<div id="&&">
逻辑与&&
只有两端的值都为true时,才会返回true。只要有一个false就会返回false。
var res = true && false
console.log(res); // false
短路运算(逻辑中断)- 逻辑与
语法: 表达式1 && 表达式2
如果第一个表达式的值为真,则返回表达式2
如果第一个表达式的值为假,则返回表达式1
</div>
<div id="||">
只有两端都是false时,才会返回false。只要有一个true,就会返回true。
短路运算(逻辑中断)- 逻辑或
规则:
1.如果第一个值为true,则返回第一个值
2.如果第一个值为false,则返回第二个值
</div>
</div>
<div id="相等运算符">
==
相等,判断左右两个值是否相等,如果相等返回true,如果不等返回false
相等会自动对两个值进行类型转换,如果对不同的类型进行比较,会将其转换为相同的类型然后再比较,转换后相等它也会返回true
var res = '11' == 11
console.log(res); // true
!=
不等,判断左右两个值是否不等,如果不等则返回true,如果相等则返回false
不等也会做自动的类型转换。
var res = '11' != 11
console.log(res); // false
===
全等,判断左右两个值是否全等,它和相等类似,只不过它不会进行自动的类型转换,
如果两个值的类型不同,则直接返回false
var res = '111' === 111
console.log(res); // false
!==
不全等,和不等类似,但是它不会进行自动的类型转换,如果两个值的类型不同,它会直接返回true
特殊的值:
null和undefined
由于undefined衍生自null,所以null == undefined 会返回true。
但是 null === undefined 会返回false。
var res = null == undefined
console.log(res); // true
NaN
NaN不与任何值相等,包括它自身 NaN == NaN //false
</div>
</div>
2 js基础学习-数组的学习Array
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。数组使用索引(index)来操作元素,索引指由0开始的整数。
https://gitee.com/hongjilin/hongs-study-notes/blob/master/%E7%BC%96%E7%A8%8B_%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/HTML+CSS+JS%E5%9F%BA%E7%A1%80%E7%AC%94%E8%AE%B0/JavaScript%E7%AC%94%E8%AE%B0/javaScript%E5%88%9D%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md#%E6%95%B0%E7%BB%84array
// 创建数组
var arr = new Array()
var arr_ = []
// 向数组中添加元素
// 数组对象[索引] = 值;
arr_[1] = 'hello'
console.log(arr_); // [ <1 empty item>, 'hello' ]
console.log(arr_.length); // 2
// 创建数组时直接添加元素
var arr1_ = [1, 2, 3, 4, , 5, 'hello']
console.log(arr1_); // [ 1, 2, 3, 4, <1 empty item>, 5, 'hello' ]
console.log(arr1_.length); // 7
var arr2_ = [null, undefined, 1, 'hello']
console.log(arr2_); // [ null, undefined, 1, 'hello' ]
console.log(arr2_.length); // 4
/*
修改数组的长度
数组.length = 新长度
如果修改后的length大于原长度,则多出的部分会空出来
如果修改后的length小于原长度,则原数组中多出的元素会被删除
*/
var arr3_ = [1, 2, 3, 4, 5]
arr3_.length = 2
console.log(arr3_); // [ 1, 2 ]
console.log(arr3_.length) // 2
/***
* 数组的方法
push() 用来向数组的末尾添加一个或多个元素,并返回数组新的长度
pop() 用来删除数组的最后一个元素,并返回被删除的元素
unshift() 向数组的开头添加一个或多个元素,并返回数组的新的长度
shift() 删除数组的开头的一个元素,并返回被删除的元素
reverse() 可以用来反转一个数组,它会对原数组产生影响
concat() 可以连接两个或多个数组,它不会影响原数组,而是新数组作为返回值返回
*/
var arr4_ = [1, 2, 3, 4, 5]
console.log(arr4_.push(100)); // 6
console.log(arr4_); // [ 1, 2, 3, 4, 5, 100 ]
console.log(arr4_.reverse()); // [ 100, 5, 4, 3, 2, 1 ]
console.log(arr4_); // [ 100, 5, 4, 3, 2, 1 ]
// ...
// 数组遍历
var arr5_ = [1, 2, 3, 4, 5, 'hello', 'zhaoshuai-lc']
for (let item of arr5_) {
console.log(item);
}
arr5_.forEach(item => console.log(item))
3 js基础学习-对象Object
对象是JS中的引用数据类型,对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性。使用typeof检查一个对象时,会返回object。
1 对象创建模式-Object构造函数模式
套路: 先创建空Object对象, 再动态添加属性/方法
适用场景: 起始时不确定对象内部数据
问题: 语句太多
<script>
var p = new Object();
p.name = 'zhaoshuai-lc'
p.age = 27
p.setName = function (name) {
this.name = name
}
console.log(p);
p.setName('zhaoshuai-la')
console.log(p);
</script>
但是,引出一下问题:
为什么?箭头函数就出现了问题,这里涉及到的是箭头函数的问题:
对于箭头函数而言:this —> window
对于普通函数而言:this—>p
2 对象创建模式-对象字面量模式
套路: 使用{}创建对象, 同时指定属性/方法
适用场景: 起始时对象内部数据是确定的
问题: 如果创建多个对象, 有重复代码
<script>
var p = {
name: 'zhaoshuai-lc',
age: 27,
sex: 'male'
}
console.log(p);
</script>
3 对象创建模式-自定义构造函数模式
套路: 自定义构造函数, 通过new创建对象
适用场景: 需要创建多个类型确定的对象
问题: 每个对象都有相同的数据, 浪费内存
4 对象创建模式-构造函数+原型的组合模式
构造函数+原型的组合模式–>最好用这个写法
套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
适用场景: 需要创建多个类型确定的对象
放在原型上可以节省空间(只需要加载一遍方法)
4 继承模式-原型链继承
子类型的原型为父类型的一个实例对象
<script>
<!-- 父类型-->
function Supper() {
this.supPro = 'Supper property'
}
Supper.prototype.showSupperProp = function () {
console.log(this.supPro);
}
// 定义子类型
function Sub() {
this.subPro = 'Sub property'
}
Sub.prototype.showSubProp = function () {
console.log(this.subPro);
}
var sub = new Sub();
// 子类调用父类的方法,此时是有问题的
sub.showSupperProp();
</script>
引出一个问题:sub.constructor 竟然指向的是Supper的构造函数
解决方案:constructor 我们称为构造函数,因为它指回构造函数本身
5 继承模式-构造函数补充
6 继承模式-借用构造函数继承(假的)
7 继承模式-组合继承
基本数据类型和引用数据类型
基本数据类型 String Number Boolean Null Undefined
引用数据类型 Object
基本数据类型的数据,变量是直接保存的它的值,变量与变量之间是互相独立的,修改一个变量不会影响其他的变量。
引用数据类型的数据,变量是保存的对象的引用(内存地址),如果多个变量指向的是同一个对象,此时修改一个变量的属性,会影响其他的变量。
比较两个变量时,对于基本数据类型,比较的就是值,对于引用数据类型比较的是地址,地址相同才相同。
4 js基础学习-函数(Function)
函数也是一个对象,也具有普通对象的功能,函数中可以封装一些代码,在需要的时候可以去调用函数来执行这些代码,使用typeof检查一个函数时会返回function。
// 函数的声明
function func(name, age, sex) {
console.log(name, age, sex);
}
// 函数表达式
var func_ = function (name, age, sex) {
console.log(name, age, sex);
}
// 函数的调用-当我们调用函数时,函数中封装的代码会按照编写的顺序执行
func('zhaoshuai-lc', 26, 'male');
// 立即执行函数-函数定义完,立即被调用,立即执行函数往往只会执行一次
(function (name, age) {
console.log(name, age)
})('zhaoshuai-la', 27);
/*
调用函数时JS解析器不会检查实参的类型和个数,可以传递任意数据类型的值:
如果实参的数量大于形参,多余实参将不会赋值;
如果实参的数量小于形参,则没有对应实参的形参将会赋值undefined;
*/
/*
返回值,就是函数执行的结果:
语法:return 值;
该值就会成为函数的返回值,可以通过一个变量来接收返回值,
return后边的代码都不会执行,一旦执行到return语句时,函数将会立刻退出。
return后可以跟任意类型的值,可以是基本数据类型,也可以是一个对象。
如果return后不跟值,或者是不写return则函数默认返回undefined。
break、continue和return
break-退出循环
continue-跳过当次循环
return-退出函数
*/
/*
参数,函数的实参也可以是任意的数据类型。
*/
// 函数的属性和方法
/*
call() && apply()
1 这两个方法都是函数对象的方法需要通过函数对象来调用
2 通过两个方法可以直接调用函数,并且可以通过第一个实参来指定函数中this
3 不同的是call是直接传递函数的实参, 而apply需要将实参封装到一个数组中传递
arguments
arguments和this类似,都是函数中的隐含的参数
arguments是一个类数组元素,它用来封装函数执行过程中的实参
所以即使不定义形参,也可以通过arguments来使用实参
arguments中有一个属性callee表示当前执行的函数对象
this是函数的上下文对象,根据函数的调用方式不同会执向不同的对象
1.以函数的形式调用时[独立调用],this是window
2.以对象.方法的形式调用时[谁调用就指向谁],this是调用方法的对象
3.以构造函数的形式调用时,this是新建的那个对象
4.使用call和apply调用时,this是指定的那个对象
5.在全局作用域中this代表window
*/
// 作用域 - 一个变量的作用范围
/*
全局作用域:
1 直接在script标签中编写的代码都运行在全局作用域中
2 全局作用域在打开页面时创建,在页面关闭时销毁
3 全局作用域中有一个全局对象window,window对象由浏览器提供,可以在页面中直接使用,它代表的是整个的浏览器的窗口。
4 在全局作用域中创建的变量都会作为window对象的属性保存
5 在全局作用域中创建的函数都会作为window对象的方法保存
6 在全局作用域中创建的变量和函数可以在页面的任意位置访问
7 在函数作用域中也可以访问到全局作用域的变量
8 尽量不要在全局中创建变量
函数作用域:
1 函数作用域是函数执行时创建的作用域,每次调用函数都会创建一个新的函数作用域
2 函数作用域在函数执行时创建,在函数执行结束时销毁
3 在函数作用域中创建的变量,不能在全局中访问
4 当在函数作用域中使用一个变量时,它会先在自身作用域中寻找,
如果找到了则直接使用,如果没有找到则到上一级作用域中寻找,
如果找到了则使用,找不到则继续向上找 ,,,
*/
/*
变量的声明提前:
1 在全局作用域中,使用var关键字声明的变量会在所有的代码执行之前被声明,但是不会赋值
所以我们可以在变量声明前使用变量。但是不使用var关键字声明的变量不会被声明提前。
2 在函数作用域中,也具有该特性,使用var关键字声明的变量会在函数所有的代码执行前被声明.
3 如果没有使用var关键字声明变量,则变量会变成全局变量
<script>
function fun() {
a = 100
}
fun()
console.log(a) // 100
</script>
*/
/*
函数的声明提前
在全局作用域中,使用函数声明创建的函数 function fun(){}, 会在所有的代码执行之前被创建,也就是我们可以在函数声明前去调用函数,
但是使用函数表达式 var fun = function(){} 创建的函数没有该特性
在函数作用域中,使用函数声明创建的函数,会在所有的函数中的代码执行之前就被创建好了。
*/
/*
构造函数是专门用来创建对象的函数
1 一个构造函数我们也可以称为一个类
2 通过一个构造函数创建的对象,我们称该对象是这个构造函数的实例
3 通过同一个构造函数创建的对象,我们称为类对象
4 构造函数就是一个普通的函数,只是他的调用方式不同,
如果直接调用,它就是一个普通函数
如果使用new来调用,则它就是一个构造函数
*/
function Person(name, age, gender) {
console.log('this - ', this)
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = () => {
console.log('hello-zhaoshuai-lc')
}
}
var person = new Person('zhaoshuai-lc', 22, 'male');
// console.log('this - ', this) // Person {}
/*
构造函数的执行流程:
1.创建一个新的对象
2.将新的对象作为函数的上下文对象(this)
3.执行函数中的代码
4.将新建的对象返回
*/
/*
instanceof 用来检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
如果该对象时构造函数的实例,则返回true,否则返回false
console.log('person instanceof Person - ', person instanceof Person)
// person instanceof Person - true
Object是所有对象的祖先,所以任何对象和Object做instanceof都会返回true
*/
Person('zhaoshuai-lc', 22, 'male');
// console.log('this - ', this) // Object
5 原型(prototype)
/**
* 创建一个函数以后,解析器都会默认在函数中添加 - prototype
* prototype属性指向的是一个对象,这个对象我们称为原型对象。
* 当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性执行该原型对象。
* 这个隐含的属性可以通过对象.__proto__来访问
*/
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sayHi = () => {
console.log('sayHi zhaoshuai-lc')
}
}
var person = new Person('zhaoshuai-lc', 28, 'male');
console.log(person.__proto__);
/**
原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。
我们可以将对象中共有的属性和方法统一添加到原型对象中, 这样我们只需要添加一次,就可以使所有的对象都可以使用。
当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找,如果在自身中找到了,则直接使用。
如果没有找到,则去原型对象中寻找,如果找到了则使用。
如果没有找到,则去原型的原型中寻找,依此类推。
直到找到Object的原型为止,Object的原型的原型为null,
如果依然没有找到则返回undefined。
hasOwnProperty()
这个方法可以用来检查对象自身中是否含有某个属性
语法:对象.hasOwnProperty("属性名")
*/
<script>
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sayHi = () => {
console.log('sayHi zhaoshuai-lc')
}
}
var person = new Person('zhaoshuai-lc', 28, 'male');
console.log('person.__proto__ = ', person.__proto__);
console.log('person.hasOwnProperty(\'name\') = ', person.hasOwnProperty('name'));
// person.hasOwnProperty('name') = true
</script>