原型 prototype 和 __proto__
-
对于使用过基于类的语言 (如 Java 或 C++) 的开发者们来说,JavaScript 实在是有些令人困惑 —— JavaScript 是动态的,本身不提供一个
class的实现。即便是在 ES2015/ES6 中引入了class关键字,但那也只是语法糖,JavaScript 仍然是基于原型的。 -
每个对象都有一个
__proto__属性,并且指向它的prototype原型对象 -
每个构造函数都有一个
prototype原型对象 -
prototype原型对象里的constructor指向构造函数本身
有的同学可能会问prototype 和 __proto__有什么用呢?
实例对象的__proto__指向构造函数的prototype,从而实现继承。
prototype对象相当于特定类型所有实例对象都可以访问的公共容器
看一下代码就清楚了
function Person(nick, age){
this.nick = nick;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.nick);
}
var p1 = new Person('Byron', 20);
var p2 = new Person('Casper', 25);
p1.sayName() // Byron
p2.sayName() // Casper
p1.__proto__ === Person.prototype //true
p2.__proto__ === Person.prototype //true
p1.__proto__ === p2.__proto__ //true
Person.prototype.constructor === Person //true
注意
- 当
Object.prototype.__proto__已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在ECMAScript 2015规范中被标准化为传统功能,以确保Web浏览器的兼容性。为了更好的支持,建议只使用Object.getPrototypeOf()。- Object.create(null) 新建的对象是没有__proto__属性的。
原型链
请看以下代码
var arr = [1,2,3]
arr.valueOf() // [1, 2, 3]
我们再来看一张图
console.dir(arr)
按照之前的理论,如果自身没有该方法,我们应该去Array.prototype对象里去找,但是你会发现arr.__proto__上压根就没有valueOf方法,那它是从哪里来的呢?
各位,请看这张图
很奇怪我们在Array.prototype.__proto__里找到了valueOf方法,为什么呢?
查找valueOf方法的过程
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
查找valueOf大致流程
- 当前实例对象obj,查找obj的属性或方法,找到后返回
- 没有找到,通过
obj. __proto__,找到obj构造函数的prototype并且查找上面的属性和方法,找到后返回 - 没有找到,把
Array.prototype当做obj,重复以上步骤
当然不会一直找下去,原型链是有终点的,最后查找到Object.prototype时
Object.prototype.__proto__ === null,意味着查找结束
我们来看看上图的关系
arr.__proto__ === Array.prototype
true
Array.prototype.__proto__ === Object.prototype
true
arr.__proto__.__proto__ === Object.prototype
true
// 原型链的终点
Object.prototype.__proto__ === null
true
原型链如下:
arr --__proto__--> Array.prototype --__proto__--> Object.prototype --__proto__--> null
这就是传说中的原型链,层层向上查找,最后还没有就返回undefined
实现数组去重
includes()方法来判断一个数组是否包含一个指定的值,根据情况,如果包含就返回true,不包含就返回false
var arr = [1,1,15,15,true,false,true,false,NaN,0,"0"]
function fn(arr){
if(!Array.isArray(arr)){
cosloe.log('type error!')
return
}
var array = []
for(var i = 0; i < arr.length; i++){
if(!array.includes(arr[i])){
array.push(arr[i])
}
}
return array
}
console.log(fn(arr))
//(7) [1, 15, true, false, NaN, 0, "0"]
总结
prototype 和 __proto__
-
每个对象都有一个
__proto__属性,并且指向它的prototype原型对象 -
每个构造函数都有一个
prototype原型对象 -
prototype原型对象里的constructor指向构造函数本身
原型链
每个实例对象(object)都有一个私有属性(称之为 proto)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
Vue 的特点
1.遵循MVVM模式 2.编码简洁,体积小,运行效率高,适合移动/PC端开发 3.它本身只关注 UI,可以引入其它第三方库开发项目 4.采用组件化模式,提高代码复用率、且让代码更好维护
5.使用虚拟DOM 和 Diff算法,尽量复用DOM节点
Vue中的MVVM模型
1.什么是MVVM?
MVVM是Model-View-ViewModel(模型-视图-视图模型)的简写,是M - V - VM 三部分组成。
本质:是MVC改进版
MVVM就是将其中View的状态和行为抽象化,其中ViewModel将视图(即View)和业务逻辑分开,它可以去除Model的数据的同时帮忙处理View中由于需要展示内容而涉及的业务逻辑。
MVVM采用:双向数据绑定。
View中数据变化将自动反映到Model上,反之,Model中数据变化也将会自动展示在页面上。
ViewModel就是View和Model的桥梁。
ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回到Model。
MVVM的核心思想:是关注Model的变化。让MVVM框架利用自己的机制自动更新DOM(即所说的View视图),也就是所谓的数据-视图分离。
2.MVVM模型
M:模型Model --->也就是data中的数据 V:视图View --->也就是模板代码 VM:视图模型ViewModel --->也就是Vue实例(vm)
3.举例:对上面的MVVM模型更透彻的理解
先给大家展示一下运行的效果(原本):
再给大家展示一下,我再页面上的输入框中添加‘123456’然后会发现Model模型中的data数据发生了变化(改变后):
npm run build
npm run serve
组件
1.模块与组件、模块化与组件化
模块
-
理解:向外提供特定功能的 js 程序,一般就是一个 js 文件
-
为什么:js 文件很多很复杂
-
作用:复用、简化 js 的编写,提高 js 运行效率
组件
- 定义:用来实现局部功能的代码和资源的集合(html/css/js/image…)
- 为什么:一个界面的功能很复杂
- 作用:复用编码,简化项目编码,提高运行效率
模块化 当应用中的 js 都以模块来编写的,那这个应用就是一个模块化的应用 组件化 当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用
2.VueComponent
- school组件本质是一个名为
VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。 - 我们只需要写
<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。 - 特别注意:每次调用
Vue.extend,返回的都是一个全新的VueComponent,即不同组件是不同的对象 - 关于this指向:
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是
VueComponent实例对象。 new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是Vue实例对象。
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是
VueComponent的实例对象,简称vc(也可称之为:组件实例对象)。Vue的实例对象,简称vm。
3.一个重要的内置关系
VueComponent.prototype.proto === Vue.prototype
为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
school.prototype.proto === Vue.prototype