发表于: 2019-11-15 18:48:14

1 1135


今天完成的事:

复习css和js深度思考,整理相关知识点

明天计划的事:

再复习、复习准备复盘评审

遇到的问题:

对学会的知识点,了解会用,但不能完整的叙述,流畅的讲出自己的理解

收获:

原型和原型链

原型

  • 所有引用类型(数组、对象、函数)都有一个__proto__隐式原型属性,属性值是一个普通对象。 此外,Object.prototype.__proto__指向null
  • 所有函数都有一个prototype显式原型属性,属性值是一个普通对象。 Function.prototype.bind()没有prototype属性
  • 所有引用类型(数组、对象、函数)的__proto__执行它的构造函数的prototype属性

构造函数

构造函数特点:函数名首字母大写,它就类似一个模板,可以new出多个实例

var a={} // var a=new Object()的语法糖 var a=[] // var a=new Array()的语法糖 function Foo(){} // var Foo=new Function()的语法糖 复制代码

instanceof

instanceof判断引用类型属于哪个构造函数

f instanceof Foo的判断逻辑:f的__proto__一层层往上,能否找到Foo.prototype。

但是因为原型链上所有特殊对象的__proto__最终都会指向Object.prototype,所以instanceof判断类型也不完全准确

new操作符具体干了什么?

  • 创建一个空对象
  • 将对象的__proto指向构造函数的原型prototype
  • 执行构造函数中的代码,传递参数,并将this指向这个对象
  • 返回对象
function _new(){     let obj = {};     let con=[].shift.call(arguments);     obj.__proto__ = con.prototype;     let res = con.apply(obj, arguments);     return res instanceof Object ? res : obj; } 复制代码

通过new的方式创建对象和通过字面量创建的区别

更推荐字面量的方式创建对象,性能和可读性都更好。使用var o=new Object()和var o={}的区别是前者会调用构造函数

hasOwnProperty

hasOwnProperty判断该对象本身是否有指定属性,不会到原型链上查找。

使用方法:object.hasOwnProperty(proName)

利用它可以循环对象自身属性

for(let item in f){     if(f.hasOwnProperty(item)){         console.log(item)     } } 复制代码

原型链

访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链

面向对象

创建对象的几种方式

  • 工厂模式
function createPerson(name, age){     var o = new Object();     o.name = name;     o.age = age;     o.sayName = function(){         console.log(this.name)     }     return o; } var person1 = createPerson('chen',21) 复制代码
  • 构造函数模式

没有显示创建对象,直接将属性方法赋给this,没有return语句

function Person(name, age){     this.name = name;     this.age = age;     this.sayName = function(){         console.log(this.name)     } } var person1 = new Person('chen',21) 复制代码

缺点:每个方法都要在每个实例上重新定义一遍,无法得到复用

  • 原型模式
function Person(){} Person.prototype.name="chen" Person.prototype.age=21 Person.prototype.sayName=function(){     console.log(this.name) } var person1 = new Person() 复制代码

缺点:所有实例都取得相同属性值

  • 混合构造函数原型模式 构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
function Person(name,age){     this.name=name;     this.age=age; } Person.prototype = {     constructor: Person,     sayName: function(){         console.log(this.name)     } } var person1=new Person('chen',21) 复制代码

实现继承

JavaScript通过原型链实现继承

  • 原型链继承 核心:将父类的实例作为子类的继承
function Parent(){     this.name = 'parent' } Parent.prototype.sayName = function(){     return this.name } function Child(){ } // 继承了Parent Child.prototype = new Parent(); var child1=new Child(); child1.say(); 复制代码

缺点:对象实例共享所有继承的属性和方法

  • 借用构造函数 核心:在子构造函数内部调用父构造函数
function Parent(){     this.arr=[1,2,3] } function Child(){     // 继承了Parent     Parent.call(this) } var child1 = new Child(); child.arr.push(4); // [1,2,3,4] var child2 = new Child(); child.arr;  // [1,2,3] 复制代码
  • 组合继承

使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性

function Parent(name){     this.name = name;     this.arr = [1,2,3] } Parent.prototype.sayName = function(){     console.log(this.name) } function Child(name,age){     // 继承属性     Parent.call(this, name)     this.age=age } // 继承方法 Child.prototype = new Parent() Child.prototype.constructor = Child; Child.prototype.sayAge = function(){     console.log(this.age) } var child1=new Child('chen',21); child1.arr.push(4); //[1,2,3,4] child1.sayName()    // 'chen' child1.sayAge()     // 21 var child2=new Child('miao', 12) child2.arr          // [1,2,3] child2.sayName()    // "miao" child2.sayAge()     // 12 复制代码

缺点:无论在什么情况都会调用两次父构造函数,一次是创建子类型原型,另一次是在子构造函数内部

  • 原型式继承 核心:执行对给定对象的浅复制
var person = {     name: 'chen',     arr: [1,2,3] } var person1 = Object.create(person); person1.name = 'run' person1.arr.push(4) var person2 = Object.create(person); person2.name = 'miao' person2.arr.push(5) person.arr; // [1,2,3,4,5] 复制代码
  • 寄生式继承 核心:基于某个对象创建一个对象,然后增强对象,返回对象。
function create(original){     // 通过调用函数创建一个新对象     var clone = object(original);      // 以某种方式增强对象     clone.sayHi = function(){         console.log('hi')     }     return clone; } var person = {     name: 'chen' } var person1 = create(person); person1.sayHi(); 复制代码
  • 寄生组合式继承
function Parent(name){     this.name = name;     this.arr = [1,2,3] } // 将共享的属性/方法放到原型上 Parent.prototype.sayName = function(){     console.log(this.name) } // 借用构造函数增强子类实例属性(支持传参和避免篡改) function Child(name,age){     // 继承属性     Parent.call(this, name)     this.age=age } function inheritPrototype(Child, Parent){     var prototype=Object.create(Parent.prototype);     prototype.constructor=Child;     Child.prototype=prototype; } // 将父类原型指向子类 inheritPrototype(Child, Parent); Child.prototype.sayAge=function(){     console.log(this.age) } var child1=new Child('chen',21); child1.arr.push(4); //[1,2,3,4] 继承自父类实例属性 child1.sayName()    // 'chen'   继承自父类原型方法 child1.sayAge()     // 21       继承自子类原型方法 var child2=new Child('miao', 12) child2.arr          // [1,2,3] child2.sayName()    // "miao"  child2.sayAge()     // 12 复制代码

class如何实现继承,class本质是什么?

class只是语法糖,本质是函数

class Parent{     constructor(value){         this.val=value     }     getValue(){         console.log(this.val)     } } class Child extends Parent{     constructor(value){         super(value)         this.val = value     } } let child = new Child(1) child.getValue() // 1 child instanceof Parent // true 复制代码

核心:使用extends表明继承自哪个父类,并且在子类构造函数中必须使用super,可以看做是Parent.call(this,value)

什么是面向对象编程及面向过程编程,它们的异同和优缺点

面向过程就是分析出解决问题所需的步骤,然后用函数把这些步骤一步步实现,使用的时候一个个依次调用

面向对象是把构成问题的事务分解成各个对象,奖励对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

优点:易维护,可读性高,易扩展,继承性高,降低重复工作量,缩短了开发





返回列表 返回列表
评论

    分享到