迷迷糊糊很多年的js原型链
2017-07-14 17:21
162 查看
1.属性描述器(属性标签)
对象的每个属性都有多个标签,也叫属性描述器
writable 是否可写
enumerable 是否可枚举
configurable 是否可配置删除
value 属性值
get方法\set方法
get与set是对象内部的关键字,他们与其他属性不同,并非键值对形式存在,可以直接咦get set关键字开头后面跟函数表达式,其默认方法如下
get方法:get 属性名(){return this.$属性名}
set方法:set 属性名(val){this.$属性名=val}
另外for...in 循环遍历对象属性,会把原型链上的属性也遍历出来,除非该属性描述器enumerable=false
for( obj in Object){ ...}
需要注意的是:遍历顺序不确定;对象的属性描述器enumerable为false时将不会被枚举;受对象原型链影响;
JS delete运算符:
对象属性的描述器 configurable=false时,该属性不能被delete,return false;全局变量、局部变量都不可delete,隐式声明全局变量可以被delete;Object.prototype不可被delete;delete对象不存在的属性时 依然会返回true
通常代码中自定义创建对象的属性的标签默认值都为true,继承自Object的有些属性的标签为false,可通过以下方法来查看:
以标签enumerable为例,其他标签用法一样
var cat={ leg:4}
cat.propertyIsEnumerable("leg")=>true 可以枚举
cat.propertyIsEnumerable("toString")=>false 不可枚举
如果修改属性标签,可通过以下方法
Object.defineProperty(对象名,属性名,{enumerable:boolean值,value:"属性值",get:function(){},set:function(){}})
Object.defineProperty(cat,"leg",{enumerable:false,value:"4"});
再查看
cat.propertyIsEnumerable("leg")=>false 不可枚举
也可以通过以下方法来列举对象某一属性的所有标签
Object.getOwnPropertyDescriptor(对象名,属性名);
Object.getOwnPropertyDescriptor({age:12},"age")=>
Object{writable:true,enumerable:true,configurable:true,value:12}
2.对象原型链(有点难度)
创建对象:new 对象构造器(),Object.create(对象原型)
I.new创建的对象的原型_proto_指向其构造器的prototype属性,而这个属性也是一个对象,而prototype的原型指向Object.prototype属性,同样它也是一个对象,它的原型指向null,所以Object是所有原型链的末端。当函数声明创建一个函数的时候,它会预设一个prototype属性,如下
var foo=function(){this.x=1}
foo.prototype=>{constructor:foo,_proto_:Object.prototype,x:1}
只有函数对象会预设prototype属性,Object对象也有,其他对象没有
II.自定义对象的原型_proto_直接指向Object的prototype属性
var foo=function(){}
foo.prototype.y=1;
var obj=new foo();
obj.x=2;
console.log(obj.x)//2 因为obj对象本身含有x属性,没啥说的
console.log(obj.y)//1 obj对象属性没有y属性,会去他的原型_proto_即其构造器的prototype属性中找(foo.prototype),如果还没有则继续上寻,直到原型链末端object,仍然没有则返回undefined;
如果需要判断属性是否属于本对象, 可调用hasOwnProperty方法判断,如果属性不在对象本身,来自对象的原型链,则同样会返回false
obj.hasOwnProperty("x")=>true
obj.hasOwnProperty("y")=>false
foo.hasOwnProperty("y")=>false
foo.prototype.hasOwnProperty("y")=>false
如上述原型链:
obj._proto_=>foo.prototype
foo.prototype._proto_=>Object.prototype
Object.prototype._proto_=null
但不是所有对象都有_proto_属性,如var obj=Object.create(null),此时的obj._proto_为undefined.
III.Object.create(参数)将参数作为新对象的原型
var a={x:1}
var obj=Object.create(a);//此时obj._proto_指向对象a,而a的原型a._proto=>Object.prototype
obj.hasOwnProperty("x");//false
a.hasOwnProperty("x");//true
综上所述:js中的对象与生俱来都拥有许多方法,皆是继承自原型链末端的Object对象
3.谈过原型链,我觉得是时候谈谈Js中的继承了,下例中定义一个父类Person,一个子类Student
父类Person包含属性name\age\legs\head,以及行为(方法)hi\walk,其中属性legs和head是固定的
子类Student除包含父类属性和行为还包括className,以及study行为,还重写了父类的hi行为
注意:object.create()是ES5才有的继承父类的原型,不支持ie9以下的版本,可以使用以下代码来兼容IE9以下版本
对象的每个属性都有多个标签,也叫属性描述器
writable 是否可写
enumerable 是否可枚举
configurable 是否可配置删除
value 属性值
get方法\set方法
get与set是对象内部的关键字,他们与其他属性不同,并非键值对形式存在,可以直接咦get set关键字开头后面跟函数表达式,其默认方法如下
get方法:get 属性名(){return this.$属性名}
set方法:set 属性名(val){this.$属性名=val}
var student={ name:"小明", get age(){ if(this.$age){ return this.$age; }else{ return new Date().getFullYear()-1988; } }, set age(val){ this.$age=val-0; } } console.log(student.age);=>29 student.age=100; console.log(student.age);=>100
另外for...in 循环遍历对象属性,会把原型链上的属性也遍历出来,除非该属性描述器enumerable=false
for( obj in Object){ ...}
需要注意的是:遍历顺序不确定;对象的属性描述器enumerable为false时将不会被枚举;受对象原型链影响;
JS delete运算符:
对象属性的描述器 configurable=false时,该属性不能被delete,return false;全局变量、局部变量都不可delete,隐式声明全局变量可以被delete;Object.prototype不可被delete;delete对象不存在的属性时 依然会返回true
通常代码中自定义创建对象的属性的标签默认值都为true,继承自Object的有些属性的标签为false,可通过以下方法来查看:
以标签enumerable为例,其他标签用法一样
var cat={ leg:4}
cat.propertyIsEnumerable("leg")=>true 可以枚举
cat.propertyIsEnumerable("toString")=>false 不可枚举
如果修改属性标签,可通过以下方法
Object.defineProperty(对象名,属性名,{enumerable:boolean值,value:"属性值",get:function(){},set:function(){}})
Object.defineProperty(cat,"leg",{enumerable:false,value:"4"});
再查看
cat.propertyIsEnumerable("leg")=>false 不可枚举
也可以通过以下方法来列举对象某一属性的所有标签
Object.getOwnPropertyDescriptor(对象名,属性名);
Object.getOwnPropertyDescriptor({age:12},"age")=>
Object{writable:true,enumerable:true,configurable:true,value:12}
2.对象原型链(有点难度)
创建对象:new 对象构造器(),Object.create(对象原型)
I.new创建的对象的原型_proto_指向其构造器的prototype属性,而这个属性也是一个对象,而prototype的原型指向Object.prototype属性,同样它也是一个对象,它的原型指向null,所以Object是所有原型链的末端。当函数声明创建一个函数的时候,它会预设一个prototype属性,如下
var foo=function(){this.x=1}
foo.prototype=>{constructor:foo,_proto_:Object.prototype,x:1}
只有函数对象会预设prototype属性,Object对象也有,其他对象没有
II.自定义对象的原型_proto_直接指向Object的prototype属性
var foo=function(){}
foo.prototype.y=1;
var obj=new foo();
obj.x=2;
console.log(obj.x)//2 因为obj对象本身含有x属性,没啥说的
console.log(obj.y)//1 obj对象属性没有y属性,会去他的原型_proto_即其构造器的prototype属性中找(foo.prototype),如果还没有则继续上寻,直到原型链末端object,仍然没有则返回undefined;
如果需要判断属性是否属于本对象, 可调用hasOwnProperty方法判断,如果属性不在对象本身,来自对象的原型链,则同样会返回false
obj.hasOwnProperty("x")=>true
obj.hasOwnProperty("y")=>false
foo.hasOwnProperty("y")=>false
foo.prototype.hasOwnProperty("y")=>false
如上述原型链:
obj._proto_=>foo.prototype
foo.prototype._proto_=>Object.prototype
Object.prototype._proto_=null
但不是所有对象都有_proto_属性,如var obj=Object.create(null),此时的obj._proto_为undefined.
III.Object.create(参数)将参数作为新对象的原型
var a={x:1}
var obj=Object.create(a);//此时obj._proto_指向对象a,而a的原型a._proto=>Object.prototype
obj.hasOwnProperty("x");//false
a.hasOwnProperty("x");//true
综上所述:js中的对象与生俱来都拥有许多方法,皆是继承自原型链末端的Object对象
3.谈过原型链,我觉得是时候谈谈Js中的继承了,下例中定义一个父类Person,一个子类Student
父类Person包含属性name\age\legs\head,以及行为(方法)hi\walk,其中属性legs和head是固定的
子类Student除包含父类属性和行为还包括className,以及study行为,还重写了父类的hi行为
function Person(name,age){ //父类的属性name、age,此时的this是指向函数的调用对象 this.name=name; this.age=age; } //父类的hi行为 Person.prototype.hi=function(){ console.log("大家好,我是"+this.name+",我今年"+this.age+"岁了!"); } //父类walk行为 Person.prototype.walk=function(){ console.log(this.name+"正在散步呢..."); } //父类常有不变的属性 Person.prototype.legs=2; Person.prototype.head=1; function Student(name,age,className){ //调用父类,并将现在的调用对象传递给父类,这句代码只是为了更好的体现继承,可直接用this.name=name;this.age=age,只是不能提现继承 Person.call(this,name,age); //子类Student扩展的属性 this.className=className; } /*下面这句是重点 如果要将Student继承Person 则必须让Student.prototype在原型链上指向Person.prototype即Student.prototype._proto_=Person.prototype,下句就是执行了此操作,当然不是唯一方法,通过Student.prototype=new Person();同样可完成此操作。此处有几个误区: a. Student=new Person();//这样不是继承Person,而是通过化Person对象直接赋值给Student,并覆盖了原来的Student对象 b. Student.prototype=Person.prototype;//这样也不是继承,而是直接将Person.prototype赋值给了Student.prototype,这样他们的原型都指向Object.prototype,即Student.prototype._proto_=Person.prototype._proto_=Object.prototype,父类都是Object,而且在对Student进行扩展时,同样会修改掉Person*/ Student.prototype=Object.create(Person.prototype); //此句代码没有实际意义,只是为了保证Student.prototype.constructor与当前对象的一致性,因为在执行完上句代码后Student.prototype.constructor=Person,如果不修改也不会影响继承。 Student.prototype.constructor=Student; Student.prototype.study=function(){ console.log(this.name+"在学习"); } Student.prototype.hi=function(){ console.log("大家好,我是来自"+this.className+"班的"+this.name+",我今年"+this.age+"岁了!") } var tom=new Student("tom","20","3"); tom.hi(); //大家好, 我是来自3班的tom, 我今年20岁了! tom.walk();//tom正在散步呢... tom.study();//tom在学习
注意:object.create()是ES5才有的继承父类的原型,不支持ie9以下的版本,可以使用以下代码来兼容IE9以下版本
if(!Object.create){ Object.create=function(_proto_){ function F(){}; F.prototype=_proto_; return new F; } }
相关文章推荐
- 深入分析JS原型链以及为什么不能在原型链上使用对象
- 90 js 强大的原型和原型链
- JS原型对象和原型链
- JS中的prototype 原型链
- 什么是作用域链,什么是原型链,它们的区别,在js中它们具体指什么?
- JS——原型链(1)
- [js高手之路]从原型链开始图解继承到组合继承的产生详解
- 第20篇 js高级知识---深入原型链
- JS继承与原型链
- JS中注意原型链的“指向”
- 理解js作用域链 原型链
- 什么是作用域链,什么是原型链,它们的区别,在js中它们具体指什么?
- JS原型和原型链
- 20180302JS的深入学习:函数的深入用法、函数的参数、JS内置对象、动态时钟及验证表单的练习、JS原型链的简单了解
- js面向对象-原型链
- js中闭包与原型链的含义及用途
- 浅谈JS原型对象和原型链
- JS面向对象组件(二)--Javascript原型链
- JS面向对象-原型链的认知
- [js高手之路]一步步图解javascript的原型(prototype)对象,原型链