面向过程POP
Javascript进阶
面向过程POP
(process-oriented programming)分析出解决问题所需的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了
面向对象OOP
(object oriented programming)把事务分解成一个个对象,然后由对象之间分工合作。
OOP的特性:封装性,继承性,多态性
对象是一组无序的相关属性和方法的集合。
【类class】
创建类 class name {
}
创建实例 var xx = name(); 类必须使用new实例化对象
类constructor构造函数
constructor()方法是类的构造函数(默认的方法),用于传递参数,返回实例对象,通过new命令生成对象实例时,自动调用该方法,如果没有显示定义,类内部会自动给我们创建一个constructor()
语法:
class Person {
constructor (name,age) { //构造方法或构造函数
this.name = name;
this.age = age;
}
say () {
}
}
var ldh = new Person('刘德华',18);
继承extends
class Father {
}
class Son extends Father {
}
【super】关键字-访问和调用对象父类上的函数
class Person {
constructor (surname) {
this.surname = surname;
}
}
class Student extends Person { //子类继承父类
constructor (surname,firstname) {
super(surname); // 调用父类的constructor(surname)
this.firstname = firstname;//定义子类独有的属性
}
}
注意:super必须放到this前面✔
super用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数
在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象。
类里面的共有属性和方法一定要加this使用。
类里面的this指向问题。
constructor 里面的this指向实例对象,方法里面的this指向这个方法的调用者。
insertAdjacentHTML(追加的位置,'要追加的字符串元素')-可以直接把字符串格式的元素添加到父元素中。不可以用appendChild追加。
追加的位置-beforeend插入元素内部的最后一个子节点之后。
禁止选中文字
window.getSelection?window.getSelection().removeAllRanges() : document.selection.empty();
构造函数-一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
在Js中使用构造函数时需要注意以下两点∶
构造函数用于创建某一类对象,其首字母要大写。构造函数要和new一起使用才有意义。
new在执行时会做四件事:
在内存中创建一个新的空对象。
让this指向这个新的对象。
执行构造函数里面的代码,给这个新对象添加属性方法。
返回这个新对象(所以构造函数里面不需要return)
构造函数可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加。通过这两种方法添加的成员分别称为静态成员和实例成员。
静态成员:在构造函数本身上添加的成员,只能由构造函数本身来访问。
实例成员:在构造函数内部创建的对象成员,只能由实例化的对象来访问。
构造函数原型prototype
构造函数通过原型分配的函数是所有对象所共享的,js规定,每一个构造函数都有一个prototype 属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有方法和属性,都会被构造函数所拥有。我们可以把那些不变的方法直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
原型是什么-一个对象,我们也称为prototype为原型对象。作用是共享方法。
function Star (uname,age) {
this.uname = unane;
this.age = age;
}
Star.prototype.sing = function (){
}//在原型上添加共有方法
对象原型__proto__
对象都会有一个属性__proto__指向构造函数的prototype 原型对象,之所以我们对象可以使用构造函数函数prototype原型对象的方法,就因为对象有__proto__原型存在。
__proto__对象原型和原型对象prototype是等价的,
__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条线,但是它是一个非标准属性,因此实例开发中,不可以使用这个属性,它只是内部指向原型对象prototype.
三者之间关系
Star构造函数通过Star.prototype指向Star原型对象prototype
Star原型对象prototype通过原型对象.constructor指向Star构造函数
Star构造函数直接指向它的ldh实例化对象
ldh对象实例通过ldh.__proto__指向Star原型对象prototype
__proto__和prototype里面都有一个constructor 属性,constructor我们称为构造函数,因为它指向构造函数本身。
constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
JS查找机制
先查找自身属性-再查找原型-查找对象的原型Object 的原型-null
__proto__的意义就在于为对象成员查找提供一个方向,或者说一条路线。
原型对象this指向
构造函数里的this指向实例对象。
原型对象里面放的是方法,这个方法里面的this指向的是这个方法的调用者,也就是这个实例对象。
通过原型对象,对原来的内置对象进行扩展自定义的方法。
继承【继承】
ES6之前没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,也就是组合继承。
call()方法
fun.call(thisArg,arg1,arg2...)
thisArg:当前调用函数this的指向对象
arg1:传递的其他参数
借用构造函数继承父类型属性
核心原理:通过call()把父类型的this指向子类型的this,这样就可以实现子类型的属性。
function Father (name,age) {
this.name=name;
this.age=age;
}
function Son (name,age,sex) {
Father.call(this,name,age);//父类的this指向子类的this,.同时调用这个函数
this.sex=sex;
}
var xt= new Son('ez','18','男');
借用原型对象继承父类型方法
一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。核心原理-
将子类所共享的方法提取出来,让子类的prototype原型对象=new 父类(),
本质-子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象,将子类的constructor 重新指向子类的构造函数。
类的本质
class的本质还是function
类的所有方法都定义在类的prototype属性上
类创建的实例,里面也有__proto__指向类的prototype原型对象
ES6的类它的绝大部分功能,Es5都可以做到,新的class写法只是让对象原型的写法更加清晰,更像面向对象编程的语法而已
ES5新增的方法
数组方法
foreach()
array.foreach(function(currentValue,index,arr){})
currentValue:数组当前项的值
index:数组当前项的索引号
arr:数组对象本身
arr.foreach(function(value,index,array){
//函数内部可以获取到参数值
})
filter()筛选元素,返回新数组
array.filter(function(value,index,array){
//函数内部可以获取到参数值
})
currentValue:数组当前项的值
index:数组当前项的索引号
arr:数组对象本身
返回一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组。
例子-
var arr=[12,66,4,88,3,7];
var newArr=arr.filter(function(value,index){
return value%2===0;
});
some()查找元素,返回布尔值
array.some(function(value,index,array){
//函数内部可以获取到参数值
})
currentValue:数组当前项的值
index:数组当前项的索引号
arr:数组对象本身
用于检测数组中的元素是否满足指定条件,查找数组中是否满足条件的元素。
返回布尔值,如果查到这个元素就返回true,查不到返回false.
找到你一个满足条件的元素,则终止循环,不再继续查找。
把数据渲染到页面-foreach
根据价格显示数据-filter
字符串方法
str.trim(),删除字符串两端的空白字符,不影响原字符串本身,返回新字符串,可用于用户输入空格失去焦点时清空表单。
对象方法
Object.keys(obj)用于获取对象自身所有属性
类似for...in
返回一个由属性名组成的数组。
Object.defineProperty(obj,prop,descriptor)
obj-必需,目标对象
prop-必需,需定义或修改的属性的名字
descriptor-必需,目标属性所拥有的特性,以对象{}形式书写,value:设置属性的值,默认undefined
writable:值是否可以重写,true|false,默认为false
enumerable:目标属性是否可以被枚举,true|false,默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true|false,默认为false
定义对象中新属性或者修改原有属性。
改变函数内部this指向
1.call方法
call()方法调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向。
fun.call(thisArg,arg1,arg2...)
thisArg:在fun函数运行时指定的this值
arg:传递的其他参数
返回值就是函数的返回值,因为它就是调用函数。
因此当我们想改变this指向,同时想调用这个函数,可以使用call,比如继承
2.apply方法
fun.apply(thisArg,[argArray])
thisArg:在fun函数运行时指定的this值
argArray:传递的值,必须包含在数组里面
返回值就是函数的返回值,因为它就是调用函数
因此apply主要和数组有关,比如使用Math.max()求数组的最大值
var arr=[1,66,3,99,4];
var max=Math.max.apply(Math,arr);
3.bind方法
fun.bind(thisArg,arg1,arg2...)
thisArg:在fun函数运行时指定的this值
arg:传递的其他参数
返回由指定的this值和初始化参数改造的原函数拷贝
因此当我们只是想改变this指向,并且不想调用这个函数的时候可以使用bind
call,apply,bind总结
相同点:改变函数内部this指向
区别:call和apply会调用函数,且改变函数内部this指向,
call和apply传递参数不一样,后者是数组形式,bind不会调用函数
应用场景:call-继承
aplly-与数组有关,求最大值最小值
bind-改变定时器内部this指向
严格模式
'use strict'
1.为脚本开启严格模式
(function () {
'use strict';
})();
2.为函数开启严格模式
严格模式中的变化
1.变量规定-在正常模式下,一个变量不声明就赋值,默认是全局变量,严格模式下禁止这种用法,变量必须才用var命令声明,然后再使用。
严禁删除已经声明的变量。例如delete x;语法是错误的。
2.严格模式下this指向问题
以往全局作用域函数中的this指向window对象。严格模式下全局作用域函数中的this是undefined。以前构造函数时不加new也可以调用,当普通函数,this指向全局对象。严格模式下,如果构造函数不加new调用,this指向的是undefined,如果给他赋值则会报错。
new实例化的构造函数指向创建的对象实例。
定时器this还是指向window。事件、对象还是指向调用者。
3.函数变化
函数不能有重名参数。
函数必须声明在顶层,新版本js会引入块级作用域,为了与新版本接轨,不允许在非函数的代码块内声明函数。
高阶函数:是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
闭包:有权访问另一个函数作用域中变量的函数。就是一个作用域可以访问另一个函数内部的局部变量。
闭包的作用-延伸变量的作用范围。
闭包案例:打车价格
递归,一个函数在内部调用其本身,那个这个函数就是递归函数。递归函数的作用和循环效果一样。递归容易发生栈溢出,所以必须要加return退出条件。
递归案例:
求1-n的阶乘
求斐波那契数列
function fb(n) {
if( n===1 || n=== 2){
return 1;
}
return fb(n-1)+fb(n-2);
}
根据id返回对应的数据对象。
浅拷贝只拷贝一层,更深层次对象级别的只拷贝引用。
深拷贝拷贝多层,每一级别的数据都会拷贝。
Object.assign(target,...sources) es6新增方法可以浅拷贝
深拷贝封装
function deepCopy(newobj,oldobj) {
for(var k in oldobj){
var item = oldobj[k];
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k],item);
} else if (item instanceof Object){
newobj[k] = {};
deepCopy(newobj[k],item);
} else {
newobj[k] = item;
}
}
}