面向对象基础知识概括

=============数据属性和访问器属性

数据属性 和 访问器属性

get 获取 Own 自己的property 属性 Descriptor 描述符

value:zhangsan //该key对应的值

writable : true //可修改

enumerable: true //可枚举性 是否可被遍历

configurable:true //可配置性 能否被删除

默认都是可修改,可被遍历到,可被删除

define 定义 property 属性

Object.definProperty(obj,key,Descriptor);默认不可被修改,遍历,删除
const obj = { name : "zhangsan", age : 18 } Object.defineProperty(obj,'age',{ value : 18, writable:true, // 默认为false 是否可修改 enumerable : false, // 默认为false 是否可遍历 configurable: true //默认为false 是否可删除 }) obj.age = 20; for(let key in obj){ console.log(key) //name,age } console.log(obj); delete obj.age; console.log(obj) //{name: "zhangsan"}
存取描述符

两个方法 get() set()

存取描述符不可与数据描述符同时存在,即get set 不可与 value writable 同时存在

案例:输入属性值,进行判断
const obj = { name : "zhangsan", // 如果这里没加下划线,那么下面get访问也不用加 // _age : 38, _score: 60 } Object.defineProperty(obj,'score',{ //这里的参数score必须对应下面的set,包括下划线 // value : 18, // writable:false, // 默认为false 是否可修改 enumerable : false, // 默认为false 是否可遍历 configurable: false, //默认为false 是否可删除 get() { //访问对象属性时自动被调用 return this._score; //获取obj.score的值 }, //输入的值 set(value){ //设置对象属性时自动被调用 //判断值 if(value < 0 || value > 100){ console.log("请输入正确分数"); }else{ this._score = value; //输入的值赋值给obj.score (注:这里不能使用下划线) console.log("录入成功"); return value;// 返回输入的值 } } })
===========面向对象
面向对象编程,一种编程范式(编程风格,编程方式)。

将现实问题构建关系,抽象成类,为类定义属性,方法。再将类【实例化】成【实例】,访问实例属性,调用实例方法进行使用。

实例化:新增 新建 创建

例如:张三想要个女儿,生的那个女儿就是实例。

Arr let arr = new Array();

编程范式

1.声明式编程 HTML,CSS告诉计算机需要XX

2.命令式编程 每一步都需要告诉计算机(比如声明一个变量),强调了做事的步骤

​ 1.面向过程 分析出解决问题的每一步,逐步实现

​ 2.面向对象 把构成问题的事物分解成各个对象,让具体对象去实现相应事情

​ ATM

种类,模板,模具

数量庞大就可以用类区分,归纳
类属于对象,对象有这些类

类是对象的一种抽象概括,对象是类的具体实现,类是模板,用于生成多个实例。

封装:封装,继承,多态

封装:信息隐藏,把实现功能的方法包装起来。函数是对于算法的封装,类是对于属性和方法的封装

函数的三要素,随机数函数, 餐馆吃饭(只关心菜品,不用关心厨师如何做出来)。

继承:子类可以继承父类的所有属性和方法,还可以扩展自己的属性和方法。
=========封装

1.对象的方式表现出来,看不出实例和类的关联

把属性和方法组成类的过程就叫做封装
//cat 想要表示猫的类 const cat = { //cat的属性 name : '', age : '', gender : '', color : '' }; const cat1 ={ name : 'xiaohei', age : '1', gender : 'male', color : 'block' } const cat1 ={ name : 'xiaohuang', age : '2', gender : 'female', color : 'yellow' }
2.ES6 class 声明类

关键字class
//此处的Dog实际是一个构造函数 class Dog { constructor(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } } let xiaohei = new Dog('xiaohei',2,'male'); //xiaohei实例化出来的具体某个对象 console.log(xiaohei); //案例:我叫张三,我的小狗叫小黑 class Person{ constructor(name){ this.name = name; console.log(this);// Person {name: "张三"} } talk(){ console.log(我叫${this.name},我的小狗叫${xiaohei.name}); } } let zhangsan = new Person("张三") zhangsan.talk(); // 我叫张三,我的小狗叫xiaohei
==========工厂模式
` //工厂模式
function CatFactory(name,age,gender){
return {
name : name,
age : age,
gender : gender
}
}
let cat_obj = CatFactory('xiaohuang','1','female');
console.log(cat_obj);

    function Dogfactory(name,age,gender,type){
        return {
            name,
            age,
            gender,
            type
        }
    }
    let dog1_obj = Dogfactory('小白',2,'female','金毛'),
        dog2_obj = Dogfactory('小黄',3,'male','拉布拉多');
        console.log(dog1_obj,dog2_obj);`

========混合模式(构造函数+原型prototype)

将实例对象共享的方法,放在类原型上,实现方法共享,节省内存
function Cat(name,age,gender){ //用this,不能用return this.name = name; this.age = age; this.gender = gender; } Cat.prototype.eat = function(){ console.log('饿了,干饭去'); } let Cat1 = new Cat('xiaohuang',2,'female'), Cat2 = new Cat('xiaobai',2,'male'); Cat1.eat(); Cat2.eat();
======静态方法(工具型) 实例方法
let arr = new Array(); arr.push(); //得到实例对象后通过实例对象去调用的方法,属性 Math.random(); Json.parse() //直接在类,构造函数身上使用的
======使用new关键字在内部经历的四个步骤
1.创建了一个该类型的空对象, 就像是 let _obj = {};

2.将这个新对象的_proto_(隐式原型)指向了类(构造函数)的prototype(原型)就像是 cat1._proto_ =>Cat.prototype

3.将构造函数(类)内部的this 指向该实例对象,并执行代码 就像是 this => _obj

4.返回该对象
=======原型
每一个函数都有一个属性,prototype表示原型(原型对象)。

class Dog{} new Dog()
原型的作用:

给所有实例提供公共的访问。
`let arr = [];
console.log(Array.prototype);

    const obj1 = {
        name : "zhangsan"
    }
    console.log(obj1.name,obj1.age);// zhangsan  un
    Object.prototype.age = 18;
    console.log(obj1.name,obj1.age);//zhangsan  18`

2.对象和隐式原型

每一个实例对象都有一个_proto_,称为隐式原型,指向创建该对象的类的原型。
const arr1 = []; //new Array()
console.log(arr1.proto === Array.prototype);//true
3.原型和构造器

每一个类(函数)的prototype上都有constructor指向函数本身

每个原型都有一个constructor属性,指向该关联的构造函数。
console.log(Array.prototype.constructor === Array);//true
4.原型链

链 链式调用 快 美化代码 简洁方便

作用域链 找变量

原型链 找公共属性 方法是特殊的属性,一个实例在调用属性,方法时,会以此从实例自身 -> 创建该实例的构造函数的原型 -> Object的原型。

查看是否有对应的属性或方法。专业上称为原型链。
function Pig(){}; let pi_obj = new Pig(); console.log(pi_obj); Pig.prototype.eat = function(){ console.log(666); } pi_obj.eat();//666 pi_obj.toString();
instanceof 判断 该对象是不是该类(函数)的实例对象。
function Pp(){} let P_obj = new Pp(); console.log(P_obj instanceof Pp);//true let pp = {} console.log(pp instanceof Pp);//false
=========继承

当 类 和 类 之间发生了is关系,就看做继承。

继承的作用:子类继承父类,继承所有的属性和方法。子类可以扩展自己的属性和方法。实现代码复用。

糟糕的继承关系,出现代码冗余,关系臃肿。
class Animal{ //动物 constructor(type,name,age,gender){ this.type = type, this.name = name, this.age = age, this.gender = gender } eat(){ console.log("饿了,干饭去"); } } class Pig extends Animal{ constructor(type,name,age,gender,color){ super(type,name,age,gender); //替代了 this.xx = xx this.color = color; } } let cat_obj = new Animal('cat','xiaobai',2,'male'); cat_obj.eat(); console.log(cat_obj); let pig_obj = new Pig('pig','xiaohei',3,'female','red'); pig_obj.eat(); console.log(pig_obj);
========= this

1.全局环境下,this => windows。

2.普通函数(包括嵌套) this => windows。

3.通过对象调用的方法,this=>对象。

4.通过事件 this => 事件源。

5.构造函数 new 出来的实例,this => 实例。

6.箭头函数的this指向取决于当前箭头函数声明的环境(执行上下文 EC)。
箭头函数需要获取函数定义时所在的EC的this,箭头函数定义在哪个作用域中,就继承当前作用域的this的指向。

1.全局 this => window。
let foo =() => { console.log(this);//window }
EC 3类 :全局环境(全局EC),局部环境(局部EC,函数级别上下文),eval环境(eval EC);
const obj = { name : "zhangsan" } talk(){ console.log(this)//指向obj }
2.对象不会生成作用域。
let count = () => { console.log(this); console.log(this.name); } var number = 5; let obj = { say : count }; obj.say();
const zhangsan = { name : 'zhangsan', talk : function(){ console.log(this); //zhangsan对象 let lisi = { name : 'lisi', talk : () =>{ console.log(this); // zhangsan对象 (因为这个箭头函数没有this指向且在zhangsan.talk()的作用域中) } } lisi.talk(); } } zhangsan.talk();
let obj = { a : 10, fn :() =>{ let bar = () =>{ console.log(this);//window } bar(); } } obj.fn();
======修改 this 的指向
1.call 呼叫

语法:fn.call(target);

2.apply 应用

3.bind 捆绑

call,apply改变this的同时立即调用函数,bind 改变后返回一个新函数,需要重新调用。
function foo(){ console.log(this); } const obj = { name : "zhangsan" } foo() // window //对于传参:call 直接跟在target后, apply 以数组的方式 bind 调用函数的()里传 foo.call(obj,5); // zhangsan (foo的this的指向改为指向obj) foo.apply(obj,[5]); // zhangsan foo.bind(obj)(5); // zhangsan
var obj = { a:1, b : function(){ console.log(this.a); } } var a = 2; let fn = obj.b; obj.b(); //1 //指向obj对象 fn(); //2 //单纯的将函数赋值给fn,指向全局 obj.b.call(window)//2 //call(window) 全局变量a
=======作用域 scope

作用: 生效 域:区域 ,变量生效的范围,也叫词法环境。

作用域的产生时间:函数定义(声明)时产生。

作用域分类

3类

全局作用域(全局EC)

局部作用域(局部EC,函数级别上下文)

eval作用域(eval EC);
=======执行上下文 EC (execution context)

代码当前的执行环境,又称为执行上下文环境。

上下文 语文 css this

EC的产生时间,函数调用时产生

全局EC:默认环境。产生时间:打开页面---关闭页面 生命周期

​ node node 执行 ---- 关闭

局部(函数)EC,调用时----调用结束 生命周期
`=======执行上下文 EC (execution context)

代码当前的执行环境,又称为执行上下文环境。

上下文 语文 css this

EC的产生时间,函数调用时产生

全局EC:默认环境。产生时间:打开页面---关闭页面 生命周期

​ node node 执行 ---- 关闭

局部(函数)EC,调用时----调用结束 生命周期 `
=======EC的组成

当调用函数,新的EC会被创建,在JS引擎内部,这个EC的生命周期还会被分为:

1.创建阶段

2.激活阶段

3.销毁阶段
创建阶段

VO(variable object)变量对象:arguments,声明式函数,var声明的变量。

scope:确定作用域链

this:确定环境对象
激活阶段

函数的引用

变量赋值

执行其他代码

销毁阶段
(注:变量提升不提升值,即不赋值)!

VO是执行上下文创建阶段内部创建的一个对象,用于记录当前作用域中所有可用的变量

VO中的属性都是不可访问的,只有等激活阶段VO变AO(active object)才能被访问。
function outer(){ console.log(a); //undefined 变量提升不赋值 console.log(inner()); //2 函数提升 var a = 1; function inner(){ return 2; } } outer();
var a = 10; fn(); function fn(){ //内部的var不会提升到外部 var b = 5; console.log(a); //un console.log(b); //5 var a = "abc"; }
var a = 1; function fn(){ console.log(a);//un a = 2; console.log(a); //2 var a = 3; // 这个var a 提升到函数内部最上层 console.log(a); //3 } console.log(a); //1 fn(); console.log(a); //1
var fn = function(){ console.log(a);// 函数a本身 var a = 1; console.log(a); //1 a(); //报错不是一个函数,因为此时a=1 function a(){} } fn();
var a = 1; function fn(){ a = 10; return a; function a(){} } console.log(fn());//10 console.log(a); //1
var a = 100; function foo(){ bar(a); //执行结束出栈 console.log(a); //100 } function bar(a){ // AO进栈 console.log(--a); //99 } foo();
function foo(num){ if(num > 3){ foo(--num);//依次执行,出栈不再执行 } console.log(num); //3,3,4 } foo(5)
======= 作用域链 scope chain SC

作用域链是一套 EC 的访问规则,由当前上下文和上层上下文中一系列VO组成。

访问规则:先访问自身EC,若找不到变量,则访问声明时所在的EC的变量,以此类推到全局。
var food = "巧克力味的粑粑"; function eat(){ console.log(吃${food}`);//声明在全局,就在全局里面找
}
function fn(){
var food = "粑粑味的巧克力";
eat();
}
fn();

    var food = "巧克力味的粑粑";
    function fn(){
        var food = "粑粑味的巧克力";
        function eat(){
            console.log(`吃${food}`);
        }
        eat();
    }
    fn();`

let a1 = 1,a2 =2,a3 = 3; function foo(){ let a2 = 6; console.log(a1,a2,a3); //1,6,un var a3 = 9; //a3变量提升 a1 = 8; function bar(b){ a3 = 7; let a4 = 6; console.log(a1,a2,a3);//8,6,7 } bar(7); } foo(); console.log(a1,a2,a3);//8,2,3 console.log(a4);//报错
垃圾:无用的东西

对于计算机:多余的,无用的数据

存储数据,计算机都会开辟空间来存储组织,但无限开辟空间则会出现爆栈影响性能。

计算机会在适当的时候自动清理无用的数据,自动执行,并不可见,引擎中有一个后台的进程被称为“垃圾回收器”。
function foo(){ let a = 5; console.log(a);//5 被标记“进入环境” } foo(); console.log(a);//无法被访问 “离开环境”
回收方案:

1.标记清除

2.引用计数
const obj = { name : "zhangsan" } obj = null;//切断了引用,计数为0,回收
======= 闭包 closure
原本应该被清理的数据,由于还有引用(使用),导致该销毁的数据没有被销毁。

难以描述的概念,书籍,文档对于闭包的描述都不一样。

MDN:函数和对其周围状态的引用捆绑在一起构成闭包,闭包可以让你从函数内部访问外部函数作用域,每当函数被创建,就会在函数生成时生成闭包。

javaScript高级程序设计:闭包是指有权访问另一个作用域中变量函数。

广义:所有函数都会生成闭包,因为只要有函数,就有SC。

狭义:函数的嵌套,内部函数在访问外部函数作用域,内部函数在自身以外被调用。
function outer(){ let number = 5; return function(){ console.log(number); } } let result = outer(); result();//5
====== 深浅拷贝

深拷贝:都是针对复杂数据类型,改变原有对象里的值,新的对象的值不会改变。

浅拷贝:改变原有对象里的值,新的对象的值也会改变

1.for, for of ,... , concat, map, slice, filter,Object.assgin(newArr,arr);

2.for in, ... ,Objcet.assgin(newobj,obj),Object.keys()等价于for in,JSON,obj =>str,str => newObj
数组深拷贝
` let arr = [1,2,3];

let newArr = [];

// newArr = arr.slice(0,4); //使用数组截取方法

// let newArr = arr.map(item => { //使用map

// return item;

// })

// newArr = arr.filter(item =>{ //使用filter

// return item;
// })

// newArr = [...arr]; //使用扩展运算符

// Object.assign(newArr,arr); //使用Object.assgin()

// for(let item of arr){ //使用for of
// newArr.push(item);
// }
arr[0] = 'a';
console.log(arr);
console.log(newArr);对象深拷贝 : 新对象不会因为旧对象属性的更改而发生改变
let zsObj = {
name : "zhangsan",
age: 18
}
let new_obj = {};
// for(let key in zsObj){
// new_obj[key] = zsObj[key]; //使用for in 赋值
// console.log(zsObj,new_obj);
// }
// Object.assign(new_obj,zsObj); //使用Object.assgin()
// new_obj = {...zsObj}; //使用扩展运算符
// new_obj = JSON.stringify(zsObj); //使用JSON
// console.log(JSON.parse(new_obj));
zsObj.name = 'lisi';
console.log(zsObj);
console.log(new_obj);`
深拷贝考虑:

1.递归考虑爆栈。

2.对象方法是否要拷贝,正则,JSON能够保存的数据类型不包括函数,undefined,data。

3.业务范畴,不能脱离业务场景。

4.库,框架已经封装好了克隆的方法,直接用。

posted on 2020-12-26 15:31  wpwp123  阅读(128)  评论(0)    收藏  举报