对象原型

对象

null和undefined没有对应的构造形式,它们只有文字形式。Date只有构造形式,没有文字形式。

数组:数组也是对象,所以虽然每个下标都是整数,但任然可以给数组添加属性;虽然添加了命名属性,数组的length值并未发生变化。

如果试图向数组添加一个属性,但是属性名“看起来”像一个数字,那它就会变成一个数值下标(因此会修改数组的内容而不是添加一个属性)。

不变性

  • 禁止扩展:Object.preventExtensions(obj)

禁止一个对象添加新属性并且保留已有属性。

  • 密封:Object.seal(obj)

不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以修改属性的值)。

  • 冻结:Object.freeze(obj)

禁止对于对象本身及其任意直接属性的修改(对象引用的其他对象是不受影响的)。

深度冻结一个对象需递归遍历它引用的所有对象并在这些对象上调用Object.freeze(...)。

存在性 

in操作符会检查属性是否在对象及其[[prototype]]原型链中;hasOwnProperty()只会检查属性是否在当前对象中,不会检查[[prototype]]原型链。

propertyIsEnumerable()会检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足enmuerable:true。

Object.keys()会返回一个数组,包含所有可枚举的属性。Object.getOwnPropertyNames()会返回一个数组,包含所有属性,无论它们是否可枚举。

Object.keys()和Object.getOwnPropertyNames()都只会查找对象直接包含的属性。

for in循环可以用来遍历对象的可枚举属性列表(包括[[prototype]]链),所以效率低。

面向对象编程强调的是数据和操作数据的行为本质上是关联起来的(当然,不同的数据有不同的行为),因此好的设计就是把数据以及和它相关的行为打包(或者说封装)起来。

多态是说父类的通用行为可以被子类用更特殊的行为重写。

类并不是必须的编程基础,而是一种可选的代码抽象。

建筑和蓝图之间的关系是间接的。你可以通过蓝图了解建筑的结构,只观察建筑本身是无法获得这些信息的。但是你想打开一扇门,那就必须接触真实的建筑才行--蓝图只能表示门应该在哪,但并不是真正的门。

原型

Object.create(...)它会创建一个对象并把这个对象的[[prototype]]关联到指定的对象。polyfill代码:

function ObjectCreate(obj){
    if(!Object.create){
        Object.create = function(obj){
            function F(){}
            F.prototype = obj
            return new F()
        }
    }
    return Object.create(obj)
}

讲解 myObject.foo = 'bar';  执行完成过程:

如果myObject对象中包含名为foo的普通数据访问属性,这条赋值语句只会修改已有的属性值。

如果foo不是直接存在于myObject中,[[prototype]]链就会被遍历,类似于[[get]]操作。如果原型链上找不到foo,foo就会直接被添加到myObject上。

如果属性名foo即出现在myObject中也出现在myObject的[[prototype]]链上层,那么就会发生屏蔽。myObject中包含的foo属性会屏蔽原型链上层的所有foo属性,因为myObject.foo总会选择原型链中最底层的foo属性。

如果foo不直接存在于myObject中而是存在于原型链上层时,会出现三种情况:

  1. 如果在[[prototype]]链上层存在名为foo的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在myObject中添加一个名为foo的新属性,它是屏蔽属性。
  2. 如果在[[prototype]]链上层存在foo,但是它被标记为只读,那么无法修改已有属性或者在myObject中创建屏蔽属性。严格模式下代码会抛出一个错误。否则这条赋值语句会被忽略。总之不会发生屏蔽。
  3. 如果在[[prototype]]链上层存在foo并且它是一个setter,那就一定会调用这个setter。foo不会被添加到(或者说屏蔽于)myObject,也不会重新定义foo这个setter。

注:只读属性会阻止[[prototype]]链下层隐式创建(屏蔽)同名属性。这样做只要是为了模拟类属性的继承。你可以把原型链上层的foo看做父类中的属性,它会被myObject继承,这样一来myObject中的foo属性也是只读所以无法创建。这个限制只存在于=赋值中,使用Object.defineProperty(...)并不会受到影响。

构造函数还是调用:当你在普通的函数前面加上new关键字之后,就会把函数调用变成一个“构造函数调用”。实际上,new会劫持所有普通函数并用构造对象的形式来调用它。 

function isRelatedTo(o1,o2){
    function F(){}
    F.prototype = o2
    return o1 instanceof F
}
var a = {}
var b = Object.create(a)
isRelatedTo(b,a)//true

行为委托 

[[prototype]]机制就是指对象中的一个内部链接引用另一个对象。

如果在第一个对象上没有找到需要的属性或者方法引用,引擎就会继续在[[prototype]]关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的[[prototype]],以此类推,这一系列对象的链接被称为原型链。换句话说,JavaScript中这个机制的本质就是对象之间的关联关系。

面向对象和对象关联

function Foo(who){
    this.me = who
}
Foo.prototype.identify = function(){
    return '我是' + this.me
}
function Bar(who){
    Foo.call(this,who)
}
Bar.prototype = Object.create(Foo.prototype)
Bar.prototype.speak = function(){
    alert('hello,' + this.identify())
}
var b1 = new Bar('b1')
var b2 = new Bar('b1')
b1.speak()
b2.speak()


let Foo = {
    init(who){
        this.me = who
    },
    identify(){
        return '我是' + this.me
    }
}
let Bar = Object.create(Foo)
Bar.speak = function(){
    alert('hello,' + this.identify())
}
var b1 = Object.create(Bar)
b1.init('b1')
b1.speak()
var b2 = Object.create(Bar)
b2.init('b2')
b2.speak()

  

原文地址:https://www.cnblogs.com/zhenjianyu/p/13263497.html