使用对象
定义对象
构造对象
var objectName = new functionName(args);
/*
objectName 返回的实例对象
functionName 构造函数,与普通函数基本相同,但是不需要 return 返回值,返回实例对象,在函数内部可以使用 this 预先访问。
*/
下面示例使用不同类型的构造函数定义各种实例:
var o = new Object(); // 定义一个空对象
var a = new Array(); // 定义一个空数组
var f = new Function(); // 定义一个空函数
对象直接量
// 使用对象直接量定义两个对象
var o = {
a: 1,
b: true
}
var o1 = {
"a": 1,
"b": true
}
// 对象属性值可以是任意值
var o = {
a: function() {
return 1;
}
}
// 如果属性值是对象,可以设计嵌套结构的对象
var o = {
a: {
b: 1;
}
}
使用 Object.create()
创建实例对象
ES5
的静态方法,用来定义一个实例对象。该方法可以指定对象的原型和对象的特性。
Object.create(prototype, desciptors);
/*
prototype 必须,指定原型对象,可以为 null
desciptors 可选,包含一个或多个属性描述符的 js 对象
- value 属性值
- writable 默认为 false,设置属性是否可写
- enumerable 默认为 false,设置属性是否可枚举(for/in)
- configurable 默认为 false,设置是否可修改属性特性和删除属性
访问器特性包含两个方法:
- set()
- get()
*/
使用 Object.create
定义一个对象,继承 null
,包含两个可枚举的属性 size
和 shape
,属性值分别为 “large
” 和 “round
"。
var newObj = Object.create(null, { // 继承 null
size: { // 属性名
value: "large", // 属性名
enumerable: true, // 可枚举
},
shape: {
value: "round",
enumerable: true
}
});
console.log(newObj.size);
console.log(newObj.shape);
console.log(Object.getPrototypeOf(newObj)); // null
下面示例使用 Object.create
定义一个与对象直接量具有相同原型的对象。
var obj = Object.create(Object.prototype, { // 继承 Object.prototype 原型对象
x: {
value: undefined, // 属性值
writable: true, // 可写
configurable: true, // 可以配置
enumerable: true // 可以枚举
}
});
console.log("obj.prototype = " + Object.getPrototypeOf(obj)); // obj.prototype = [object Object]
getPrototypeOf()
可以获取原始对象的原型,如果要获取对象的属性描述符,可以使用 Object.getOwnPropertyDescriptor()
函数。
下面示例定义一个对象,使用访问器属性 b
来读写数据属性 a
。
var obj = Object.create(Object.prototype, {
a: {
writable: true,
value: "a"
},
b: {
get: function() {
return this.a;
},
set: function(value) {
this.a = value;
}
}
})
console.log(obj.a); // 'a'
console.log(obj.b); // 'a'
obj.b = 20;
console.log(obj.b); // 20
操作对象
引用对象
var obj = {
x: true,
y: false
}
var obj1 = obj; // 引用对象
console.log(obj1 === obj); // true,说明对象是完全相等
console.log(obj1.x); // true
console.log(obj1.y); // false
复制对象
复制对象就是利用 for/in
遍历对象,然后把每个对象成员赋值给另一个对象。
// 深拷贝
var obj = {
x: true,
y: false
}
var obj1 = {};
for(var i in obj) {
obj1[i] = obj[i];
}
console.log(obj1 === obj); // false 说明两个对象不同
console.log(obj1.x); // true
console.log(obj.x); // true
克隆对象
克隆对象也是一种复制操作,不过它的执行效率更高一些。
封装一个克隆工具
// 封装一个克隆工具
var clone = function(obj) {
function Temp() {}
Temp.prototype = obj;
return new Temp;
}
var obj = {
x: true,
y: false
}
var obj1 = {};
obj1 = clone(obj);
console.log(obj1);
console.log(obj1 === obj); // false
console.log(obj1.x); // true
console.log(obj1.y); // false
销毁对象
把对象的所有引用都设置为 null,可以强制废除对象。
var obj = {
x: true,
y: false
};
obj = null;
操作属性
定义属性
- 直接量定义
var obj = {
x:1,
y:function() {
return this.x + this.x;
}
}
- 点语法定义
var obj = {};
obj.x = 1;
obj.y = function() {
return this.x + this.x;
}
- 使用
Object.defineProperty
使用 Object.defineProperty
函数可以为对象添加属性,或者修改属性。如果指定的属性名在对象中不存在,就执行添加操作,如果在对象中存在,就执行修改操作。
Object.defineProperty(object, propertyname, descriptor);
/*
object:指定要添加或修改属性的对象。可以是 JS 对象或 DOM 对象。
propertyname:要添加的属性名。
descriptor:定义属性的描述符。
返回值为已经修改的对象。
*/
var obj = {};
Object.defineProperty(obj, "x", {
value: 1,
writable: true,
enumerable: true,
configurable: true
});
console.log(obj); // { x:1 }
- 使用
Object.defineProperties
可以一次性定义多个属性。
Object.defineProperties(object, descriptors);
/*
object:对其添加或修改属性的对象,可以是本地对象或是 Dom 对象。
descriptors:包含一个或多个描述符对象。
*/
var obj = {};
Object.defineProperties(obj, {
x: {
value: 1,
writable: true
},
y: {
set: function(x) {
this.x = x;
},
get: function() {
return this.x;
}
}
})
console.log(obj);
obj.y = 10;
console.log(obj.x); // 10
读写属性
- 使用点语法
- 使用中括号语法
- 使用
Object.getOwnPropertyNames
能够返回指定对象的自身属性的名称。
Object.getOwnPropertyNames(object);
/*
object:表示一个对象,返回值为一个数组,其中包含私有属性的名称。
*/
var obj = {
x: 1,
y: 2,
z: 3
}
var arr = Object.getOwnPropertyNames(obj);
console.log(arr); // ["x", "y", "z"]
Object.keys()
仅能回去可枚举的私有属性的名称。
Object.keys(object);
/*
返回值是一个数组,其中包括对象的可枚举属性名称。
*/
Object.getOwnPropertyDescriptor
获取对象属性的描述符。
Object.getOwnPropertyDescriptor(object, propertyname);
/*
object:表示对象
propertyname:表示属性名称
*/
var obj = {
x: 1,
y: 2,
z: 3
}
var des = Object.getOwnPropertyDescriptor(obj, "x");
console.log(des); // {value: 1, writable: true, enumerable: true, configurable: true}
// 重写特性
des.writable = false;
des.value = 100;
console.log(des); // {value: 100, writable: false, enumerable: true, configurable: true}
console.log(obj); // {x: 1, y: 2, z: 3}
// 使用修改后的数据描述符覆盖属性 x
Object.defineProperty(obj, "x", des);
console.log(obj); // {x: 100, y: 2, z: 3}
des = Object.getOwnPropertyDescriptor(obj, "x");
console.log(des); // {value: 100, writable: false, enumerable: true, configurable: true}
删除属性
使用 delete
可以删除对象的属性。
var obj = {x: 1};
delete obj.x;
console.log(obj.x);
使用方法
方法也是函数,当函数被复制给对象的属性,就被称为方法。方法的使用于函数时相同的,唯一的不同点就是方法内常用 this
引用调用对象,其实在普通函数内也有 this
,只不过不常用。
var obj = {}
obj.f = function(n) {
return 10*n;
}
var n = obj.f(5);
console.log(n);
在方法内部 this
总是指向当前调用对象。在不同运行环境中调用对象 obj
的方法 f()
时,该方法的 this
指向不同。
var obj = {
f: function() {
console.log(this); // 访问的是当前对象
}
}
obj.f(); // 此时 this 指向对象 obj
var f1 = obj.f; // 引用对象 obj 的方法 f
f1(); // 此时 this 指向对象 window
属性描述对象
用来描述对象的属性的特性。
- 属性描述对象的结构
属性描述符实际上就是一个对象,包含 6
个属性,可以选择使用:
/*
value 设置属性值,默认为 undefined
writable 设置属性值是否可写,默认为 true
enumerable 设置属性是否可枚举,默认为 true
configurable 设置是否可设置属性特性,默认为 true,如果为 false,将无法删除该属性,不能够修改属性值,也不能够修改属性的属性描述对象。
get 取值函数,默认为 undefined
set 存值函数,默认为 undefined
*/
var obj = {};
Object.defineProperty(obj, 'x', {value: 100});
console.log(obj)
console.log(Object.getOwnPropertyDescriptor(obj, 'x').value); // 100
// 使用 writable 属性禁止修改属性 x
var obj = {};
Object.defineProperty(obj, 'x', {
value: 1,
writable: false, // 重写属性失败,在严格模式下会报错
});
console.log(obj); // {x: 1}
obj.x = 2;
console.log(obj.x); // 1
/*
* enumerable 可以禁止 for/in 语句、Object.keys() 函数、JSON.stringify() 方法遍历访问指定属性,这样可以隐藏属性。
*/
var obj = {};
Object.defineProperty(obj, 'x', {
value: 1,
enumerable: false // 禁止遍历
})
console.log(obj.x); // 1
for(var key in obj) {
console.log(key); // 空
}
console.log(Object.keys(obj)); // []
console.log(JSON.stringify(obj)); // "{}"
/*
* configurable 可以禁止修改属性描述对象当其值为 false 时,value、writable、enumerable 和 configurable 禁止修改,同时禁止删除属性。
**/
var obj = Object.defineProperty({}, 'x', {
configurable: false // 禁止配置
})
obj.x = 5;
console.log(obj.x); // undefined
Object.defineProperty(obj, 'x', {value: 2}); // error
Object.defineProperty(obj, 'x', {writable: true}); // error
Object.defineProperty(obj, 'x', {enumerable: true}); // error
Object.defineProperty(obj, 'x', {configurable: true}); // error
/*
* 当 configurable 为 false 时,如果把 writable = true 改为 false 是允许的。只要 writable 或 configurable 有一个为 true,则 value 也允许修改。
*/
- 访问器
除了点语法 或中括号语法访问属性的 value
外,还可以使用访问器,包括 set
和 get
两个函数。
// 设计对象 obj 的 x 属性值必须为数字,为属性 x 定义了 get 和 set 属性,obj.x 取值时,就会调用 get;赋值时,就会调用 set。
var obj = Object.create(Object.prototype, {
_x: {
value: 1,
writable: true
},
x: {
get: function() {
return this._x;
},
set: function(value) {
if(typeof value != 'number') throw new Error('请输入数字');
this._x = value;
}
}
})
console.log(obj.x); // 1
obj.x = "2"; // Error
// js 也支持一种简写方式。
var obj = {
_x: 1,
get x() {
return this._x;
},
set x(value) {
if(typeof value != 'number') throw new Error('请输入数字');
this._x = value;
}
}
console.log(obj.x); // 1
obj.x = 2;
console.log(obj.x); // 2
/*
get() 不能接收参数
set() 只能接收一个参数
*/
- 操作属性描述对象
属性描述符是一个内部对象,无法直接读写,可以通过下面几个函数进行操作。
/*
* Object.getOwnPropertyDescriptor():可以读出指定对象私有属性和属性描述对象。
* Object.defineProperty():通过定义属性描述符对象来定义或修改一个属性,然后返回修改后的对象。
* Object.defineProperties():可以同时定义多个属性描述对象。
* Object.getOwnPropertyNames():获取对象的所有私有属性。
* Object.keys():获取对象的所有本地可枚举的属性。
* propertyIsEnumerable():对象实例方法,直接调用,判断指定的属性是否枚举。
*/
var obj = Object.create(Object.prototype, {
_x: {
value: 1,
writable: true
},
x: {
configurable: true,
get: function() {
return this._x;
},
set: function() {
if(typeof value != 'number') throw new Error('请输入数字');
this._x = value;
}
}
})
var des = Object.getOwnPropertyDescriptor(obj, "x");
console.log(des); // {enumerable: false, configurable: true, get: ƒ, set: ƒ}
des.set = function(value) { // 重写 set 方法
if(typeof value != 'number' && isNaN(value * 1)) throw new Error('请输入数字');
this._x = value;
}
obj = Object.defineProperty(obj, "x", des);
console.log(obj.x); // 1
obj.x = "2";
console.log(obj.x); // 2
/*
上述方法无法复制属性描述符包含的丰富信息。下面示例先定义一个拓展函数,使用它可以把一个对象的属性以及丰富的信息复制给另一个对象。
*/
function extend(toObj, fromObj) {
for(var property in fromObj) {
if(!fromObj.hasOwnProperty(property)) continue; // 过略掉继承属性
Object.defineProperty(
toObj, // 复制完整的属性信息
property, // 目标对象
Object.getOwnPropertyDescriptor(fromObj, property) // 获取属性描述对象
)
}
return toObj;
}
var obj = {};
obj.x = 1;
extend(obj, {get y() {return 2}});
console.log(obj.y); // 2
- 控制对象状态
JS
提供 3
中方法,用来精确控制一个对象的读写状态,防止对象被改变。
/*
Object.preventExtensions:阻止为对象添加新的属性。
Object.seal:阻止为对象添加新的属性,同时也无法删除旧的属性。等价于把属性描述对象设置为 configurable 属性设置为 false。注意:这种方法不影响修改某个属性的值。
Object.freeze:阻止为一个对象添加新属性、删除旧属性、修改属性值。
*/
// 同时提供了 3 个对应的辅助检查函数
/*
Object.isExtensible:检查一个对象是否允许添加新的属性。
Object.isSealed:检查一个对象是否使用了 Object.seal 方法。
Object.isFrozen:检查一个对象是否使用了 Object.freeze 方法。
*/
var obj1 = {};
console.log(Object.isExtensible(obj1)); // true
Object.preventExtensions(obj1);
console.log(Object.isExtensible(obj1)); // false
var obj2 = {};
console.log(Object.isSealed(obj2)); // false
Object.seal(obj2);
console.log(Object.isSealed(obj2)); // true
var obj3 = {};
console.log(Object.isFrozen(obj3)); // false
Object.seal(obj3);
console.log(Object.isFrozen(obj3)); // true
Object 原型方法
JS
原生提供了 Object 类型对象,其他所有对象都继承自 Object,都是 Object 实例。
- 使用
toString()
// 实例对象与构造函数的 toString 方法返回值是不同的
function F(x, y) {
this.x = x;
this.y = y;
}
var f = new F(1, 2);
console.log(f.toString()); // [object Object]
console.log(F.toString());
/*
function F(x, y) {
this.x = x;
this.y = y;
}
*/
重写 toString
方法,如下,让对象能够返回构造函数的源代码。
function F(x, y) {
this.x = x;
this.y = y;
}
Object.prototype.toString = function() {
return this.constructor.toString();
}
var f = new F(1, 2);
console.log(f.toString());
/*
function F(x, y) {
this.x = x;
this.y = y;
}
*/
- 使用
valueOf()
valueOf
能够返回对象的值。
// Date 对象的 valueOf 方法返回的是当前日期对象的毫秒数
var o = new Date();
console.log(o.toString()); // Thu Jul 29 2021 17:07:01 GMT+0800 (中国标准时间)
console.log(o.valueOf()); // 1627549667354 毫秒数
console.log(Object.prototype.valueOf.apply(o)); // Thu Jul 29 2021 17:08:57 GMT+0800 (中国标准时间)
/*
* 当 String、Number、Boolean 对象具有明显的原始值时,他们的 valueOf 方法会返回合适的原始值。
*/
// 重写 valueOf()
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.valueOf = function() {
return "(" + this.x + "," + this.y + ")";
}
var p = new Point(26, 28);
console.log(p.valueOf()); // (26,28)
console.log(Object.prototype.valueOf.apply(p)); // Point {x: 26, y: 28}
/*
* 下面示例:当获取自定义类型的对象的 p 时,console.log() 会首先调用 valueOf() 方法,而不是 toString() 方法,如果获取该对象的字符串表示,则必须明确调用对象的 toString()
**/
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.valueOf = function() {
return "(" + this.x + "," + this.y + ")";
}
Point.prototype.toString = function() {
return "[object object]";
}
var p = new Point(26, 69);
console.log("typeof p = " + p); // typeof p = (26,69)
console.log("typeof p = " + p.toString()); // typeof p = [object object]
- 检测私有属性
对象属性可以分为两类:私有属性、继承属性(原型属性)。
function F() {
this.name = "私有属性";
}
F.prototype.name = "继承属性";
// 为了判断对象属性的类型,Object 对象预定义了 hasOwnProperty(),该方法可以快速检测属性的类型。
var f = new F();
console.log(f.hasOwnProperty('name')); // true
console.log(f.name); // '私有属性'
下面演示,toString()
方法对于 Date
对象来说是继承属性,但是对于 Date
构造函数的原型对象来说,则是私有属性。
var d = Date;
console.log(d); // function Date()
console.log(d.hasOwnProperty("toString")); // false
var d = Date.prototype;
console.log(d.hasOwnProperty("toString")); // true
演示 hasOwnProperty
方法所能检测的属性范围
var o = {
o1: {
o2: {
name: 1
}
}
};
console.log(o.hasOwnProperty('o1')); // true o1 是 o 的私有属性
console.log(o.hasOwnProperty("o2")); // false o2 不是 o 的私有属性
console.log(o.o1.hasOwnProperty('o2')); // true o2 是 o1 的私有属性
- 检测枚举属性
in
会检查私有属性和原型属性,需要使用 hasOwnProperty
来判断一下。
var person = {
'first-name': 'zhang',
'last-name': 'san',
sayName: function() {
console.log(this['first-name'] + this['last-name'])
}
}
console.log('first-name' in person); // true
console.log(person.hasOwnProperty('first-name')); // true
console.log('toString' in person); // true 检查原型属性
console.log(person.hasOwnProperty('toString')); // false
for...in
用来遍历一个对象中的所有属性名,包括原型属性和私有属性。很多情况下需要过滤掉一些不想要的值。最常用的是使用 hasOwnProperty
方法,也可以使用 typeof
运算符进行排除。
使用 for/in
语句枚举,属性名出现的顺序是不确定的,最好的办法是完全避免使用 for/in
。
对于 Js 对象来说,用户可以使用 for/in
语句遍历一个对象的“可枚举”属性,但并不是所有对象属性都是可枚举的,只有用户自定义的属性和原型属性才允许枚举。
下面的自定义对象 o,使用 for/in
循环可以遍历它的所有私有属性、原型属性,但是 JS 允许的属性只有 a、b、c
function F() {
this.a = 1;
this.b = 2;
}
F.prototype.c = 3;
F.d = 4;
var o = new F();
for(var I in o) {
console.log(I); // a b c
}
为了判断指定的私有属性是否可枚举,Object 对象定义了 propertyIsEnumerable()
方法,该方法的返回值是 true
,则说明指定的私有属性可以枚举,否则不允许枚举。
function F() {
this.a = 1;
this.b = 2;
}
F.prototype.c = 3;
F.d = 4;
var o = new F();
console.log(o.propertyIsEnumerable("a")); // true
console.log(o.propertyIsEnumerable("b")); // true
console.log(o.propertyIsEnumerable("c")); // false 不可枚举
console.log(o.propertyIsEnumerable("d")); // false 不可枚举
var o = F;
console.log(o.propertyIsEnumerable("d")); // true 可以枚举
- 检测原型对象
为自定义函数定义两个原型成员
var f = function() {} // 定义函数
f.prototype = {
a: 1,
b: function () {
return 2;
}
}
console.log(f.prototype.a); // a
console.log(f.prototype.b); // function(){}
当使用 new
就会创建一个实例对象,这个实例对象将继承构造函数的原型对象中的所有属性。
var f = function() {} // 定义函数
f.prototype = {
a: 1,
b: function () {
return 2;
}
}
console.log(f.prototype.a); // a
console.log(f.prototype.b); // function(){}
var o = new f();
console.log(o.a); // 1
console.log(o.b()); // 2
Object
对象定义了 isPrototypeOf()
方法,该方法可以检测一个对象的原型对象。
判断 f.prototype
就是对象 o
的原型对象:
var f = function() {} // 定义函数
f.prototype = {
a: 1,
b: function () {
return 2;
}
}
var o = new f();
var b = f.prototype.isPrototypeOf(o);
console.log(b); // true
下面演示各种特殊对象的原型对象:
- 函数的原型对象可以是
Object.prototype
或者是Function.prototype
var f = function() {}
console.log(Object.prototype.isPrototypeOf(f)); // true
console.log(Function.prototype.isPrototypeOf(f));
Object
和Function
对象的原型对象比较特殊
console.log(Object.prototype.isPrototypeOf(Object)); // true
console.log(Function.prototype.isPrototypeOf(Function)); // true
Object.prototype
和Function.prototype
的原型对象不是Object.prototype
,Function.prototype
的原型对象可以是Function.prototype
,但是Object.prototype
的原型对象绝对不是Function.prototype
。
console.log(Object.prototype.isPrototypeOf(Object.prototype)); // false
console.log(Object.prototype.isPrototypeOf(Function.prototype)); // true
console.log(Function.prototype.isPrototypeOf(Function.prototype)); // false
console.log(Function.prototype.isPrototypeOf(Object.prototype)); // false
Object 静态函数
Object 静态函数就是定义在 Object 对象上的方法,通过 Object 直接调用,不需要实例继承。
- 对象包装函数
Object()
也是一个函数,他可以将任意值转化为对象。如果参数为空,或者为 undefined
和 null
,Object()
将返回一个空对象。
var obj = Object();
// 等同于
var obj = Object(undefined);
var obj = Object(null);
如果参数为数组、对象、函数,则返回原对象,不进行转换。根据这个特性,可以设计一个类型检测函数,专门检测一个值是否为引用型对象。
function isObject(value) {
return value === Object(value);
}
console.log(isObject([])); // true
console.log(isObject(true)); // false
- 对象构造函数
Object()
不仅可以当作工具函数使用,还可以当作构造函数使用。如果使用 new
命令调用 Object()
函数,将创建一个实例对象。例如,下面代码将创建一个新的实例对象。
var obj = new Object();
- 静态函数
Object()
包含很多静态函数:
/*
Object.keys():以数组形式返回参数对象包含的可枚举的私有属性
Object.getOwnPropertyNames():以数组形式返回参数对象包含的私有属性名。
Object.getOwnPropertyDescriptor():获取某个属性的描述对象
Object.defineProperty():通过描述对象,定义某个属性
Object.defineProperties():通过描述对象,定义多个属性
Object.preventExtensions():防止对象扩展
Object.isExtensible():判断对象是否可配置
Object.seal():禁止对象配置
Object.isSealed():判断对象是否可配置
Object.freeze():冻结一个对象
object.isFrozen():判断一个对象是否被冻结
Object.create():返回一个新的对象,并指定原型对象和属性
Object.getPrototypeOf():获取对象的 prototype 对象
*/
案例实战
- 生成指定范围的随机数和字符串
- 获取指定范围的随机数
var getRand = function(min, max) {
return Math.random() * (max - min) + min;
}
console.log(getRand(2, 4));
- 获取指定范围的随机整数
var getRand = function(min, max) {
return parseInt(Math.random() * (max - min)) + min;
}
console.log(getRand(2, 4));
- 获取指定长度的随机字符串
var getRandStr = function(length) {
var _string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 26个大写字母
_string += 'abcdefghijklmnopqrstuvwxyz'; // 26 个小写字母
_string += '0123456789-_'; // 10个数组、下划线、连字符
var _temp = '', _length = _string.length - 1;
for(var i = 0; i < length; i++) {
var n = parseInt(Math.random() * _length);
_temp += _string[n];
}
return _temp;
}
console.log(getRandStr(16));
- 数字取整
-
Math.floor()
:向下取整 -
Math.ceil()
:向上取整 -
Math.round()
:四舍五入
- 设计时间显示牌
var showtime = function() {
var nowdate = new Date();
console.log(nowdate); // Date Sat Jul 31 2021 19:06:08 GMT+0800 (中国标准时间)
var year = nowdate.getFullYear(); // 年
var month = nowdate.getMonth() + 1; // 月
var date = nowdate.getDate(); // 日
var day = nowdate.getDay(); // 星期
var week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var h = nowdate.getHours();
var m = nowdate.getMinutes();
var s = nowdate.getSeconds();
h = checkTime(h);
m = checkTime(m);
s = checkTime(s);
return year + '年' + month + '月' + date + '日' + " " + week[day] + " " + h + ":" + m + ":" + s;
}
var checkTime = function(i) {
if(i < 10) {
i = "0" + i;
}
return i;
}
setInterval(function() {
showtime();
}, 1000)
// 2021年7月31日 星期六 19:12:48
- 设计倒计时
var showtime = function() {
var nowtime = new Date();
var endtime = new Date("2021/8/8");
var lefttime = endtime.getTime() - nowtime.getTime();
var leftd = Math.floor(lefttime / (1000 * 60 * 60 * 24)); // 天数
var lefth = Math.floor(lefttime / (1000 * 60 * 60) % 24); // 小时数
var leftm = Math.floor(lefttime / (1000*60) % 60); // 计算分钟数
var lefts = Math.floor(lefttime / 1000 % 60); // 计算秒数
return leftd + "天" + lefth + ":" + leftm + ":" + lefts;
}
setInterval(function() {
showtime();
}, 1000)