第五章 原型

5 原型

5.1 prototype

对象的内置属性,是对于其他对象的引用。几乎所有的对象在创建时prototype属性都会被赋予一个非空的值

5.1.1 Object.prototype

所有普通的prototype链都会指向内置的Object.prototype

5.1.2 属性设置和屏蔽

myObject.foo = 'bar';
1.    当myObject不包含foo,则进行赋值操作
2.    如果foo不直接存在于myObject,prototype链就会被遍历
  2.1    如果prototype链上存在foo,当foo被标记为writable:true,则会在myObject中添加foo
  2.2      如果prototype链上存在foo, 当foo被标记为writable:false,则无法修改已有属性或在myObject创建屏蔽属性,严格模式下,会抛出错误,总之,不会发生屏蔽
  2.2    如果在prototype链上存在foo,并且是个 setter ,那就一定会调用这个setter。foo不会被添加到(或屏蔽与)myObject,也不会重新定义foo这个setter
如果希望在二、三情况下也屏蔽foo,那就不能使用=操作符来赋值,而是使用Object。defineProperty()来向myObject添加foo
3.    如果foo同时出现在myObject和myObject的prototype链中,则myObject的foo属性会屏蔽原型链上的foo属性
 
  1. var anotherObj = {
  2.    a:2;
  3. }
  4. var myObj = Object.create(anotherObj);
  5.  
  6. anotherObj.a; //2
  7. myObj.a; //2
  8.  
  9. anotherObj.hasOwnProperty('a'); //true
  10. myObj.hasOwnProperty('a'); //false
  11.  
  12. myObj.a++; //隐式屏蔽
  13.  
  14. anotherObj.a; //2
  15. myObj.a // 3
  16.  
  17. myObj.hasOwnProperty('a'); // true
myObj.a++ 看起来会通过委托查找并增加anotherObj.a,但myObj.a++相当于 myObj.a = myObj.a + 1;++操作会首先通过prototype查找a并从anotherObj.a获取当前属性值2,然后给这个值+1,接着用Put将值3赋给myObj中新建的屏蔽属性a, amazing!!!
 

5.2 “类”

js和面向类的语言不同,他并没有类来作为对象的抽象模式。 js中只有对象
实际上,js才是真正应该被称为“面向对象”的语言,因为它是少有的可以不通过类,直接创建对象的语言
 

5.2.1 “类”函数

类似类的行为利用了函数的一种特性:所有的函数默认都会有一个名为prototype的 共有且不可枚举的属性 ,它会指向另一个 对象 ,这个对象通常被称为...的原型,这个对象是在调用new Foo()时创建的,最后会关联到这个"Foo点Prototype"对象上
  1. functionFoo(){
  2.    // ...
  3. }
  4. var a =newFoo();
  5. Object.getPrototype(a)===Foo.prototype;//true
使用new Foo()时会创建a,其中一步就是给a一个内部的prototype链接, 关联 到Foo.prototype指向的那个对象
 
在面向类的预言中,类可以被复制(或实例化)多次,像模具制造东西。但在js中,没有类似的复制机制,不能创建一个类的多个实例,只能创建多个对象,它们 的prototype关联的是同一个对象
 
a 和 Foo 是两个对象,它们之间相互关联
 
In fact: new Foo()这个函数调用实际上没有直接创建关联,这个关联只是一个意外的副作用,new Foo()只是间接完成目标:一个关联到其他对象的新对象
 
达成目标直接做到这个点的: Object.create(...);
 

5.2.2 "构造函数"

构造函数的错觉:
  1. functionFoo(){
  2.    //...
  3. }
  4. Foo.prototype.constructor ===Foo;// true
  5. var a =newFoo();
  6. a.constructor ===Foo;// true
Foo.prototype有一个 公有并不可枚举 的属性 .constructor ,这个属性引用的是对象关联的函数,本例是Foo
 
 实际上a并没有.constructor属性。而且,虽然a.constructor确实指向Foo函数,但这个属性并不是表示a由Foo“构造”。(a).constructor引用同样被委托给了Foo.prototype,而Foo.prototype.constructor默认指向Foo,即对象的.constructor会默认指向一个函数,这个函数可以通过对象的.prototype引用
 
Foo.prototype的.constructor属性只是Foo函数在声明时的默认属性。如果创建一个新对象并替换了函数默认的.prototype对象引用,那么新对象不会自动获取.constructor属性
  1. functionFoo(){/* */}
  2. Foo.prototype ={/* */};
  3. var a1 =newFoo();
  4. a1.constructor ===Foo;// false
  5. a1.constructor ===Object;// true
当然,可以给Foo.prototype手动添加一个.constructor属性

构造函数or调用

js中对“构造函数”的最准确是解释是: 所有带 new 的函数调用
 

5.2.3 技术

js开发者绞尽脑汁模仿类的行为
 

5.3 原型继承

  1. functionFoo(name){
  2. this.name = name;
  3. }
  4. Foo.prototyp.myName =function(){
  5. returnthis.name;
  6. }
  7. functionBar(name,label){
  8. Foo.call(this,name);
  9. this.label = label;
  10. }
  11. Bar.prototype =Object.create(Foo.prototype);
  12. Bar.protptype.myLabel = fucntion(){
  13. returnthis.label;
  14. }
  15. var a =newBar('a','obj a');
  16. a.myName();//a
  17. a.myLabel();// obj a
核心语句: Bar.prototype =  Object.create(Foo.prototype);
调用Object.create(..)会凭空创建一个“新”对象并把新对象内部的prototype关联到指定的对象
 
错误的作法:
 
  1. Bar.prototype =Foo.prototype;
不是关联,而是直接引用到Foo.prototype对象,当执行Bar.prototype.myLabel = ...的赋值语句会直接修改Foo.prototype对象本身
  1. Bar.prototype =newFoo();
会产生副作用(比如写日志,修改状态,注册到其他对象)
 
修改对象的prototype关联的可靠的方法:
__proto__ 不标准并且无法兼容所有浏览器
ES6添加了辅助函数: Object.setPropertyOf(..)
 
  1. // ES6之前 需要抛弃默认的Bar.pototype
  2. Bar.prototype = Object.create(Foo.prototype); // 性能更高
  3. // ES6 直接修改现有的Bar.prototype
  4. Onject.setPropertyOf(Bar.prototype,Foo.prototype);
 

检查类的关系

  1. functionFoo(){
  2.    //...
  3. }
  4. Foo.prototype.blah = ...;
  5. var a = new Foo();
 
1. instanceof
a  instanceof Foo; //true
instanceof回答的问题 :在a的整条prototype链中是否有指向Foo.prototype的对象
 
如果要比较a和b(均为对象),则无法实现
2. isPropertyOf(a)
Foo.prototype.isPropertyOf(a);  // true
回答的问题:在a的整条prototype中是否出现过Foo.prototype
 
b.isPropertyOf(c);  //可行
 
3. 直接获取一个对象prototype属性
Object.getPrototypeOf(a);
Object.getPrototypeOf(a) === Foo.prototype; // true
a.__proto__ === Foo.prototype; // true (浏览器内部的实现)
__proto__ 是可设置属性 笨蛋proto
 

5.4 对象关联

5.4.1  创建关联: Object.create(..)

使用new的构造函数调用会生成.prototype和.constructor引用
Object.create(..) 是ES5中新增的函数
Object.create(..) 的polyfill代码详见 P160
第二个参数指定了需要添加到新对象中的属性以及这些属性的属性描述符
 
5.4.2  关联关系是备用
内部委托比直接委托可以让API接口更加清晰
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





转载于:https://www.cnblogs.com/Natsume5233/p/6488857.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值