判断类型
- typeof 返回的值都是字符串: number string boolean object(引用类型) undefined function
typeof(null) ==> object
- instanceof 判断一个对象是否由某个构造函数构造
var array = [];
array instanceof Array; // ture
- 通过 toString() 判断
Object.prototype.toString.call([]); // [object Array]
Object.prototype.toString.call({}); // [object Object]
Object.prototype.toString.call(10); // [object Number]
- constructor 判断对象的构造函数
var arr = [];
var obj = {};
console.log(arr.constructor);
console.log(obj.constructor);
// 封装一个类型判断的方法
function type(target) {
if (target === null) {
return 'null';
}
if (typeof(target) == 'object') {
return Object.prototype.toString.call(target);
} else {
return typeof(target);
}
}
构造函数内部原理
- 在函数体最前面隐式的创建
this = {}
,this放在AO中。 - 执行
this.xxx = xxx;
- 隐式的返回
this
对象
// 简单模拟构造函数
function Dog(name, breed) {
var that = {
// __proto__ : Dog.prototype;
};
that.name = name;
that.breed = breed;
return that;
}
var wangcai = Dog('wangcai', 'ShibaInu');
var laifu = Dog('laifu', 'TuGou');
我们可以在构造函数中显示返回引用值return {};
,但不能显示的返回原始值return 1;
无效。
function Dog(name, breed) {
this.name = name;
this.breed = breed;
return {}; // 会返回一个空对象
return 10; // 无效,会正常的隐式返回this
}
var wangcai = new Dog('wangcai', 'ShibaInu');
var laifu = new Dog('laifu', 'TuGou');
包装类
- 原始值是没有属性和方法的,只有引用值才有。
- 数字、字符串和布尔值分为原始值和对象两种类型。
var num1 = 123;
var mum2 = new Number(123); // 通过构造函数生成的是一个对象
console.log(num1);
console.log(num2);
num1.abc = 'abc';
num2.abc = 'abc';
console.log(num1.abc); // undefined
console.log(num2.abc); // abc
var str = 'abc';
str.length = 100;
console.log(str.length); // 3,length不能更改
str.abc = 'abc';
console.log(str.abc); // undefined
// 包装类
var num = 123;
num.len = 3;
// new Number(123).len = 3;
// delete 对象
console.log(num.len); // undefined
// new Number(123).len
// 又new了一个新的不同的对象
// 包装类
var str = 'abc';
str.length = 100;
// new String('abc').length = 100;
// delete
console.log(str); //abc
console.log(str.length); // 3
// new String('abc').length
命名空间
-
管理变量,防止污染全局,适用于模块化开发。
- 开发中使用闭包,封装一个私有变量,不会污染全局
var name = 'aaa'; var init = (function () { var name = 'bbb'; function callName() { console.log(name); } return function () { callName(); } }()); inti();
- 使用
with
语法(es5严格模式不能使用)
var org = { department1 : { staff1 : { name : 'aaa', age : 10 }, staff2 : { name : 'bbb' } }, department2 : { staff1 : { name : 'ccc' } } } with (org.department1.staff1) { // 把代码块的作用域链顶端改变为传入的对象org.department1.staff1 console.log(name); // 'aaa' }
对象的枚举enumeration
for in
: 遍历一个对象的(除Symbol以外的)可枚举属性。hasOwnProperty()
: 判断对象是否包含特定的自身(非继承)属性。
for (var key in object) {
if (object.hasOwnProperty(key)) {
var element = object[key];
// to do
}
}
// JavaScript 并没有保护 hasOwnProperty 属性名,所以可以在Object原型上使用:
// Object.prototype.hasOwnProperty.call(object, key);
in
: 判断指定的属性是否在指定的对象或其原型链中
var obj = { name : 'Libai' }
console.log('name' in obj); // ture
console.log('toString' in obj); // ture
instanceof
: 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链。
A instanceof B 表示 A对象 是否是 B构造函数 构造出来的
// 语法:object instanceof constructor
[] instanceof Array; // ture
[] instanceof Object; // ture
callee
和 caller
注意:ES5严格模式和ES6中不允许使用
function test() {
console.log(arguments.callee);
}
test(); // function test() {...}
// 使用场景:匿名递归函数初始化数据时
var num = (function (n) {
if (n == 1) {
return 1;
}
return n * arguments.callee(n-1);
}(100));
function test() {
demo(); // function test() {...}
}
function demo() {
console.log(demo.caller);
}
拷贝
function deepClone(origin, target) {
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]";
for (var key in origin) {
if (origin.hasOwnProperty(key)) {
// 判断是不是引用类型
if (origin[key] !== null && typeof(origin[key]) == 'object') {
// 判断是数组还是对象
if (toStr.call(origin[key]) == arrStr) {
target[key] = [];
} else {
target[key] = {};
}
// 递归,循环判断引用类型里的值类型
deepClone(origin[key], target[key]);
} else {
// 递归出口,原始值类型拷贝
target[key] = origin[key];
}
}
}
return target;
}
另一种思维:
var obj = {
name: 'asd',
arr: [1,2,[3,4]],
ooo: {
length : 10,
un : null,
abc : [2,2,2]
}
}
var res = JSON.parse(JSON.stringify(obj));
console.log(res);
数组
push
方法重写
Array.prototype.push = function () {
for (var i = 0; i < arguments.length; i ++) {
this[this.length] = arguments[i];
}
return this.length;
}
splice
方法引申
var arr = [1, 2, 3, 5];
// arr.splice(从第几位开始, 截取多少的长度, 在切口处添加新的数据) 改变原数组并返回截取的片段。
arr.splice(3, 0, 4);
// 实现功能:在第3位不截取,只添加4
// 函数内部实现负数参数的兼容
splice = function (pos) {
pos += (pos > 0 ? 0 : this.length);
if (pos >= 0 && pos < this.length) {...}
}
sort
方法
var arr = [1, 3, -1, 10, 9];
// 按照字符编码的顺序
arr.sort(); // [-1, 1, 10, 3, 9]
// 规定排序顺序
arr.sort(sortBy); // 参数是函数,规定排序顺序。
// sortBy函数两个参数,返回正数则交换,返回负数不变
arr.sort(function (a, b) {
// 升序排序
if (a > b) { return 1 }
else { return -1 }
});
arr.sort(function (a, b) {
// 升序排序
return a - b;
// 降序排序
return b - a;
});
// 实现功能:给定一个有序是数组,使其乱序。
arr.sort(function (a, b) {
return Math.random() - 0.5;
});
splice
和slice
splice
: 删除数组元素,并可以添加新的元素。会改变原数组。slice
: 提取字符串的片断成一个新数组。不会改变原数组。- 不填参数可以把类数组转换为数组
join
和split
- 都通过指定的分隔符进行分或隔。
join
: 将一个数组的所有元素连接成一个字符串split
: 把一个字符串分割成字符串数组。
类数组
// 模拟类数组
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"length" : 3,
"push" : Array.prototype.push,
"splice" : Array.prototype.splice
}
console.log(obj);
数组去重
// 在原型链上构造一个数组去重的方法
Array.prototype.unique = function () {
var temp = {};
var arr = [];
for (var i = 0; i<this.length; i ++) {
if (temp[this[i]] === undefined) {
temp[this[i]] = 'abc';
arr.push(this[i]);
}
}
return arr;
}
字符串去重
// 在原型链上构造一个字符串去重的方法(依赖于数组去重)
String.prototype.unique = function () {
var arr = this.split("");
return arr.unique().join("");
}