学习笔记3

33 阅读10分钟

对象

全局对象

程序所在的宿主环境一般会为其提供一个全局对象,而所谓的全局变量只是全局对象的属性而已。例如当宿主环境为浏览器时,全局对象为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
  • 错误类对象
  1. Object

Object是所有对象的父级对象,所有对象都继承于Object。

一个“空”对象中,还是会有部分属性和方法,比如

  • constructor:返回构造器函数的引用
  • toString():返回对象的描述字符串
  • valueof():返回对象的单值描述信息,通常返回对象本身。
var o = new Object();
>o.toString(); //在某些需要用字符串来表示对象时会用到,比如字符串拼接,alert方法
>'[object Object]'
>o.valueof();//所有对象共有的方法
>{} 
  1. 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] }
  1. 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 3Array.prototype.find //返回第一个符合条件的元素
  Array.prototype.findIndex //返回第一个符合条件的元素的索引
>let arr = [1,2,3]
>arr.find(n => n>1)
>2
>arr.findIndex(n => n>1)
>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方法,因为它已经被覆写了
​
这个用法还能用在argumentsDOM元素上

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;
    }
};