属性
数据描述符:
- configurable:表示对象的属性是否可以被删除,以及除
writable
特性外的其他特性是否可以被修改。 - enumerable:为true时,才能出现在对象的枚举属性中,才能在
for...in
和Object.keys()
被枚举 - writable:能否改写
- value:属性的数据值
- configurable:表示对象的属性是否可以被删除,以及除
要修改默认属性的特性,需要用Object.defineProperty(obj, prop, descriptor)
|
|
定义多个属性
Object.defineProperties(obj,{prop1:descriptor1,prop2:descriptor2...})
12345678910111213141516171819202122var book = {}Object.defineProperties(book, {_year:{writable:true,value:2004},edition:{writable:true,value:1},year:{get:function(){return this._year},set:function(newValue){if(newValue > 2004){this._year = newValuethis.edition = newValue - 2004}}}})存取描述符:get & set
1234567891011121314151617var book = {_year:2004, //下划线默认用于只能通过对象方法访问的属性edition:1}Object.defineProperty(book,"year",{ //这里的year属性和_year不是同一个get(){return this._year},set(newValue){if(newValue >2004){this._year = newValuethis.edition = newValue - 2004}}})book.year = 2018book.edition //14读取属性Object.getOwnPropertyDescriptor(obj, prop)
123var descriptor = Object.getOwnPropertyDescriptor(book,"_year")console.log(descriptor.value)console.log(descriptor.writable)
工厂模式(一个函数返回一个对象)
解决多个相似对象的问题,但是没有解决对象的识别问题
构造函数
构造函数也是函数,只要通过new操作符调用的,就是构造函数
用来创建特定类型的对象,与工厂模式的区别是
没有显示地创建对象
直接把属性和方法赋给this对象
没有return语句
创建新实例必须使用new操作符,新的实例person1和person2都有constructor(构造函数)属性,是一个指针,指向Person(prototype属性所在的函数)。构造函数的优势是可以将它的实例标识为一种特定的类型,可以用
instanceof
来检测,工厂模式只能检测出来Object。- 创建一个新对象
- 将构造函数的作用域赋给这个新对象(this指向这个新对象)
- 执行代码,给新对象添加属性
- 返回新对象
1234567891011121314151617function Person(name,age){this.name = namethis.age = agethis.sayName = function(){console.log(this.name)}}var person1 = new Person("jacK",18)var person2 = new Person("tom",20)-------------person1 instanceof Object //trueperson2 instanceof Person //true------------------原型模式prototype# 以上定义在this上的方法,每创建一个新的实例,就要创建一个相同任务的方法,完全没有必要,可通过原型来解决。每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象。Person.prototype.sayName = function(){console.log(this.name)}var person1 = new Person("jacK",18)var person2 = new Person("tom",20)person1.sayName() //jacK 此时他们引用的是同一个函数person2.sayName() //tomobj.hasOwnProperty(prop)
:用来检测属性是否存在于实例中,只有属性存在于实例中才返回true,来自原型会返回false。in
操作符单独使用prop in obj
:无论在实例中,还是在原型中,只要能访问到该属性,就返回truefor-in
循环,返回包括原型和实例的可枚举属性(enumerable:true),如果要包含不可枚举属性,可以用Object.getOwnPropertyNames()
12345678910111213141516171819function Person(){}Person.prototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Software Engineer";Person.prototype.sayName = function(){ alert(this.name) };var person1 = new Person();var person2 = new Person();alert(person1.hasOwnProperty("name")); //falsealert("name" in person1) //true-------------person1.name = "Greg";alert(person1.name); //"Greg"——来自实例alert(person1.hasOwnProperty("name")); //truealert(person2.name); //"Nicholas"——来自原型alert(person2.hasOwnProperty("name")); //falsedelete person1.name;alert(person1.name); //"Nicholas"——来自原型alert(person1.hasOwnProperty("name")); //false理解原型对象
创建一个新函数,就会为该函数创建一个prototype属性,指向函数的原型对象。所有的原型对象都会自动获得一个constructor属性(构造函数),这个属性是一个指向prototype属性所在函数的指针。
12345function foo(a){console.log(a)}//console.dir(foo) 会有prototype属性指向函数原型对象,而原型对象有个constructor属性指向foo函数foo.prototype.constructor === foo //true两种原型语法
12345678910111213##第一种function Person(){}Person.prototype.name = "Jack";Person.prototype.age = 29;Person.prototype.sayName = function(){ alert(this.name) };-----------##第二种简写,重写了默认的prototype属性,此时constructor属性指向了Object,不再指向Person,所以需要添加constructor属性,来指定到Personfunction Person(){}Person.prototype={name = "Jack";age = 29;sayName = function(){ alert(this.name) };}构造函数、原型和实例的关系
1每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。123456789101112131415161718# 实现一个原型链,让A的原型对象 = B的实例,那么A重写了原型对象,继承了B。function A(){this.name = "heihei"}A.prototype.getName = function(){return this.name}function B(){this.age = 18}----------继承了AB.prototype = new A()B.prototype.getAge = function(){return this.age}var person = new B()person.getName() //"heihei"这里的person实例的constructor指向的是A
#####作用域链和原型继承
在作用域链中查找变量的过程和原型继承(prototypal inheritance)有着非常相似之处。但是,非常不一样的地方在于,当你在原型链(prototype chain)中找不到一个属性的时候,并不会引发一个错误,而是会得到undefined
。但是如果你试图访问一个作用域链中不存在的属性的话,你就会得到一个ReferenceError
。
作用域链,作用域对象。作用域链本质上是一个指向作用域对象的指针列表,它只引用但不实际包含作用域对象。
1js运行时,需要一些空间来存储本地变量,这些空间称作为作用域对象。作用域对象是可以有父作用域对象(parent scope object)的。当代码试图访问一个变量的时候,解释器将在当前的作用域对象中查找这个属性。如果这个属性不存在,那么解释器就会在父作用域对象中查找这个属性。就这样,一直向父作用域对象查找,直到找到该属性或者再也没有父作用域对象。我们将这个查找变量的过程中所经过的作用域对象称作作用域链