首先,为什么定义一个数值类型可以使用tostring方法,实际上js完成了装箱和拆箱的操作
所谓装箱,就是把基本数据类型转换为对应的引用类型的过程。而拆箱与装箱相反,即把引用类型转换为基本的数据类型。
当我们使用一个基本数据类型,它不是对象,而可以使用原型方法。实际上它经历了:
- 创建一个 Number 类型的实例
- 在实例上调用 toFixed 方法
- 销毁这个实例
当你创建一个数值类型,可以
var num1 = 123;
var num2 = Number(123);
var num3 = new Number(123);
console.log(typeof num2); //number
console.log(typeof num3); //object
console.log(typeof num3.valueOf()); //number
再比如
var dog1 = Animal('xiaobai');
var dog2 = new Animal('xiaohei');
console.log(dog1);
console.log(dog2);
后者输出结果直接指出数据类型
前者相当于调用函数,后者相当于创建函数,概念上有很大区别
1.js创建对象的方式
工厂模式
工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系
// 工厂模式
function Dog(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
return obj;
}
var d1 = Dog('xiaobai',2);
var d2 = Dog('xiaohei',1);
console.log(d1);
console.log(d2.name);
构造函数模式
js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此我们可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建
//构造函数方式创建对象
function Dog(name,age){
this.name = name;
this.age = age;
// this.sayName = function(){
// console.log(this.name);
// }//每一次创建对象时都会去创建一个函数
}
function sayName(){
console.log(this.name);
}
//我们可以把函数写在全局解决问题
// 但是这样做函数的封装性很差
var d1 = new Dog('xiaobai',2);
var d2 = new Dog('xiaohei',1);
console.log(d1);
console.log(d2.name);
d2.sayName();
原型模式
因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此我们可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例
//原型模式
function Dog(){}
//在prototype中定义的属性和方法,所有的实例对象都共享
Dog.prototype.name="xiaobai";
Dog.prototype.age=2;
Dog.prototype.sayName = function(){
console.log(this.name);
}
var dog1 = new Dog();
dog1.name = 'zahngsan';
console.log(dog1.name);
混合模式
第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此我们可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,因为使用了两种不同的模式,所以对于代码的封装性不够好。
//混合模式
//es5中比较完美的方法
function Dog(name,age){
this.name = name;
this.age = age;
this.arr = [];//这里是重复创建的所以不会出现影响
}
Dog.prototype.sayName = function(){
console.log(this.name);
}
var d1 = new Dog('xiaobai',2);
var d2 = new Dog('XIAOHEI',1);
2.内置对象的方法
字符串中内置对象的方法
var str1 = 'xiaoming';
var str2 = String('xiaoming');
var str3 = new String('xiaoming');
console.log(str1.length);//字符串的长度
console.log(str1.charAt(0));//返回索引0的那个字符
console.log(str1.charCodeAt(0));//返回给定位置的那个字符编码
console.log(str1.indexOf('a'));//返回给定字符的位置
console.log(str1.lastIndexOf('a'));//返回给定字符的位置(反向查找)
console.log(str1.concat('xiaohong'));//字符串拼接,返回新的字符串
console.log(str1.slice(2,4));//字符串截取ao(start_index,end_index);
console.log(str1.substr(2,2));//字符串截取ao(start_index,length);
console.log(str1.substring(2,4));//字符串截取ao(start_index,end_index);
console.log(str1.trim());//去除某个字符串两侧的空格
console.log(str1.toLowerCase());//将字符串的字母转换为小写
console.log(str1.toUpperCase());//将字符串的字母转换为大写
数学内置对象的方法
console.log(Math.min(2,4,6,2,1,7));//其中最小的那个数
console.log(Math.max(2,4,6,2,1,7));//其中最大的那个数
var num = 10.41;
console.log(Math.ceil(num));//向上取舍11
console.log(Math.floor(num));//向下取舍10
console.log(Math.round(num));//四舍五入10
console.log(parseInt(num));//10
console.log(Math.random());//获取一个0-1的随机数
console.log(Math.ceil(Math.random()*100));//1-100
console.log(Math.PI);//圆周率
日期对象的方法
var date = new Date();
console.log(date.getFullYear()); //返回2020,2020年
console.log(date.getMonth()); //月 0-11
console.log(date.getDate()); //返回日 1-31
console.log(date.getHours()); //返回小时0-23
console.log(date.getMinutes()); //分钟0-59
console.log(date.getSeconds()); //秒0-59
console.log(date.getDay()); //3 星期3
console.log(date.getMilliseconds());//毫秒
console.log(date.getTime()); //时间戳
console.log(date.toString()); //时间
console.log(date.toDateString()); //日期
console.log(date.toTimeString()); //时间