数据类型:
6种基本数据类型:
包装对象
理解:基本类型String/Number/Boolean是没有属性的,但有对应的包装对象String/Number/Boolean,当对其进行访问和设置属性操作时,js会将其临时转换为对应的包装对象类型String/Number/Boolean,这样就可以访问或设置属性了。然后其属性会被销毁。
如下:
var a = “string”; //基础类型
alert(a.length); //6,访问length属性时a被转换为包装对象类型
a.t = 3;//添加t属性,这时a被转换为包装对象类型
alert(a.t); //undefined,由于上面的操作已完成,临时对象被销毁,a是基础类型,没有属性
类型检测方法:
typeof
返回字符串,适合函数(function)对象和基本类型的判断检测,遇到null失效1
2
3
4
5
6
7
8typeof 100 "number"//返回字符串number
typeof true "boolean"
typeof function "function"
typeof (undefined) "undefined"
typeof new Object() "object"
typeof [1,2] "object"//没有经过特殊处理
typeof NaN "number"
typeof null "object"//兼容问题
instanceof
:适用于对象类型,基于原型链来判断类型,也可以检测原生对象
obj instanceof Object//基于原型链
会判断左操作数在原型链上是否有右边构造函数的prototype属性
任何一个构造函数都有一个prototype属性
不同window或iframe间的对象类型检测不能使用instanceof
Object.prototype.toString
遇到null,undefiend失效
Object.prototype.toString.apply([]);===”[object Array]”//判断数组
constructor
任何一个对象都有一个constructor属性,指向构造这个对象的构造器或者构造函数,可以被改写。
duck type
比如不知道这个是不是数组,可以判断他的特征:length数字,是否有join,push等等
任务:arraysSimilar函数,实现判断传入的两个数组是否相似。具体需求:
- 数组中的成员类型相同,顺序可以不同。例如[1, true] 与 [false, 2]是相似的。
- 数组的长度一致。
- 类型的判断范围,需要区分:String, Boolean, Number, undefined, null, 函数,日期, window.
当以上全部满足,则返回”判定结果:通过”,否则返回”判定结果:不通过”。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function type(a){
return Object.prototype.toString.apply(a); //hack ie678
}
function arraysSimilar(arr1, arr2){
if(!Array.isArray(arr1) || !Array.isArray(arr2) ||arr1.length!=arr2.length){return false;}
var arr3=[];
var arr4=[];
var x;
for(var i in arr1){
arr3.push(type(arr1[i]));
arr4.push(type(arr2[i]));
}
if(arr3.sort().toString()==arr4.sort().toString()){
return true;
}else{
return false;
}
}
表达式与运算符
属性访问表达式
var o = {x : 1};
o.x
o[‘x’]
val = +val;
实际上就是利用一元+操作符的特性(会尝试转换为数字),来隐式将一个变量转换为数字类型(number)。
例如:
如果val是”123”
+”123”; // 输出123,类型是number,而不再是string
,运算符:
var val = (1, 2, 3); // val = 3
运算符 delete
1 | var obj = {x : 1}; |
运算符 void
1 | void 0 // undefined |
运算符优先级
语句
block:
没有块级作用域1
2
3
4
5
6
7
8
9
10
11// 下面两种写法相等
for (var i = 0; i < 10; i++) {
var str = "hi";
console.log(str);
}
var i = 0
for (; i < 10; i++) {
var str = "hi";
console.log(str);
}
var
如下例,b未定义,为全局变量,a为局部变量。1
2
3
4
5
6
7function foo() {
var a = b = 1;
}
foo();
console.log(typeof a); // ‘undefined’
console.log(typeof b); // ‘number’
try catch语句
1 | try { |
for…in
- 顺序不确定
- enumerable为false时不会出现
- for in对象属性时受原型链影响
1
2
3
4
5var p;
var obj = {x : 1, y: 2}
for (p in obj) {
}
with语句
- 让JS引擎优化更难
- 可读性差
- 可被变量定义代替
- 严格模式下被禁用
1
2
3
4
5
6
7
8
9
10with ({x : 1}) {
console.log(x);
} //输出1
with (document.forms[0]) {
console.log(name.value);
}
//等价于:
var form = document.forms[0];
console.log(form.name.value);
严格模式
严格模式是一种特殊的执行模式,
它修复了部分语言上的不足,提供更强的错误检查,并增强安全性。1
2
3
4
5
6
7
8function func() {
;
}
//或者如下格式:
;
function func() {
}
‘use strict’;指令并不一定要在第一行出现的,之前也可以有其它指令(字符串)。
但是不允许有其它语句,如变量声明、赋值等。
例如下面例子中:1
2
3
4
5!function() {
'abc';
'use strict';
console.log(this === undefined ? "strict" : "not strict");
}();
上面的use strict前面有abc,仍将进入严格模式,下面的不会进入严格模式。1
2
3
4
5!function() {
var a;
'use strict';
console.log(this === undefined ? "strict" : "not strict");
}();
严格模式与普通模式区别:
- 不允许用with
- 所有变量必须声明, 赋值给未声明的变量报错,而不是隐式创建全局变量。
- eval中的代码不能创建eval所在作用域下的变量、函数。而是为eval单独创建一个作用域,并在eval返回时丢弃。
- 函数中的特殊对象arguments是静态副本,而不像非严格模式那样,修改arguments或修改参数变量会相互影响。
- 删除configurable=false的属性时报错,而不是忽略
- 禁止八进制字面量,如010 (八进制的8)
- eval, arguments变为关键字,不可作为变量名、函数名等
- 一般函数调用时(不是对象的方法调用,也不使用apply/call/bind等修改this)this指向null,而不是全局对象。
- 若使用apply/call,当传入null或undefined时,this将指向null或undefined,而不是全局对象。
- 试图修改不可写属性(writable=false),在不可扩展的对象上添加属性时报TypeError,而不是忽略。
- arguments.caller, arguments.callee被禁用
对象
对象中包含一系列属性,这些属性是无序的。
每个属性都有一个字符串key和对应的value。1
2
3
4
5
6
7
8var obj = {};
obj[1] = 1; //此时obj={1:1}
obj['1'] = 2;//替换上一个属性值
obj; // Object {1: 2}
obj[{}] = true;
obj[{x : 1}] = true;
obj; // Object {1: 2, [object Object]: true}
对象结构
对象创建
三种方法:
1、对象字面量1
2
3
4
5
6
7
8var obj2 = {
x : 1,
y : 2,
o : {
z : 3,
n : 4
}
};
2、new/原型链1
2
3
4
5
6
7
8
9
10function foo(){}
foo.prototype.z = 3;
var obj =new foo();
obj.y = 2;
obj.x = 1;
obj.toString //结果为:function toString() { [native code] }
typeof obj.toString; //结果为:function
'z' in obj; // true, in语句时,对象属性会受原型链影响。
obj.hasOwnProperty('z'); // false
3、Object.create1
2
3
4
5
6
7var obj = Object.create({x : 1});
obj.x // 1
typeof obj.toString // "function"
obj.hasOwnProperty('x');// false
var obj = Object.create(null);
obj.toString // undefined
属性操作
属性检测
1 | Object.defineProperty(cat, 'price', {enumerable : false, value : 1000}); |
属性枚举
1 | var o = {x : 1, y : 2, z : 3}; |
get/set –读写属性的另一种方法
1 | var man = { |
get/set与原型链
1 | //通过new创建对象 |
属性标签
属性权限设置
Object.getOwnPropertyDescriptor(obj,’key’):读取对象obj的key权限1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28Object.getOwnPropertyDescriptor({pro : true}, 'pro');
// Object {value: true, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined
//通过Object.defineProperty(obj,'key')可以设置属性权限
var person = {};
Object.defineProperty(person, 'name', {
configurable : false,
writable : false,
enumerable : true,
value : "Bosn Ma"
});
person.name; // Bosn Ma
person.name = 1;
person.name; // still Bosn Ma
delete person.name; // false
//通过Object.defineProperty(obj,{key1:{value:},key2:{value:},})可以设置多个属性权限
Object.defineProperties(person, {
title : {value : 'fe', enumerable : true},
corp : {value : 'BABA', enumerable : true},
salary : {value : 50000, enumerable : true, writable : true}
});
Object.getOwnPropertyDescriptor(person, 'salary');
// Object {value: 50000, writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(person, 'corp');
// Object {value: "BABA", writable: false, enumerable: true, configurable: false}
对象标签
- [[proto]]
- [[class]]
- [[extensible]]
class标签
toString = Object.prototype.toString; 1
2
3
4
5
6
7
8
9
10function getType(o){return toString.call(o).slice(8,-1);};
toString.call(null); // "[object Null]"
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(1); // "Number"
getType(new Number(1)); // "Number"
typeof new Number(1); // "object"
getType(true); // "Boolean"
getType(new Boolean(true)); // "Boolean"
extensible标签
1 | var obj = {x : 1, y : 2}; |
对象序列化方法
1 | var obj = {x : 1, y : true, z : [1, 2, 3], nullVal : null}; |
其他方法
1 | var obj = {x:1, y:2}; |
数组
数组元素增删
添加数组元素
1 | var arr = []; |
删除数组元素–delete/pop()/shift()
1 | // delete方法 |
稀疏数组
稀疏数组是不含有从0开始的连续索引。一般length属性值比实际元素个数大。
如果那个位置有值的话用in判断就返回true,反之则返回false。1
2
3
4
5
6
7
8
9
10
11
12var arr1 = [undefined];
var arr2 = new Array(1);
0 in arr1; // true
0 in arr2; // false
arr1.length = 100;
arr1[99] = 123;
99 in arr1; // true
98 in arr1; // false, 虽然通过arr[99]使得数组长度变为100,但JavaScript并不会自动创建从0 ~ 98的其它Key。
这就是稀疏数组。
var arr = [,,];
0 in arr; // false
数组方法
Array.prototype.join–将数组转为字符串
1 | var arr = [1, 2, 3]; |
Array.prototype.reverse–将数组逆序(原数组被修改)
1 | var arr = [1, 2, 3]; |
Array.prototype.sort–数组排序(原数组被修改)
1 | var arr = ["a", "d", "c", "b"]; |
Array.prototype.concat–数组合并(原数组未被修改)
1 | var arr = [1, 2, 3]; |
Array.prototype.slice–返回部分数组(原数组未被修改)
1 | var arr = [1, 2, 3, 4, 5]; |
Array.prototype.splice–数组拼接(原数组被修改)
1 | var arr = [1, 2, 3, 4, 5]; |
Array.prototype.forEach–数组遍历
1 | var arr = [1, 2, 3, 4, 5]; |
Array.prototype.map–数组映射(原数组未被修改)
1 | var arr = [1, 2, 3]; |
Array.prototype.filter–数组过滤(原数组未被修改)
1 | var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
Array.prototype.every & some–数组判断
1 | var arr = [1, 2, 3, 4, 5]; |
Array.prototype.reduce&reduceRight–(原数组未被修改)
1 | var arr = [1, 2, 3]; |
Array.prototype.indexOf&lastIndexOf–数组检索
1 | var arr = [1, 2, 3, 2, 1]; |
Array.isArray–判断是否为数组
1 | Array.isArray([]); // true |
数组与一般对象区别:
相同点:
都可以继承
数组是对象,对象不一定是数组
都可以当做对象添加删除属性
不同点:
数组自动更新length
按索引访问数组常常比访问一般对象属性明显迅速。
数组对象继承Array.prototype上的大量数组操作方法