JavaScript通过原型委托的方式实现对象与对象之间的继承。
- 静态类型语言 在编译时已经确定变量的类型,因此在编译时就能发现类型不匹配的错误。
- 动态类型语言的变量类型要到程序运行的时候,待变量被赋予了某个值之后,才会具有某种类型。
多态的思想是将“不变的事物”与“可能改变的事物”分离开来,把不变的部分隔离开来,把可变的部分封装起来,使得程序是可扩展的,
var makeSound = function(animal){
if(animal instanceof Duck){
console.log('111');
}else if(animal instanceof Chicken){
console.log('222');
}
};
var Duck = function(){};
var Chicken = function(){};
makeSound(new Duck());
makeSound(new Chicken());
修改后:
var makeSound = function(animal){
animal.sound();
};
var Duck = function(){};
Duck.prototype.sound = function(){
console.log('111');
}
var Chicken = function(){};
Chicken.prototype.sound = function(){
console.log('222');
}
makeSound(new Duck());
makeSound(new Chicken());
多态最根本的好处在于,你不必再向对象询问“你是什么类型”而后根据得到的答案调用对象的某个行为——你只管调用该行为就是了,其他的一切多态机制都会为你安排妥当。即通过把过程化的条件分支语句转化为对象的多态性,从而消除这些条件分支语句。
封装的目的是将信息隐藏,在js中通过依赖变量的作用域实现封装特性,
1)封装数据,除了使用let
之外,可以通过函数创建作用域。
var my = (function(){
var _name = 'chao';
return {
getName:function(){
return _name;
}
}
})();
console.log( my.getName()); // chao
console.log( my._name); // undefined
2)封装实现
从封装实现细节来讲,封装使得对象内部的变化对其他对象而言是不可见的,其他对象或者用户不关心其内部的实现,对象之间只通过暴露API接口来通信,当修改一个对象的时候可以随意修改其内部实现,对外的接口没有变化,不会影响其他功能。
3)封装变化
考虑你的设计中哪些地方可能变化,这种方式与关注会导致重新设计的原因相反。它不是考虑什么时候会迫使你的设计改变,而是考虑你怎样才能够在不重新设计的情况下进行改变。这里的关键在于封装发生变化的概念,这是许多设计模式的主题。
1)所有的数据都是对象
js包含两套类型机制:基本类型和对象类型,基本类型包括:undefined、number、boolean、string、function、object。js中的跟对象是Object.prototype
对象,Object.prototype
是一个空对象,js中的每个对象都是从Object.prototype
对象克隆而来的,即为对象的原型,
2)要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它。
在js中不需要关心克隆的细节,只需要显式的调用var obja = new Object()
或者var obj2 = {}
function Person(name){
this.name = name;
};
Person.prototype.getName = function(){
return this.name;
};
var a = new Person('sven');
console.log(a.name); // sven
console.log(a.getName()); // sven
console.log(Object.getPrototypeOf(a) === Person.prototype); // true
当使用new运算法调用函数时i,此时函数是一个构造器。
3)对象会记住它的原型
对象把请求委托给它的构造器的原型,JavaScript给对象提供了一个名为__proto__
的隐藏属性,某个对象的__proto__
属性默认会指向它的构造器的原型对象,即{Constructor}.prototype。
var a = new Object();
console.log(a.__proto__ === Object.prototype); // true
4)如果对象无法响应某个请求,它会把这个请求委托给它的构造器的原型。
在JavaScript中,每个对象都是从Object.prototype对象克隆而来的,
原型继承方式:
var obj = { name:'ss'};
var A = function(){};
A.prototype = obj;
var a = new A();
console.log( a.name ); //ss
a.__proto__
记录着并且指向A.prototype
,而A.prototype
被设置为对象objvar A = function(){};
A.prototype = { name: '11'};
var B = function(){};
B.prototype = new A();
var b = new B();
console.log(b.name); // 11
b.__proto__
记录着并且指向B.protoype
,,而B.protoype
被设置为一个通过new A()
创建出来的对象,A.prototype
.A.prototype
.中找到了name属性,并返回它的值。js中的this总是指向一个对象,具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而Fri函数被声明时的环境。
this的指向大致可以分为以下四种:
Function.prototype.call
或者Function.prototype.apply
调用。1)作为对象的方法调用,this指向该对象
var obj = {
a:1,
getA: function(){
console.log(this === obj); // true
console.log(this.a); //1
}
}
obj.getA();
2)作为普通函数调用
当函数不作为对象的属性被调用的时候,此时的this指向全局对象。
window.name = "aaa";
var getName = function(){
return this.name;
}
console.log(getName()); // aaa
3)构造器调用
当使用new运算符调用函数时该函数总是返回一个对象,通常情况下,构造器里的this执行返回的这个对象。
var myClass = function(){
this.name = '222';
};
var obj = new myClass();
console.log(obj.name); // 222
但如果构造器显式返回了一个object类型的对象,此次运算结果最终会返回这个对象,不是之前的this’。
var myClass = function(){
this.name = '222';
return {
name:'111';
}
};
var obj = new myClass();
console.log(obj.name); //111
4)Function.prototype.call
或者Function.prototype.apply
调用。可以动态的改变传入函数的this
var obj1 = {
name:'123',
getName: function(){
return this.name;
}
};
var obj2 = {
name:'456'
};
console.log(obj1.getName()); // 123
console.log(obj1.getName.call(obj2)); // 456
1)区别
var func = function(a,b,c){
console.log([a,b,c]);
}
func.apply(null,[1,2,3]);
var func = function(a,b,c){
console.log([a,b,c]);
}
func.call(null, 1 ,2, 3 )
call是包装在apply上的一颗语法糖,如果明确知道函数接受多少个参数,并且想一目了然表达形参和实参的对应关系,可以使用call传递参数、
2)用途
1)变量作用域:是指变量的有效范围
函数可以用来创建函数作用域,当在函数中搜索一个变量的时候,如果函数内并没有声明这个变量,那么此次搜索的过程会随着代码执行环境创建的作用域链往外层逐层搜索,一直搜索到全局对象为止,变量的搜索是从内到外。
2)变量的生存周期
对于在函数内声明的局部变量来说,退出函数时,这些变量会随着函数调用的结束被销毁,
多态:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果,换句话说给不同的对象发送同一个消息的时候,这些对象可以根据这个消息分别给出不同的反馈。
封装:
(1)Object.create();
对象的_proto_会属性会默认指向他的构造器的原型对象。
(1)函数作为对象的方法被调用,this指向该对象。
(2)普通函数调用,this指向全局对象。
(3)构造器调用:当用new运算符调用函数时,该函数会返回一个对象,通常情况下,构造器中的this会指向返回的对象。
var myClass = function(){
this.name = "chao";
}
var obj = new myClass();
console.log(obj.name); //chao
如果构造器显示返回了一个object类型的对象,那么会返回该对象。
var myClass = function(){
this.name = "chao";
return {
name:"llal"
}
}
var obj = new myClass();
console.log(obj.name); //llal
如果构造器不显示返回任何数据,或者返回一个非对象类型的数据,则不会有上述现象。
(4)function.prototype.call
或者function.prototype.apply
调用
可以动态的改变this的指向。
var obj= {
name :"se",
getName:function(){
return this.name;
}
}
var obj2 = {
name:"ssss"
}
console.log(obj.getName()); // se
console.log(obj.getName.call(obj2)); //ssss