VN-SGG JavaScript 基础(中)

[VN-SGG] JavaScript 基础(中)

JavaScript视频课程笔记【入门到精通】,这只是笔记!!!

主要内容:

  • this,对象,原型对象,垃圾回收,数组;
  • call、apply,arguments,Date,Math,包装类,正则;

this

解析器在调用函数时,每次都会向函数内部传递一个隐含参数,这个隐含参数就是this

  • 浏览器传入的;指向的是个对象-函数执行的上下文对象;
  • 函数调用方式不同,this指向也不同;

function sayName(){
    console.log(this);
}

sayName();//this->window

var obj = {
    name:'hahah',
    sayName:sayName
}
obj.sayName();//this->obj

this一般指向

  • 函数调用:永远指向window;
  • 方法调用:调用方法的那个对象;

创建对象

使用工厂方法创建对象

算是个技巧吧;

都使用了Object的构造函数,返回的对象类型 都是Object类型;

function createObj(name,age,opre){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.opre = opre;
    obj.sayName = function(){
        console.log(this.name);
    }
    return obj;
}

构造函数

构造函数其实就是一个普通的函数,习惯上首字母需要大写;
与普通函数 区别在于 构造函数 需要使用 new来调用;

function Person(){

}
function Dog(){
    
}

var person = new Person();
var dog = new Dog();

构造函数执行流程:

  • 立刻创建一个新的对象;
  • 将新建对象设置为函数中的this;
  • 执行函数中代码;
  • 将新对象,作为返回值返回;

因此 在构造函数中,可以使用this引用新创建的对象;

function Person(name){
    this.name = name || '猴哥';
}

类和对象

  • 使用构造函数创建的对象的类型都是一类的,一般也将一个构造函数称为一个类;
  • 创建的对象,称为类的实例;

可以使用instanceof运算符判断实例类型:

var per1 = new Person();
per1 instanceof Person;//true
per1 instanceof Object;//true

所有实例都是Object类的实例;

对象打印时,除了函数会打印function,其他嗾使object;

this一般指向(+)

  • 函数调用:永远指向window;
  • 方法调用:调用方法的那个对象;
  • 构造函数:新创建的那个对象;

原型对象

为多个对象指定公共函数的问题:

将函数定义在全局作用域,污染了全局作用域的命名空间,而且定义在全局作用域中也很不安全,再起重名函数,易被覆盖;通过这个问题引出原型对象;

原型prototype

在我们所创建的每一个函数时,解析器都会向函数中添加一个属性prototyoe,无论是构造函数还是普通函数;这个属性对应着是一个对象,这个对象就是我们所谓的原型对象;


function Person(){

}
console.log(Person.prototype)

原型对象的作用

  • 普通函数调用时,prototype没啥作用;
  • 构造函数调用时(new Person()),它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象;这个隐含属性可以通过 __proto__来访问(只是访问);
function MyClass(){

}
var mc = new MyClass();
var mc2 = new MyClass();

mc.__proto__ == MyClass.prototype//true
mc2.__proto__ == MyClass.prototype//true

相当于一个公共区域,所有同一个类的实例都可以访问这个原型对象;
可以将对象共有的内容,统一设置到原型对象中;

MyClass.prototype.a = 123;
mc.a;//123

共有的函数也可以放在原型对象中,这样就不会出现本节一开始函数定义在全局的问题了;
以后创建构造函数时,可以将这些对象的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了;

in 和 hasOwnProperty()

  • 使用in检查对象是否包含某个属性时,对象中没有但原型中有,也会返回true;
  • 可以使用对象的hasOwnProperty()方法来检查对象自身是否包含指定属性;
// 只有对象自身中含有该属性时,才会返回true
console.log(mc.hasOwnProperty("age"));

hasOwnProperty从哪来的?

  • 原型对象也是对象,也有原型;当访问一个对象的属性或方法,会先在对象自身中寻找,否则会在对象的原型对象中寻找;
  • 使用hasOwnProperty时,会在自身中找,自身没有的话就在原型中找,原型也没有的话,就在原型的原型中找;直到找到Object对象的原型(值为null);
console.log(mc.hasOwnProperty("hasOwnProperty"));//false 
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));//false 
// ...
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//true 

根原型对象是Object,Object对象没有原型,如果在Object中依然没有找到需要的属性,则返回undefined;

原型链对应着面向对象类的继承链;

toString()

function Person(name,age,gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
}

var per = new Person("猴哥",18,'boy');

console.log(per);// [object Object]

这里打印per对象,实际输出的是对象的toString()方法 的返回值;之所以打印出了“[object Object]”就是因为toString()方法的返回值就是“[object Object]”;

toString()方法定义在Object类中,如果希望实际输出的不是默认的,就可以为对象的原型添加一个toString方法:

Person.prototype.toString = function(){
    return this.name + this.age + this.gender;
}

对象的原型对象 指向 类的原型对象,类的原型对象指向其原型对象的原型对象,如Object(表现为类之间的继承链),Object的原型对象为null;


垃圾回收

什么是垃圾?

var obj = new Object();
obj = null;

obj指针与堆内存的空间断开了链接:

当一个对象没有任何变量或属性对它进行引用,我们就无法操作它,这个对象就变成了垃圾;他们会占用大量内存空间,影响程序运行;

垃圾回收机制:

自动进行垃圾回收,而我们需要做的就是将不再使用的对象设置为null;


数组

对象分类:内建对象、宿主对象、自定义对象;
我们此前接触的主要是自定义对象;
Function、Object,还有Array(数组)都是内建对象;

数组:

  • 也是一个对象;
  • 使用数字索引操作元素;
  • 索引(index):从0开始的整数;
  • 存储性能高于普通对象;
var arr = new Array();
typeof arr;//object

arr[0] = 'a';
arr[1] = 'b';

console.log(arr[0]);
console.log(arr[3]);//undefined

// 获取数组长度 length属性
arr.length;

// 如果索引不连续,,使用length会获取到数组的最大索引+1(尽量不要创建非连续的数组)
// length还可以修改(用的不多)

具体JS对象方法可以查阅JavaScript对象参考手册,详细介绍了JS本地对象、内置对象、BOM对象、DOM对象的属性和方法:

方法 描述
concat() 连接两个或更多的数组,并返回结果。
join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
pop() 删除并返回数组的最后一个元素
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reverse() 颠倒数组中元素的顺序。
shift() 删除并返回数组的第一个元素
slice() 从某个已有的数组返回选定的元素
sort() 对数组的元素进行排序 (默认按照unicode编码,对数字排序也是,可能会得到不正确的结果;可通过传入回调函数自定义排序规则;)
splice() 删除元素,并向数组添加新元素。
toSource() 返回该对象的源代码。
toString() 把数组转换为字符串,并返回结果。
toLocaleString() 把数组转换为本地数组,并返回结果。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
valueOf() 返回数组对象的原始值

数组字面量

//构造函数方式
var arr = new Array(1,2,3,4,5);
//字面量方式
var arr = [1,2,3,4,5];

// 但二者有区别
var arr = new Array(3);//创建一个长度为3的数组
var arr = [3];//创建一个数组,只有一个数是3

数组中的元素可以是任意数据类型:包括对象、函数等;

数组常用方法:

  • push末尾加 pop末尾删
  • unshift开头加 shift开头删

数组遍历

var arr = [1,2,3,4,5,6,7];

// 最简单常用的for循环
for(var i=0; i<arr.length; i++){
    arr[i]
}

// forEach() 支持ie8+,参数是一个回调函数
arr.forEach(function (item,index,array){
    item;//数组元素
    index;//数组索引
    array;//原数组
});

//other

slice()

从某个已有的数组返回选中的元素——切片;

  • arr.slice(start,end);左闭右开区间;
  • arr.slice(start);从start开始直到末尾的所有元素;
  • 如果参数是负值,表示从后往前计算索引,-1表示最后一个元素;

splice()

删除元素并向数组添加新元素;

  • arr.splice(0,2)从第0个位置开始,删除2个元素,返回值是被删除的元素;
  • arr.splice(0,1,'haha')第三个位置及以后,可以传递一些新的元素,这些元素会被自动插入到开始索引(这里是0)的前边;

小练习:数组去重

例子没有写注释,但解决问题也很有意思,仔细品品;

var arr = [1,2,3,2,2,1,3,4,2,5];
for (var i = 0; i < arr.length ; i++){
    for (var j = i + 1; j < arr.length ; j++){
        if(arr[i] == arr[j]){
            arr.splice(j,1);//这种遍历数组过程中 对数据进行删除 在以前接触的语言中 是不允许的
            j--;
        }
    }
}

sort()

对数组的元素进行排序 (默认按照unicode编码,对数字排序也是,可能会得到不正确的结果;可通过传入回调函数自定义排序规则;)

var arr = [2,1,4,3]

arr.sort(function(a,b){
    return a - b;//升序
});

arr.sort(function(a,b){
    return b - a;//降序
});


call和apply

函数也是一个对象,函数对象也有相应的对象方法:call() 和 apply()

fun.call() fun.apply()

  • 默认都会进行函数func调用;
  • 可以将一个对象指定为第一个参数(this指代);此时这个对象将会成为函数执行时的this;

区别:

  • call()方法可以将实参在对象之后一次传递;
  • apply()方法需要将实参封装到一个数组中统一传递;
function fun(a,b){
    console.log(this);
}
var obj = {
    name:'haha'
}
fun.call(obj,'1','2');
fun.apply(obj,['1','2']);

this一般指向(++)

  • 函数调用:永远指向window;
  • 方法调用:调用方法的那个对象;
  • 构造函数:新创建的那个对象;
  • 使用call和apply调用时,this指向指定的那个对象;

arguments

在调用函数时,浏览器每次会传入两个隐含参数:

  • 函数的上下文对象this;
  • 封装实参的对象arguments

arguments是一个类数组对象:

  • 并不是一个数组,可以用arguments instanceof ArrayArray.isArray(arguments)来进行检验;
  • 可以通过索引操作数据,也可以获取长度;
  • 即使不定义形参,也可以通过arguments使用实参;
function fun(){
    console.log(arguments.length);//2
    console.log(arguments.callee == fun);//true
}
fun("hello","world");

callee属性

arguments有一个callee属性,它对应一个对象,就是当前正在执行的函数对象;


Date对象

Date对象也是内建对象的一种,用于表示日期和时间;

var d = new Date();//当前时间

var d1 = new Data("12/30/2020")// 指定日期(是有时区的)
var d1 = new Data("12/30/2020 11:10:30")// 指定时间

d.getDate();//几号
d.getDay();//星期几(0-6,0表示周日)
d.getMonth();//几月(0-11,0表示1月)
d.getFullYear();//哪年

d.getTime();//获取当前对象的时间戳(ms)
Date.now();//获取当前时间戳(利用时间戳可测试代码执行耗时和性能)

Math

Math对象用于执行数学任务。

Math并不是一个构造函数,而是一个工具类;

Math.PI;
Math.abs(1);//计算绝对值
Math.ceil(1.4);//2 (对数进行上舍入)
Math.floor(1.5);//1 (对数进行下舍入)
Math.round(1.5);//2 (对数进行4舍5入)
Math.random();// 0~1之间的随机数(不包括0 和 1)

Math.round(Math.random() * 20);// 0~20之间的随机数(包括0 和 20)
Math.round(Math.random() * 9 + 1);// 1~10之间的随机数(包括1 和 10)

//随机数生成:生成一个x~y之间的随机数
Math.round(Math.random() * (y-x) + x);

Math.max(1,2,3,4,5);//获取多个数中的最值 max/min
Math.pow(x,y);//返回x的y次幂
Math.sqrt(x);//返回数的平方根

包装类

基本数据类型:String Number Boolean Null Undefined
引用数据类型:Object

JS提供了三个包装类:

通过包装类可以将基本数据类型的数据转换为对象;

  • String():构造函数,将基本数据类型字符串装换为String对象
  • Number():构造函数,将基本数据类型数字装换为Number对象
  • Boolean():构造函数,将基本数据类型布尔值装换为Boolean对象
// 使用举例
var num = new Number(3);
console.log(typeof num);//object

var num1 = new Number(3);

num == num1;//false (这里比较的是引用 肯定是false)

平时基本用不到基本数据类型的对象类型,也不会创建它,因为在比较的时候往往会得到不可预料的结果;

方法和属性只能添加到对象中,基本数据类型并没有,但是我们用过的 123.toString()就是包装类的一种使用场景;浏览器会临时使用包装类将其装换为对象(临时但并未保存装换后的对象结果),然后再调用对象的属性和方法;

基于此,String对应的包装类的方法,我们的基本数据类型字符串就可以直接调用;

String对象常用方法

  • 字符串以字符数组的形式保存;
var str = "Hello world!"

str.length;//12 -> 获取字符串长度
str[1];//e

str.charAt(1);//e -> 返回指定位置的字符
str.charCodeAt(1);//101 -> 获取指定位置的字符编码(Unicode 十进制)
String.fromCharCode(101);//e -> 根据字符编码获取字符
String.fromCharCode(0x101);//十六进制表示 -> 根据字符编码获取字符

str.concat('haha');//链接两个或多个字符串,作用和+基本一样
str.indexOf('e');//1 -> 检索字符串中是否含有指定内容:
// -> 有的话 返回第一次出现的索引
// -> 没有的话 返回-1
str.indexOf('e',1);//-1 -> 第二个参数 表示从第几个指定字符开始查找
str.lastIndexOf('e');//1 -> 从后往前找,也支持第二个参数

// martch/replace/search:结合正则使用

str.slice(0,2);//He -> 切片字符串,左闭右开区间;两个参数:开始位置 和结束位置索引
str.slice(1);//省略第二个参数 表示从开始到最后
str.slice(1,-1);// 负数 表示从后往前数

str.substring(0,2);// 基本同slice,不同的是:不可以使用负数的参数;而且如果第二个参数小于第一个参数,会自动调整参数位置(交换)

str.substr(3,2);// 开始位置 和 截取长度(非标准定义的方法)

str.split(' ');//将字符串拆分成数组 与数组的join是相反操作

toLowerCase();//大小写装换 不会影响原字符串
toUpperCase();//大小写装换 不会影响原字符串

正则表达式

正则语法参考我的另一篇《正则校验-我需要的正则表达式知识》

什么是正则表达式?

正则表达式定义的是一套规则,常用语校验字符串或提取;

JS里正则表达式实际上是一个对象:

  • test():使用这个方法可以检测一个字符串是否符合正则,返回布尔值;
  • 匹配模式:
    • i 忽略大小写
    • g 全局匹配模式
// var reg = new RegExp('正则表达式','匹配模式');
var reg = new RegExp('a');//规则:包含a的字符串
var str = 'a';

reg.test(str);//true 严格区分大小写,i模式下 A也能匹配到

字面量创建正则

// var reg = /正则表达式/匹配模式
var reg = /a/i;
reg.test('a');//true

正则语法举例

  • /[ab]/ 包含a或b
  • /[^ab]/ 包含除了a 和 b 以外的其他字符
  • 量词:设置内容出现次数
    • /a{3}/ a出现3次
    • /(ab){3}/ ab出现3次
    • /a{1,3}/ a出现1到3次
    • /a{3,}/ a出现3次以上
    • n+ 至少一次
    • n* 0或多次
    • n? 0或1次
  • /^a/ 以a开头(与在[]中使用意义完全不同)
  • /a$/ 以a结尾
  • /^a$/ 完全匹配 只能是一个a
  • /^a|a$/ 以a开头 或 以a结尾

^$一起使用时,表示完全比配;

转义字符:

使用正则表达式构造函数创建时,对于类似\.的转义需要表示为new RegExp("\\."),表示其参数是字符串'\.';这点与字面量不同;

  • \. .是元字符,其他元字符参考文档
  • \\

其他元字符:

  • \d 数字
  • \D 除了 数字
  • \w 字母 数字
  • \W 除了 字母 数字
  • \s 空格
  • \S 除了 空格
  • \b 单词边界 /\bchild\b/
  • \B 除了 单词边界

字符串前后空格处理:

var str = "    a child      ";
str = str.replace(/^\s*/g,'')//去开头空格
str = str.replace(/\s*$/g,'')//去结尾空格
str = str.replace(/^\s*|\s*$/g,'')//去开头 和 结尾空格

手机号:

  • ^1 [3-9] [0-9]{9}$

邮箱:

字符串和正则相关方法

支持正则表达式的 String 对象的方法:

方法 描述
search 检索与正则表达式相匹配的值。
match 找到一个或多个正则表达式的匹配。
replace 替换与正则表达式匹配的子串。
split 把字符串分割为字符串数组。
var str = "1a2b3c4d5e6f7"

// split:可传递一个正则作为参数,最终会根据正则规则进行拆分
str.split(/[A-z]/);

// 原 search:搜索字符串中是否含有指定内容
str.search('3c');//返回索引(找到时) 或 -1(未找到时)

// search:可接收一个正则参数,根据正则进行检索
str.search(/a[bde]c/);

// match:根据正则提取符合规则的字符串,返回的是一个数组;
str.match(/[A-z]/);//a -> 默认只会找到第一个符合要求的字符
str.match(/[A-z]/g);//[a,b,c,d,e,f] -> 可设置为全局匹配
str.match(/[a-z]/gi);//也可以同时设置多个匹配模式

//replace:不会影响原字符串
str.replace(/[a-z]/gi,'@');//替换掉所有字母

你可能感兴趣的:(Web前端开发,js)