原型和原型链
原型
- 所有的
变量
都有一个隐式原型proto属性(错)
- 所有的
对象
都有一个隐式原型proto属性(对)
- 所有的
函数
都有一个显式原型prototype属性(错)
- 所有的
构造函数
都有一个显式原型prototype属性(对)
- 属性值:原型对象
-
构造函数
的prototype
指向一个空的Object对象(错)
- 所有
构造函数
的prototype
的__proto__
指向Object的prototype(对)
将伪数组转化为真数组&怎么判断一个变量是不是数组
- 它从 Array.prototype 中继承了一些它的专属方法,如 push() , pop() , sort() , slice() , splice() 等,这些方法在伪数组和Object对象中是没有的。
- slice方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。原始数组不会被修改。
-
obj instanceof Array
可以判断是否为数组
var arr = {length:3,0:"a",1:"b",2:"c"};
arr.push('d');//报错 伪数组不能使用数组的方法
var arr2 = Array.prototype.slice.call(arr);
arr2.push("d")
console.log(arr2)
默认值
- Array.prototype指向一个空数组
- Function.prototype指向一个空的Function
-
map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
-
join()
方法将数组(或一个类数组对象)的所有元素连接到一个字符串中。
function test(arr,fn){
arr =arr||Array.prototype;
fn =fn||Function.prototype;
return arr.map(fn).join(" ");
}
console.log(test());
==
的使用规则
- 引用数据类型进行比较时:
- 先调用本身的valueof(),如果valueof方法返回的基本数据类型则直接做比较
- 如果valueof()返回的不是基本数据类型,则调用比较对象本身的tostring()
- 基本数据进行比较时:
- 先通过number()转化成一个number类型后再做比较
//正常情况下[""]的valueof方法返回原数组[""]
再调用[""].tostring()返回""
再调用number()返回0
console.log([""]==false)//true
//方法的重写
Array.prototype.valueof = function(){
return 1;
}
console.log([""]==flase)//false
原型链的继承
- 模拟jQuery中的
html()
on()
- 体现出jQuery的链式调用 读写二合一
//构造函数 new Element()--->返回一个真实的dom节点
function Element(id){
this.ele = document.getElementById(id);
}
Element.prototype.innerText= function(val){
var ele = this.ele;
if(val){
ele.innerText = val;
return this;//链式调用
}else{
return ele.innerText;
}
}
Element.prototype.on = function(val,fn){
var ele = this.ele;
if(ele.addEventListener){
ele.addEventListener(val,fn);
return this
}
}
var textNode = new Element("test");
textNode.innerText("text")//写
textNode.innerText("text").innerText()//链式调用
console.log(textNode.innerText("text").innerText())//读
textNode.on("click",function(){
alert(1);
}).innerText('text')
综合面试题
//运算符的优先级
//左右查询
//原型链
//this
//属性的查找
//提升
function getName() {
alert (5);
}
function Foo() {
getName = function () { alert (1); };
return this;
}
Foo.getName = function () {
alert (2);
};
Foo.prototype.getName = function () {
alert (3);
};
var getName = function () {
alert (4);
};
Foo.getName(); //2
getName();//4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName()//3
原型&原型链
- 原型对象:它不是一个空的Object对象,但是它的proto永远指向Object的prototype
- 原型链的头
Object.prototype.__proto__===>null
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__=== null
javascript中的属性
变量的查找
属性描述符(元属性)
- 修饰属性的属性(元属性)
- 获取对应属性的描述符
-
Object.getOwnPropertyDescriptor(obj,"name")
第一个参数:对应的对象;第二个参数:对应对象的属性
-
writable
决定是否可以修改属性的值
- 一般和value绑定在一起
- 当writable为false时,对应的属性的值是无法修改的。
在默认情况下:继续修改的话会静默失败
在严格模式下:会报错
-
configurable
来决定属性是否可以配置
- 是否可以被delete
- 删除
configurable:true 可以删
configurable:false 不可以删
- 重新配置
能不能重新定义属性的描述符
configurable:true 可以重新配置
configurable:false
writable可以从true变为false
其他两个属性不可以动
var damu={};
Object.defineProperty(damu,"age",{
value:18,
writable:true
})
Object.defineProperty(damu,"age",{
value:19,
configurable:true//报错
})
console.log(damu)//age:19
var a=3;
b=4;
console.log(Object.getOwnPropertyDescriptor(window,"a"))
console.log(Object.getOwnPropertyDescriptor(window,"b"))
delete a;//a configurable:false不能删除
delete b;//b configurable:true可以被删除
console.log(a)//3
console.log(b)//报错
-
enumerable
可枚举:能否出现在对象的for in循环
- 判断属性是否可枚举
(不会遍历原型链)obj.propertyIsEnumerable("a")
- 获取可枚举属性列表
(不会遍历原型链)Object.keys(obj)
- 获取所有属性的列表
(不会遍历原型链)Object.getOwnPropertyNames(obj)
var damu={};
Object.defineProperty(damu,"a",{
enumerable:false
})
Object.defineProperty(damu,"b",{
enumerable:true
})
Object.defineProperty(damu,"c",{
enumerable:true
})
Object.defineProperty(damu,"d",{
enumerable:true
})
Object.defineProperty(damu,"e",{
enumerable:false
})
Object.defineProperty(damu,"f",{
enumerable:false
})
for(item in damu){
console.log(item);//输出b,c,d
}
for(item in damu){
if(damu.hasOwnProperty(item)){
console.log(item);
}
}
Object.defineProperty(Object.prototype,"text",{
value:"text"
enumerable:true
})
console.log(damu.text)//text可以找到
console.log(damu.propertyIsEnumerable("f"))//false
console.log(damu.propertyIsEnumerable("text"))//false不会在原型链上找
console.log(Object.keys(damu));//可枚举类型(不会在原型链上找)
console.log(Object.getOwnPropertyNames)//所有属性列表(不会在原型链上找)
定义对象属性的两种方法
var damu={
wife:"zdy"
}
damu.wife="fbb";
console.log(damu);
var damu={}
Object.defineProperty(damu,"age",{
value:18
})
console.log(damu);
对象的不变性
对象的常量属性
- 将属性的
writable
和configurable
设置为false
禁止对象扩展
-
Object.preventExtensions(obj)
传入一个对象
密封对象
- 在禁止对象扩展Object.preventExtensions(obj)的基础上把现有属性的configurable都调整为false
- 调用
Object.seal(obj)
密封一个对象
- 密封之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,但属性值是可以修改的
冰封对象
- 在密封对象(Object.seal(obj))的基础上把现有属性的writable都调整为false
- 调用
Object.freeze(obj)
密封一个对象
- 冻结之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,属性值不可以进行修改
深度冻结对象
- 在js中!!!所有方法的创建都是浅不变形的,他们只会影响目标对象和他的直接属性
- 一般项目中不会深度冻结对象(如果需要使用,考虑是不是设计错误)
- 如果使用深度冻结对象时需要使用
for in
一直循环
var obj={
hoddy:{
hoddy1:"a",
hoddy2:"b",
hoddy3:"c",
hoddy4:"d",
hoddy5:"e"
}
};
Object.freeze(obj);
obj.hoddy.hoddy1 = "g"//hoddy1会发生改变
console.log(obj)
for(item in obj){
Object.freeze(obj[item]);
}
存在性检查
- in(会遍历原型链)
"a" in obj
- hasOwnProperty(不会遍历原型链,只在对象中查找)
obj.hasOwnProperty("a")
访问描述符
- 当你给一个属性定义
set
或者get
,或者两者都有时,这个属性会被定义为访问描述符
- 对于访问描述符来说,Javascript会忽略他们的
value和writable
特性。取而代之的是set和get函数。
-
value writable
和set get
只能有一组
- 访问描述符可以使我们在对属性进行取赋值操作时预先变规定逻辑(比如if else)
- 访问描述符可以使我们的属性变的更加安全!!!!封装
总结
- 属性描述符
用来修饰属性的属性(元属性) 5个
- 数据描述符
具有writable和value属性描述符的属性 我们称之为数据描述符
- 访问描述符
具有set和get属性描述符的属性 我们称之为访问描述符
-
writable为true的数据描述符
- 属性的查找:在实例对象的直接属性没有找到对应的属性则上原型链,如果整条原型链都没有该属性,返回undefined
- 属性的设置:不管什么情况,设置操作只会影响对象的直接属性
属性的查找
- 在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
- 如果没有找到,则遍历原型链
- 无论·如何都没找到,返回undefined
属性的设置
-
如果属性直接存在于对象中 不在原型链上(或者属性直接存在于对象中 也在原型链上) 找到直接存在于对象中的属性
- 数据描述符(没有setter/getter):直接修改对象中的属性的值(注意writbale的值)
- 访问描述符:直接调用set方法
-
如果属性不直接存在于对象中 在原型链上
- 该属性是数据描述符(没有setter/getter)
- writbale为true
直接在对象中添加一个属性,我们称之为屏蔽属性
- writbale为false
报错,不会生成屏蔽属性
- 该属性是访问描述符
调用set,不会生成屏蔽属性
- 如果属性不直接存在于对象中 也不在原型链上 在对象的直接属性中添加一个属性(数据描述符)