一,数据类型
值类型:
- 数字
- 字符串
- 布尔
- undefined
- null
引用类型
- 数组
- 对象
- 函数
- set(es6新增)
- map(es6新增)
值类型与引用类型的区别?
- 值类型的key与value都存储在栈区
- 引用类型数据将key存储在堆区,而将真正的值存储在栈区
- 如果将一个引用类型的数据直接赋值给一个变量,实际上是将这个变量的地址复制给了这个变量,而并非真正的值;
二,数据类型的判断
-
typeof
只能判断值类型与引用类型的数据
-
instance of
判断是否为某个数据类型的实例
-
constructor
判断是否某个数据类型的构造者
-
isArray
数组专用,判断是否为数组 -
Object.prototype.toString.call()
最为准确,可以精准具体判断是哪一个数据类型
可以为第五组判断方法封装一个函数
<script>
function Gettype(obj){
return Object.prototype.toString.call(obj).slice(8,-1)
}
</script>
斐波拉契数列
求斐波那契 数为n的数列
1,1,2,3,5,8,13,21,34,55,89,…
function fib(n){
if(n == 0 || n == 1){ //如果是第0位返回1,如果是第1位返回1
return 1
}else{
return fib(n - 1) + fib(n - 2) //如果其他位 返回 前面两个数的和
}
}
// alert(fib(41));此种方法计算有局限,最高计算到41位
//分析
/*
n=0时,fib(0)==> return 1
n=1时,fib(1)==> return 1
n=2时,fib(2)==> return fib(1)+fib(0)==>1+1=2
n=3时,fib(3)==> return fib(2)+fib(1)==>2+1=3
n=4时,fib(4)==> return fib(3)+fib(2)==>3+2=5
*/
三,深浅拷贝
- 浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用;直接将一个值赋值给一个变量就是浅拷贝
- 深拷贝:创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”,新对象跟原对象不共享内存,修改新对象不会改到原对象
- Es6扩展
var obj1 = {
name: "张三",
age: 18,
friend: ['小红', '小绿', {
name: "小蓝",
job: "teacher"
}]
}
var obj2 = {
...obj1
}
- for循环
var obj3 = {};
for (var k in obj1) {
obj3[k] = obj1[k];
}
- assign
//第三种 (目标对象,源对象)
var obj4 = Object.assign({}, obj1)
console.log(obj4)
- 递归
function deepCopy(obj1) {
if (typeof obj1 == "object"&obj1!=null) {
var temp = null
if (obj1 instanceof Array) {
temp = [];
for (var i = 0; i < obj1.length; i++) {
temp[i] = deepCopy(obj1[i]);
}
} else {
temp = {};
for (var k in obj1) {
temp[k] = deepCopy(obj1[k])
}
}
return temp;
} else {
return obj1;
}
}
//浅拷贝三种方式
var obj1 = {
name: "张三",
age: 18,
friend: ['小红', '小绿', {
name: "小蓝",
job: "teacher"
}]
}
//第一种:Es6扩展
var obj2 = {
...obj1
}
//第二种:for循环
var obj3 = {};
for (var k in obj1) {
obj3[k] = obj1[k];
}
//第三种 (目标对象,源对象)
var obj4 = Object.assign({}, obj1)
console.log(obj4)
//第四种递归
function deepCopy(obj1) {
if (typeof obj1 == "object"&obj1!=null) {
var temp = null
if (obj1 instanceof Array) {
temp = [];
for (var i = 0; i < obj1.length; i++) {
temp[i] = deepCopy(obj1[i]);
}
} else {
temp = {};
for (var k in obj1) {
temp[k] = deepCopy(obj1[k])
}
}
return temp;
} else {
return obj1;
}
}
四,隐式转换
- 字符串与任意类型的数据链接都会转换成字符串
var a="100" //字符串
var b=10; //数字
var c = a+b; //10010
- 数学运算符会尝试将隐式转换成数字;如果没有将数据转换成功,结果就是NaN
var a="10";
var b=2;
var c =a*b //20;
var a ="abc10"
var b=2;
var c =a*b // NaN;
- 算数运算会将布尔类型默认转换成0,1
var a =false;
var b=2;
var c =a*b; //0;
- 空字符串,0,null,undefined NaN false会被转换成false,其他都会转换成true
var a ="";
var b = true;
console.log(!!a);
等于判断
== (等于) 判断隐式转换后值是否相等
=== (严格等于) 判断类型与值是否相对
- ==判断
console.log(100 == "100"); //true(如果两边类似数字会优先隐式转换为数字)
console.log("" == false); //true
console.log(1 == true);// true
console.log(null == undefined);// true 隐式转换后都为fasle
console.log(null == null); // true 空指针都指向一个地方(空)
console.log(undefined == undefined);//
console.log(null == NaN);false(特殊) 数字不等于空
console.log([] == []);//false //两块不同的内存地址
console.log({}== {});//false //两块不同的内存地址
- ===严格等于
// === 严格等于 判断类型 与值 是否相对
alert(0 === ""); //false
alert([] === []); //false
alert({} === {}); //false
alert(null === undefined); //false
alert(null === null); //true
//应该都用=== 严格等于
//判断是为null 还是undefined 可以用===
if与逻辑运算符
if判断
- if判断只要求()内 表达式结果是否为truely变量
- falsely变量:false “ ” 0 NaN false undefined null;对变量取两次反; !! 结果为false的变量,称为falsely变量
- 除了falsely变量外其他都是truely变量
var a = 10;
if(a){
console.log("条件通过") //条件通过
}
//条件通过
var b = "";
if(b){
console.log("b通过")
}else{
console.log("b不通过")
}
// b不通过
逻辑运算符
- 与&&
1.如果前面的为false,则直接返回false,如果前面的为true,则看后面是否为true
2.&&前面是truely变量则返回后面的值,前面是falsely变量则直接使用前面的值
3.在逻辑判断中,&&前面的值为falsely后面的不执行,前面为truely,则看&&后面的值
4.注意在&&前面如果有报错,则这个代码也会报错,都不执行
var a = 15 || 0;
var b = false || 50;
var c = false || undefined;
var d = 0 || false;
console.log(a); //15 15 转换结果为true ,a的值就是15
console.log(b); //50 false 转换的结果为false b的值是50
console.log(c); // undefined
console.log(d); //false
判断对象
if(a&&a.b&&a.b.c){}
if(a?.b?.c){}
如果有a并且有a.b并且有a.b.c
- 或||
同假则假,只要一方为真,结果就是真,如果前面的变量为truely,最终的结果为第一个,如果为falsely,结果为第二个
var a = 15 || 0;
var b = false || 50;
var c = false || undefined;
var d = 0 || false;
console.log(a); //15 15 转换结果为true ,a的值就是15
console.log(b); //50 false 转换的结果为false b的值是50
console.log(c); // undefined
console.log(d); //false
原型与原型链
作用:
- 在js中实现继承
- 实现类(构造函数)实例上方法的扩展
例子:自定义一个求一组数最大值的方法,并将其挂载到数组原型对象上面
准则1:不要需要js默认对象原型上的方法
准则2:不要在js默认对象的原型上添加方法
vue2 数组的双向绑定劫持就是重写了数组的原型上的方法实现的
什么是类?
类是构造对象的一个模板,例如:Array,Object,String,其实本质上是一个函数
什么是实例?
说白一点就是将一个抽象的类给具体化的过程就叫做实例化,比如你要一个人的类,那我就实例化出一个对象,name为张三,age为18,sex为男
什么是原型?
每一个类(构造函数)都有一个显示原型prototype,每一个实例都有一个隐式原型__proto__,
实例化对象的__proto__等于类(构造函数)的prototype
什么是原型链?
当我们查找对象的一个属性会先在自身上找,如果找不到就沿着__proto__的__proto__向上查找,我们将proto形成的链条关系称为我们的原型链
类的继承
为了更好的理解原型链,我们来定义两个类分别是Person类与Student类,Person上有name,age属性与eat方法,让学生来继承Person身上的方法
//01 创建people类
function People(name, age) {
this.name = name;
this.age = age;
}
//02 给people 显示原型添加eat方法
People.prototype.eat = function() {
console.log(this.name + "正在吃饭");
}
//03 创建 学生类继承People 类
function Student(name, age, no) {
//执行people构造函数(执行people 函数并把当前的this传入函数,当做people的this)
People.call(this, name, age);
//定义学号
this.no = no;
}
//04 让Student 显示原型链继承 People 的原型链
Student.prototype = Object.create(People.prototype);
//05 修正Student 显示原型链 上的构造函数
Student.prototype.constructor = Student;
//06 在Student 显示原型链添加方法
Student.prototype.study = function() {
console.log(this.name + "正在好好学习");
}
//07 构建 Student 的实例s1
var s1 = new Student("菜菜", 18, 9527);