对象
全局对象
程序所在的宿主环境一般会为其提供一个全局对象,而所谓的全局变量只是全局对象的属性而已。例如当宿主环境为浏览器时,全局对象为window,另外一种获取全局对象的方法是使用this关键字。例如:
>var a = 1;
>window.a;
>1
>this.a;
>1
我们来分析下构造器函数不用new调用时的情况,当不用new 调用时,函数的this指向全局对象,而用new调用时,会创建一个新的全局变量,然后this指向新的变量。所用内建全局函数都可以当作window对象方法调用。
构造器属性
当我们创建一个对象时,同时也赋予了对象一种特殊的属性--构造器函数,这个属性实际上是指向创建该对象的构造器函数的引用.
function Hero(name) {
this.name = name;
}
>var h2 = new Hero('liming');
>h2.constructor;
>function Hero(name) {
this.name = name;
}
构造器属性引用的是一个函数,我们可以利用它来创建一个新的对象,例如:
>var h3 = new h2.constructor('wangwu');
>h3.name;
>'wangwu'
另外如果对象是通过对象文本标识法创建的,那么实际上它就是由内建构造器Object()函数创建的。
instanceof操作符
通过instanceof操作符,我们可以测试一个对象是否有某个指定的构造器函数创建的。例如:
function Hero() {}
>var h = new Hero();
>var o = {};
>h instanceof Hero;
>true;
>o instanceof Object;
>true;
>h instanceof Object;
>true;
返回对象的函数
除了构造器函数,一般的函数我们也可以让它返回一个对象,例如:
function factory(name) {
return {
name : name
}
}
>var o = factory('one');
>o.name
>'one'
>o.constructor;
>function Object() { [native code] }
构造器也可以返回一个特定的对象,例如:
function Test() {
this.a = 1;
return {
b: 2
}
}
> var o = new Test();
>o.a;
>undefined
>o.b;
>2
在这里构造器返回的不再是包含属性a的对象this,而是一个只包含b的对象,这是当返回值为一个对象时才会发生,而如果返回值为非对象类型时,构造器函数将会照常返回this。
而关于对象在构造器中是如何创建出来的,可以想象在进入构造器函数时,首先创建了一个this的对象,最后将返回值设定为this。例如:
function A() {
// var this = {}; //伪代码
this.a = 1;
//return this;
}
传递对象
当我们复制某个对象或者传递对象给函数时,往往传递的都是函数的引用。当我们对引用做任何改动,都会修改到原对象。
例如:
>var orginal = {name: 'a'};
>var copyObj = orginal;
>copyObj.name = 'b';
>copyObj.name;
>'b';
>orginal.name;
>'b';
同样,将对象传递给函数也是同理。
比较对象
当我们用比较操作比较对象时,只用当两个变量的引用值指向同一个对象时才会返回true,否则就算对象中拥有同样的属性也是会返回false。
>var obj1 = {name:'1'};
>var obj2 = {name:'1'};
>obj1 === obj2;
>false
>obj1 == obj2;
>false
>var obj3 = obj1;
>obj3 === obj1;
>true
>obj2 === obj3;
>false
对象属性与类型
对象一般都有若干属性,而每一个属性则拥有其键和类型。某个属性的状态都有这些类型决定,所有的属性都包含以下类型设置值:
- Enumberable(布尔值): 可枚举类型。这一设置定义了对象属性的可枚举性,一般系统内建属性是不可枚举的,而用户自定义属性是可枚举的
- Configurable(布尔值):可设置类型。如果此项被设置false的,则该属性无法被删除或修改。
你可以通过Object.getOwnPropertyDescriptor()方法来获取对象属性的设置项。
let obj = {
age:25
}
Object.getOwnProprtyDescriptor(obj, 'name');
{
"value": 25,
"writable": true,
"enumerable": true,
"configurable": true
}
可以通过Object.defineProperty()方法来配置属性的设置项
let obj = {age:25};
Object.defineProperty(obj, 'age', {configurable: false})
Object.getOwnProprtyDescriptor(obj, 'age');
{
"value": 25,
"writable": true,
"enumerable": true,
"configurable": false
}
ES6对象方法
Object.is
对于一些特殊值,如+0、-0、NaN一类的值使用严格相等运算符的结果会出人意料。
+0 === -0;
>true
NaN===NaN;
>false
//Object.is
Object.is(+0, -0);
>false;
Object.is(NaN, NaN);
>true
解构赋值
对数组解构赋值:
let [a,b] = [1,2];
a=1,b=2
//如果想跳过某一项可以用逗号来占位
对对象解构赋值:
let obj = {
aa: '1',
bb: '2'
}
let {aa, bb} = obj;
aa='1',bb='2'
//还可以进行自定义变量名
let { aa:aa1 } = obj;
aa1='1'
给函数传参的时候也可以使用:
function test(params) {
console.log(params);
}
let obj1 = {
aa: '1',
bb: '2'
}
test({aa, bb} = obj1);
内建对象
内建对象大致可以分为3大类:
- 数据封装类对象:包括Object、Array、Number和String。这些对象代表着javascript中不同数据类型
- 工具类对象:Math、Date和RegExp
- 错误类对象
- Object
Object是所有对象的父级对象,所有对象都继承于Object。
一个“空”对象中,还是会有部分属性和方法,比如
- constructor:返回构造器函数的引用
- toString():返回对象的描述字符串
- valueof():返回对象的单值描述信息,通常返回对象本身。
var o = new Object();
>o.toString(); //在某些需要用字符串来表示对象时会用到,比如字符串拼接,alert方法
>'[object Object]'
>o.valueof();//所有对象共有的方法
>{}
- Array
Array()是一个用于构建数组的内建构造器函数,如:
var a = new Array()
它和数组文本标识法是等效的:
var a = [];
>var a = new Array(1,2,3'four');
>[1,2,3,'four'];
>var b = new Array(5); //当传入参数为一个数字时,构造器会当成需要生成的数组长度,并用undefined填充
>[undefined*5];
//每个数组都会有一个length属性,代表非字符属性的数量;而对象一般没有length属性
>a.length;
>4;
>a.prop = 'a';
>a.length;
>4
//数组的length属性可以被设置,如果设置的length大于数组长度,会用undefined补充,如果小于数组长度,会删除多余的元素
>typeof [1,2,3];
>'object'
// 数组也是对象,所以数组也继承了Object的方法和属性
>a.toString();
>'1,2,3,four'
>a.valueof();
>[1,2,3,'four']
>a.constructor;
>function Array() { [native code] }
- ES6中的数组方法
1) Array.from
// 可以将类数组对象或可枚举值转换为数组
// 类数组对象是值拥有length属性和索引元素的对象,如每个函数都拥有的arguments类数组对象。
>function test(){
console.log(Array.from(arguments))
}
>test(1,2,3);
>[1,2,3]
2) Array.of
// 用来创建数组的方法,与Array构造器不同,Array构造器会因为传入参数个数和类型的不同,导致产生不同的结果,而使用Array.of则不受传入参数类型或个数影响
>let arr1 = Array.of(2);
>[2]
>let arr2 = Array.of('2');
>['2']
3) Array.prototype 方法
// 遍历数组的方法
Array.keys()
>let arr = [1,2,3];
>for(let i of arr.keys()) {
console.log(i);
}
>0 1 2
Array.values()
>for(let i of arr.values()) {
console.log(i);
}
>1 2 3
Array.entries()
>for(let [index, item] of arr.entries()) {
console.log(index, item);
}
>0 1
>1 2
>2 3
Array.prototype.find //返回第一个符合条件的元素
Array.prototype.findIndex //返回第一个符合条件的元素的索引
>let arr = [1,2,3]
>arr.find(n => n>1)
>2
>arr.findIndex(n => n>1)
>1
- 函数
函数对象的属性
constructor属性
// 函数对象中含有constructor属性,其引用的就是Function()这个构造器函数
>function myFunc() {}
>myFunc.constructor
>function Function() { [native code] }
length属性
// 记录函数声明时定义的参数数量
>function myFunc(a,b,c) {}
>myFunc.length
函数对象的方法
所有函数对象都是继承于顶层父对象Object的,所以它也拥有Object对象的方法,例如toString
//调用toString会返回该函数的源码,如果是内建函数则会返回[native code]
>function myFunc(a,b,c) {return a + b + c}
>myFunc.toString()
>'function myFunc(a,b,c) {return a + b + c}'
>parseInt.toString()
>'function parseInt() { [native code] }'
call()与apply()
//每个函数都有这两个方法,可以用他们来请求函数,并传递指定参数,还有一个功能是可以让一个对象借用另一个对象的方法,据为己用
>var obj = {
name: 'lu',
say(who) {
return 'hey ' + who + ', I am a ' + this.name;
}
}
// 现在可以调用obj.say方法
>obj.say('boy');
>'hey boy, I am a lu'
// 现在有另一个对象obj2
>var obj2 = {
name: 'wu'
}
// obj2也适合调用say方法,如果我们想obj2也能调用say方法
>obj.say.call(obj2, 'girls');
>'hey girls, I am a wu';
// call方法,会将say方法中的this绑定到传递的第一个参数上,如果第一个参数为null或者没有传第一个参数,那么默认调用对象为全局对象
// call方法的第二个参数是,传入调用方法的参数
apply()和call()的工作方式基本相同,不同的是传递参数的方式,apply(obj2, ['wu']),apply()需要传递一个数组给调用的方法
判断对象类型
//既然typeof方法对对象和数组都返回object,那么我们可以通过Object的toString方法来判断
Object.prototype.toString.call({});
>'[object Object]'
Object.prototype.toString.calll([]);
>'[object Array]'
// 注意不能使用Array的toString方法,因为它已经被覆写了
这个用法还能用在arguments和DOM元素上
Boolean
Number
可以在未创建Number对象的情况下使用这些方法,在这些例子中,Number对象均在后台被创建和销毁:
>(12345).toExponential();
>1.2345e+4
// toString()
>var n = new Number(255);
>n.toString();
>'255'
>n.toString(10);
>'255'
>n.toString(16);
>'ff'
>(3).toString(2);
>'11'
>(3).toString(10);
>'3'
String
可以通过String()构造器新建String对象,该对象提供文本操作的方法
1.string对象实际上就像是一个字符数组,其中包括用于每个字符的索引属性,以及length属性
>var obj = new String('world');
>typeof obj;
>'object';
>obj[4];
>'d'
>obj.length;
>5
2.基本类型的字符串就不是字符串对象了,不提供任何的属性和方法,但我们可以通过一些方法将基本类型字符串转换成String对象
例如:
>'potato'.length
>6
>'tomato'[0];
>'t'
3.转换成布尔值的区别
>Boolean('');
>false;
>Boolean(new String(''));
>true;
4.不调用new
不使用new调用时,会将参数转换成字符串
>String(1);
>'1'
而如果参数是对象,会相当于调用该对象的toString方法
>String({p:1});
>'[object Object]';
>String([1,2,3]);
>'1,2,3'
Math
Date
Date()是用于创建Date对象的构造器函数,我们创建对象的时候可以传入以下几种参数:
a.无参数: 默认为当天的日期
b.分开传递年,月,日,时间等值
c.一个用于表示日期的字符串
d.一个时间戳值
>new Date()
>new Date('2023 9 13');
>new Date('09 13 2023');
>new Date(2023, 8, 13, 23, 46, 00, 000);
>Wed Sep 13 2023 23:46:00 GMT+0800 (中国标准时间)
Date对象的方法:
1.setMonth: 设置月份
2.getMonth: 读取月份
3.Date.parse('') 将字符串转换成对应的时间戳
4.Date.UTC() 接收包括年份、月份、日期等在内的所有参数,并以此产生一个相应的格林尼治时间标准的时间戳
5.Date.now() === new Date.getTime()
RegExp
// 练习题1: 在String()构造器、不存在的情况下,自定义一个与String()构造器类似的MyString()构造器
function MyString(value) {
const that = this;
this.str = value;
this.length = (function() {
let length = 0;
for(let item of value) {
that[length] = item;
length++;
}
return length;
})();
this.toString = function() {
return this.str + '';
}
this.valueOf = function() {
return this.str;
}
this.charAt = function(index) {
if(Object.is(Number(index), NaN)) {
return this[0];
}
return this[index];
}
this.concat = function(str2) {
return this.str + str2 + '';
}
this.slice = function(start, end) {
let ret = '';
for(let i = start; i<end; i++) {
ret += this[i];
}
return ret;
}
this.split = function(char) {
let arr = [];
let str = '';
for(let i = 0; i<this.length;i++) {
if(this[i] === char) {
arr.push(str);
str = '';
}else {
str += this[i];
}
}
if(!!str) {
arr.push(str);
}
if(arr.lenth===0) {
return Array.of(this.str);
}else {
return arr;
}
}
return this;
}
// 练习题2: 在Array()构造器以及相关的数组文本标识法都不存在的情况下,自定义一个与Array()构造器类似的MyArray()构造器
function MyArray() {
const args = arguments;
this.toString = function() {
let str = '';
for(let i = 0; i<this.length;i++) {
if(i===0) {
str += this[i];
}else {
str += ',' + this[i];
}
}
return str;
};
this.length = arguments.length;
(function(that) {
for(let i = 0;i<that.length; i++) {
that[i] = args[i];
}
this.length
})(this);
this.push =function (str) {
this[this.length] = str;
this.length++;
return this.length;
};
this.pop = function() {
const ret = this[this.length-1];
delete this[this.length-1];
this.length--;
return ret;
};
this.join = function(str1) {
let str2 = '';
for(let i = 0;i<this.length;i++) {
if(i===0) {
str2 += this[i];
}else {
str2 += str1 + this[i]
}
}
return str2;
}
};