一、数组
注意:不要在循环中使用 return,否则会终止循环。如果一定要使用,将原本要 return 的最终结果,存到数组中,再将这个数组 return 出来。
1. 数组的创建、赋值、分类:
(1)创建:
① 声明式创建: var arr = [];
② 构造函数创建: var arr2 = new Array();
(2)赋值:
① var arr = [4,5,6,7];
② var arr2 = new Array(7,8,9,0,1);
(3)分类:
① 伪数组:例如 arguments
;
② 数组: 整数数组、字符串数组、json对象数组、二维数组;
2. 数组的简单操作(根据索引增、查、改):
(1)增:
var arr = [];
arr = [4,'a',true,undefined,NaN,null,{},[],function(){console.log("hello")}];
console.log(arr[9]);//undefined 声明了arr,但是arr下标为9的位置未赋值
arr[9] = "world";
console.log(arr);//(10) [4, "a", true, undefined, NaN, null, {…}, Array(0), ƒ, "world"]
- 注意:打印的时候,浏览器显示的是
(2) [empty,0]
,实际上 arr2[0] 的值是undefined
,而不是 empty。var arr2 = []; arr2[1] = 4; console.log(arr2); //(2) [empty,0] console.log(arr2[0]); //undefined
(2)查:
var arr = [4,'a',true,undefined,NaN,null,{},[],function(){console.log("hello")}];
console.log(arr[1]);//a
arr[8]();//hello
for(var i =0;i<arr.length;i++){
console.log(arr[i]);
}
(3)改:
var arr = [4,'a',true,undefined,NaN,null,{},[],function(){console.log("hello")}];
arr[2] = "hello";
console.log(arr[2]); //hello
3. 声明式和构造函数创建的数组的区别:
(1)使用声明式:
var arr1 = []; // 创建空数组
var arr2 = [ 20 ]; // 长度为1,数据是20
var arr3 = [ "2","6","9" ]; // 创建带有三个字符串的数组
console.log(arr2); //[20]
console.log(arr3); //(3) ["2", "6", "9"]
(2)使用 Array 构造函数
var arr1 = new Array( ); // 创建空数组
var arr2 = new Array( 20 ); // 长度是 20 的空数组
var arr3 = new Array( "2","6","9" ); // 创建带有三个字符串的数组
console.log(arr2); //(20) [empty × 20]
console.log(arr3); //(3) ["2", "6", "9"]
4. 数组的方法:
以下所列方法中:
- 会改变原数组的方法:
push()
、unshift()
、splice()
、pop()
、shift()
、splice()
、sort()
、reverse()
;- 返回新数组,不影响原数组的方法:
slice(n,m)
、join()
、toString()
、concat()
;
(1)增:push()
、unshift()
、splice()
;
-
①
push()
,给数组的最后一位增加;var arr = [4,5,6,7]; arr.push("hello"); console.log(arr);//(5) [4, 5, 6, 7, "hello"]
-
②
unshift()
,给数组的第一位增加;var arr = [4,5,6,7]; arr.unshift("hello"); console.log(arr);//(5) ["hello", 4, 5, 6, 7]
-
③
splice(指定位置(从0开始,指定位置包括自身), 删除个数, 新增内容)
,给指定索引的位置增加;var arr = [4,5,6,7]; arr.splice(1,2,"world"); console.log(arr);//(3) [4, "world", 7] arr.splice(1,0,2); console.log(arr);//(4) [4, 2, "world", 7] arr.splice(1,1,"hello"); //相当于替换 console.log(arr);//(4) [4, “hello”, "world", 7]
(2)删: pop()
、shift()
、splice()
;
-
①
pop()
,删除数组的最后一个;var arr = [4,5,6,7,8,9]; arr.pop(); console.log(arr);//(5) [4, 5, 6, 7, 8]
-
②
shift()
,删除数组的第一个;var arr = [4,5,6,7,8,9]; arr.shift(); console.log(arr);//(5) [5, 6, 7, 8, 9]
-
③
splice(指定位置(从0开始,指定位置包括自身),删除个数)
;var arr = [4,5,6,7,8,9]; arr.splice(1,1); console.log(arr);//(5) [4, 5, 7, 8, 9]
(3)截取: slice(n,m)
(截取数组的第 n 位到第 m 位的前一位,含前不含后。返回新数组,不操作/影响原数组)
var arr = [4,5,6,7,8,9];
console.log(arr);//(6) [4,5,6,7,8,9]
arr.slice(1,3);
console.log(arr); //(6) [4,5,6,7,8,9]
//当使用方法时,返回原数组,发现没有变化时,可能是这个方法把处理结果放在返回值中。
//就像在 slice() 方法中有个 return。
console.log(arr.slice(1,3)); //(2) [5,6]
var newArr = arr.slice(1,3);
console.log( newArr ); //(2) [5,6]
(4)排序:sort()
、reverse()
- ①
sort()
,默认按字符升序排列;
解决var arr = [4,6,5,3,8]; arr.sort(); console.log(arr);//(5) [3, 4, 5, 6, 8] var arr2 = [2,101,6,58,3] arr2.sort(); console.log(arr2);//(5) [101, 2, 3, 58, 6] var arr3 = ["Banana", "Orange", "Apple", "Mango"] arr3.sort(); console.log(arr3); //(4) ["Apple", "Banana", "Mango", "Orange"]
sort()
按位排序的方法://升序: var arr2 = [2,101,6,58,3] arr2.sort(function(a,b){return a-b;}) console.log(arr2); //(5) [2, 3, 6, 58, 101] //降序: arr2.sort(function(a,b){return b-a;}) console.log(arr2); //(5) [101, 58, 6, 3, 2]
- ②
reverse()
,反向排序,将数组中的元素颠倒顺序,返回逆序后的数组。var arr = ["Banana", "Orange", "Apple", "Mango"] arr.reverse(); console.log(arr); //(4) ["Mango", "Apple", "Orange", "Banana"]
(5)数组转为字符:join()
、toString()
- ①
join()
,将数组转为字符,参数会将逗号替换掉,返回一个新数组;var arr = [2,6,8,9]; console.log(arr.join()); //2,6,8,9 console.log(arr.join('')); //2689 console.log(arr.join('-')); //2-6-8-9
- ②
toString()
,也可以将数组转为字符,返回一个新数组;var arr = [2,6,8,9]; console.log(arr.toString()); //2,6,8,9
(6)合并两个或多个数组:concat()
,返回新数组,不影响原数组。
var a = [2,6,8,9];
var b = ["hello", "world", "I"];
var c = [4, 7];
var result = a.concat(b, c);
console.log(result); //(9) [2, 6, 8, 9, "hello", "world", "I", 4, 7]
5. 数组的遍历(获取数组中的每个元素):for()
(1)定义一个 30 项的数组,数组每一项要求是 1-10 的随机数,每间隔 5 个数字,求出前 5 个数的平均值。
var arr = new Array(30);
var newArr = [];
var aveArr = [];
for(var i=0; i<30; i++){
arr[i] = Math.round(Math.random()*9+1)
}
for(var i=0; i<30; i=i+5){
newArr.push( arr.slice(i, i+5) );
}
console.log(newArr)
for(var i=0; i<newArr.length; i++){
aveArr.push( ave(newArr[i]) )
}
console.log(aveArr)
//求数组每个值之和的平均值
function ave(arr){
var sum=0;
for(var i=0; i<arr.length; i++){
sum += arr[i];
}
return sum/arr.length;
}
(2)数组去重(利用 对象 添加属性得到undefined)
通过
obj.A
,就可以给对象添加一个值为undefined
的属性A。
- 定义一个空对象 obj,遍历数组;
判断数组中的第一个值在obj中是否存在,如果不存在,就将这个值作为对象的键,给它赋值为1,如果存在,就把它的值+1。判断第二个值在obj中是否存在…一次类推.
var arr = ['a','b','a','a','b','a'];
var obj = {};
for(var i=0; i<arr.length; i++){
if( obj[arr[i]] ){
obj[arr[i]]++;
} else {
obj[arr[i]] = 1;
}
}
console.log(obj);//{a:4, b:2},得到的是a和b在数组中的重复个数
var newArr = [];
for(var key in obj){
newArr.push(key);
}
console.log(newArr); //[a,b]
6. 冒泡排序 和 比较排序
(1)冒泡排序:依次对数组中相邻数组进行比较。如果第一个比第二个大,就交换他们两个。
var arr = [12,9,6,8,3,4];
for(j = 0; j<arr.length-1; j++){
for(var i = 0; i<arr.length-1-j; i++){
if(arr[i] > arr[i+1]){
var temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
(2)比较排序:将第一位依次与后面的元素相比较,得到最小值,与第一位交换,再用第二位依次与后面的元素相比较,得到最小值,再与第二位交换…;
var arr = [3,1,2,4,6,9];
for(var i = 0;i<arr.length; i++){
var min = arr[i];//假设为最小值
var minIndex = i;//最小值的index
for(var j = i+1; j<arr.length; j++){ //i与后面所有的值做比较
if(min > arr[j]){
min = arr[j];
minIndex = j;
}
}
arr[minIndex] = arr[i];
arr[i] = min
}
console.log(arr);
二、对象
- 存储数据的载体称为变量,在对象中称为属性;
- 功能实现的载体称为函数,在对象中称为方法;
- 当只操作对象进行编程的时候,称为“面向对象编程”。
- 对象: 其实就是一种类型,即 引用类型。对象的值就是引用类型的实例。
在 ECMAScript 中引用类型是一种数据结构,用于将数据和功能组织在一起,它也常被称为“类”。- 对象的组成: 由 属性(键、key) 和 属性值(值、value) 组成;
- 作用:
(1)储存数据;(2)用来编程;
1. 书写规则:
(1)属性可以直接写,类似于变量名;
(2)属性值可以是任意数据;
(3)键和值之间用 “:
” 连接;
(4)没对属性之间用“,
”隔开。
- 对象的值可以是数字、字符、布尔值、undefined、null、对象、数组、函数(函数在对象中叫做 “方法”)
var obj = { num: 1, str: "hello", bool: true, und: undefined, nul: null, obj: {}, arr: [], fn: function(){ console.log(1); } }
2. 创建对象
所有对象都不相等,但是对象身上的属性可以相等;
(1)字面量方式创建:var obj = {};
(2)构造函数的方式创建:var obj = new Object();
-
构造函数:
new
,用来执行(构造)函数; -
构造函数的特点 :
(1)所有通过 new 调用的函数,不管有没有返回值,都会得到一个函数的同名对象,每次 new 得到的不是同一个;(2)构造函数只会产生对象,构造函数是用来构造对象的函数(不能用
ypeof
来检查数据类型。);function fn(){ console.log(1) } var a = new fn(); var b = new fn(); console.log(a);//fn {} console.log(b);//fn {} console.log(a == b);//false
-
内部用this 来构造属性和方法
function Person() { this.name="hxl"; this.age=18; this.sayHi=function() { alert("Hi") } } var a = new Person(); console.log(a);//Person {name: "hxl", age: 18, sayHi: ƒ}
3. 操作属性值
(1)获取:
① 通过 “.
” 拿到对象中的值;也可以使用 obj["属性名"]
,注意要加双引号;
② 当 i 是变量时,我们不能用 obj.i
去访问,而要用 obj[i]
;
③ 获取一个对象中不存在的属性时,它的属性值为 undefined
。
var obj = {
"a":1,
"b":"hello",
"c":true,
"d":function(){
console.log("haha");
},
"e":function(){
return {
fn:function(){console.log(111);}
}
}
};
//两种获取方式:
console.log(obj.a);//1
console.log(obj["a"]);//1 此处若不加双引号,意味着 a 是一个变量
console.log(obj["" + "a"]);//1 用 [] 的方式获取,里面还可以对变量进行拼接
//获取和调用对象中的函数
console.log(obj.d); //f (){console.log("haha");}
console.log(obj.d()); //haha
console.log(obj.e);//f (){return{ fn:function(){console.log(111);} }}
console.log(obj.e());//{fn:f}
console.log(obj.e().fn);//f (){cosnole.log(111);}
console.log(obj.e().fn());//111
//获取对象中不存在的属性名
console.log(obj.x); //undefined
(2)改值: obj.c = false;
4. 操作属性
(1)赋值:
① 直接赋值:var obj = {"a":1,"b":2};
;
② 变量赋值:
var obj = {};
obj.a = 20;
console.log(obj)//{a:20}
obj.fn = function(){
console.log(1);
}
console.log(obj);//{a:20,fn:f}
(2)删除对象中的某个属性:delete 对象.属性名;
var obj = {
name: "admin",
age: 18,
sex: "保密",
height: "180cm",
weight: "70KG",
like: ["read","sport","wirte"]
}
delete obj.like;
console.log(obj); //{name: "admin", age: 18, sex: "保密", height: "180cm", weight: "70KG"}
5. 对象的遍历 for-in
(1)for-in
用于非数组对象的遍历,常用于对象的遍历。
因为 obj.length 得到的是 undefined,所以普通的 for()
对 对象 没有用。
枚举: for-in 循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作,这种循环也称“枚举”。
var obj = {
name:"hxl",
age:20,
show:function(){
console.log("hello")
},
skill:"编程"
};
for(var i in obj){
console.log(i);//name age show skill
console.log(obj.i);//undefined undefined undefined undefined
//注意:
//原因: i 不是 obj 身上的属性,这里的 i 只是一个变量。
//当 i 是变量时,我们不能用 obj.i 去访问,而要用 obj[i]
console.log(obj[i]);//hxl 20 f (){console.log("hello")} 编程
}
(2)Object
:适用于 所有可枚举属性的 对象(包括字符串)。
① Object.keys():返回值是一个由原对象的 key/键/属性名
组成的新数组 。
- 传入普通数组,返回
索引
。var arr = ['a', 'b', 'c']; console.log(Object.keys(arr)); // ['0', '1', '2'] //传入对象,返回 键/属性名 var obj = { a: 'alive', b: 'bike', c: 'color' }; console.log( Object.keys(obj) ); // ['a', 'b', 'c']
- 传入对象,返回
键/属性名
。var obj = { a: 'alive', b: 'bike', c: 'color' }; console.log( Object.keys(obj) ); // ['a', 'b', 'c']
② Object.values():返回值是一个由原对象的 value/值/属性值
组成的新数组 。
const obj = { id:1, name:'zhangsan', age:18 }
console.log(Object.values(obj)); // ["1", "zhangsan", "18"]
- 补充:
Object.assign({}, 对象1, 对象2, 对象3)
合并两个或多个对象,返回一个新对象,不修改原对象。var obj1 = {a:1, b:2}; var obj2 = {c:3, d:4}; console.log(Object.assign({}, obj1, obj2); // {a:1, b:2, c:3, d:4}
6. 深浅拷贝
(1)值传递: 在拷贝的时候,拷贝的是值;
var a = 10;
var b = a;
console.log(a, b); //10 10
b = 20;
console.log(a, b); //10 20
(2)引用传递: 在拷贝的时候,拷贝的是指针(内存地址);
var obj1 = {"name":"admin"};
var obj2 = obj1;
console.log(obj1, obj2);//{name: "admin"} {name: "admin"}
obj2.name = "hxl";
console.log(obj1, obj2);//{name: "hxl"} {name: "hxl"}
(3)对象的深浅拷贝
- 浅拷贝(直接复制,数组和对象): 只拷贝内存地址,当修改拷贝之后的数据时,会影响原数据;引用传递
对象本身是引用传递,浅拷贝。 - 深拷贝: 不拷贝内存地址,只拷贝值,当修改拷贝之后的数据时,不会影响原数据。值传递
(4)浅拷贝 转换为 深拷贝:(常使用深拷贝)
① 整个赋值:
var obj1 = {"name":"hxl"};
var obj2 = obj1;
obj2 = {"name":"zjx"};
console.log(obj1);//{name: "hxl"}
console.log(obj2);//{name: "zjx"}
//或者 相比上面的方法,建议
var obj1 = {"name":"hxl"};
var obj2 = {}; //给自己一个存储空间
obj2.name = obj1.name;
obj2.name = "root";
console.log(obj1); //{name: "hxl"}
console.log(obj2); //{name: "root"}
② 当对象有多个属性和属性值时:
var obj1 = {name:"admin",age:18};
var obj2 = {};
for(var i in obj1){
obj2[i] = obj1[i];
}
obj2.name = "root";
console.log(obj1); //{name: "admin", age: 18}
console.log(obj2); //{name: "root", age: 18}
③ 当对象有多个属性和属性值时,属性值又是对象:
使用
JSON.stringify
将数据转换成字符,再用JSON.parse
转换成对象。
this.labelListData = JSON.parse(JSON.stringify(this.editLabelList));
- 这种情况在项目中会出现在——从接口获取的数据同时赋值给两个变量,改变其中一个变量时,另一个变量的值也会改变。
7. 基础类型和引用类型
基础类型都是值传递,引用类型都是引用传递。
(1)值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(ES6 引入了一种新的原始数据类型,表示独一无二的值)。
(2)引用数据类型:对象(Object)、数组(Array)、函数(Function)。
三、this
- this 是一个指针、变量、对象。表示当前函数所在的执行上下文空间(即当前的执行环境);
- 面向对象语言中 this 表示当前对象的一个引用,但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
- this 指向问题:
(1)在 js 中,全局的变量和函数,全部属于window
,this 指向window
。
(2)在方法中,this
表示该方法所属的对象。
(3)在函数中,this
会指向window
,但在严格模式下,函数中的 this 会指向undefined
;
(4)在事件中,this
表示接收事件的元素,即接收事件的 HTML 元素。
1. 在 js 中,全局的变量和函数,全部属于 window。
var a = this;
console.log(a, window);
2. 在方法中,this 表示该方法所属的对象。
在对象方法中, this 指向调用它所在方法的对象。
//this 表示 person 对象。fullName方法所属的对象就是 person,this.firstName相当于person.firstName
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
console.log( person.fullName() ); //John Doe
3. 在函数中:在函数中会生成一个区域,也叫做作用域;除此之外,在函数中还存在另外一个东西——this
;
(1) 在函数中,函数的所属者默认绑定到 this 上,在浏览器中,window 就是该全局对象。回调函数中的 this 也指向window。
-
普通函数
function myFunction() { return this; } console.log(myFunction())
-
回调函数:回调函数就是把一个函数作为参数 传递给另一个函数。
var obj = { name: "admin", show: function (fn) { console.log(this); //指向obj fn(); } } obj.show( function(){ //obj.show中的这个以函数为参数的函数就是“回调函数” console.log(this); //指向window })
其实拆分出来,相当于:
var obj = { name: "admin", show: function () { console.log(this); //指向obj function fn(){ conosle.log(this); //指向fn,fn属于window } fn(); //window.fn(); } } obj.show();
(2)严格模式下函数是没有绑定到 this 上,这时候 this 是 undefined。
function myFunction() {
"user strict";
return this;
}
console.log(myFunction()); //undefined
4. 在事件中,this 表示接收事件的元素。
在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素。
<button onclick="this.style.display='none'">
点我后我就消失了
</button>
总结:
-
观察一个函数或变量,看前面有没有对象,如果有对象,那么就属于这个对象,如果没有就属于window。
-
this 指向的必须是一个对象,如果不是对象,会强行当成 一个对象;
-
call() 和 apply() 方法可以将 this 引用到任何对象。