Javascript 高级程序设计--总结【二】
********************** Chapter 6 **********************
属性:
数据属性:
Configurable: 能否通过delete 删除属性,默认true
Enumerable: 能否通过 for-in 循环返回属性,默认true
Writeble: 能否修改属性的值
Value:属性的数据值
使用 Object.defineProperty(obj,'prop',{}) 来定义属性,这种方式的默认值都是 false ,不建议 IE8 中使用
var person={};
Object.defineProperty(person,'name',{
writable:false,
value:"test"
});
如果设置了configurable:false, 那么就不能再设置更改其他属性,否则会抛出错误
访问器属性:
getter\setter configurable enumerable
var book={
_year:2010,
edition:1
};
Object.defineProperty(book,'year',{
get:function(){
return this._year;
},
set:function(value){
if(value>2010){
this._year=value;
this.edition+=value-2010;
}
}
});
book.year=2011;
console.log(book.edition);
//另外一种方式
book.__defineGetter__('year',function(){
return this._year;
});
book.__defineSetter__('year',function(value){
if(value>2010){
this._year=value;
this.edition+=value-2010;
}
});
defineProperties() 定义多个属性
Object.defineProperties(book,{
_year:{
value:2010
},
edition:{
value:1
}
})
读取属性的特性 getOwnPropertyDescriptor() :IE9+
var desc = Object.getOwnPropertyDescriptor(book,'_year')
console.log(desc.configurable);
创建对象:
工厂模式:
function createPerson(name,age){
var obj = new Object();
obj.name=name;
obj.age=age;
obj.sayName = function(){
console.log(this.name);
}
return obj;
}
var p1 = createPerson('test',15);
var p2 = createPerson('test2',18);
这种模式的缺点就是:不能检测对象的所属类型
构造函数模式:
function Person(name.age){
this.name=name;
this.age=age;
this.sayName=function(){
console.log(this.name);
}
}
var p1 = new Person('jj',20);
var p2 = new Person('ee',22);
console.log(p1.constructor==Person);//true
console.log(p2.constructor==Person);//true
console.log(p1 instanceof Person);//true
构造函数本质也是函数,区别只是在于如何调用,构造函数使用 new 操作符地哦啊用,
如果看做普通函数调用,本质也没什么区别,this 关键字可指向window
//普通函数调用
Person('gl',22);
window.sayName();
var o = new Object();
Person.call(o,'cl',19);
o.sayName();
问题:每个对象里面的方法都会创建一个Function的新实例,但是如果方法体定义在全局中,那么将会声明太多的全局函数
原型模式:
function Person(){
}
Person.prototype.name='aa';
Person.prototype.age=18;
Person.prototype.sayName=function(){
console.log(this.name);
}
Person.prototype.isPrototypeOf(p1);//true
Object.getPrototypeOf(p1)==Person.prototype;//true
var p1 = new Person();
console.log(p1.name);
p1.sayName();
p1.hasOwnProperty('name');//false
原型链的属性搜索:从实例本身开始找,如果没有就会去原型对象中寻找
同样,实例对象里面的同名属性会覆盖掉原型对象中的同名属性 delete
ES5中,Object.getOwnPropertyDescriptor() 只能获取实例对象中属性,要获取原型对象必须在原型对象上调用此方法
in操作符:
只要是能访问到,不管实例还是原型上都为true, 如果
'name' in p1;//true
Object.keys(p1);// for-in
Object.keys(Person.prototype);//["name", "age", "sayName"]0: "name"1: "age"2: "sayName"length: 3__proto__: Array[0]
Object.getOwnPropertyNames(Person.prototype);//["constructor", "name", "age", "sayName"]
字面量的原型对象声明
function Person() {
}
//这里使用了字面量的方式创建原型对象,但是这个原型的constructor 就不是指向Person,而是Object
Person.prototype = {
//constructor: Person,//constructor 的enumerable 会设置为true,可迭代出去
name: "test",
age: 18,
sayName: function () {
console.log(this.name);
}
}
var p = new Person();
console.log(p.constructor);//Object
//手动定义的方式 ES5 兼容
Object.defineProperty(Person.prototype, 'constructor', {
enumerable: false,
value: Person
});
原型的动态性:
声明变量之后,再更改原型对象,也是可以再对象中使用的
var p = new Person();
Person.prototype.run = function () {
}
p.run();
//注意: 以下是重写了原型的方式
function Person() {
}
var p = new Person();
//重写了原型对象, p 对象还是指向原来的原型对象
Person.prototype = {
constructor: Person,
name: "test",
sayName: function () {
console.log(this.name);
}
}
//原来的原型对象中没有此方法
p.sayName();//error: p.sayName is not a function
扩展原生对象的原型:
String.prototype.startWith=function(){
//......
}
原型对象的问题:
属性的引用类型问题:
function Person() {
}
//重写了原型对象, p 对象还是指向原来的原型对象
Person.prototype = {
constructor: Person,
name: "test",
hobbies:['basketball','football'],
sayName: function () {
console.log(this.name);
}
}
var p = new Person();
p.hobbies.push('a');
console.log(p.hobbies);//["basketball", "football", "a"]
var p1 = new Person();
console.log(p1.hobbies);//["basketball", "football", "a"]
组合使用构造函数模式和原型模式【推荐】:
function Person(name, age) {
this.name = name;
this.age = age;
this.hobbies = [];
}
Person.prototype = {
constructor: Person,
sayName: function () {
console.log(this.name);
}
};
动态原型模式:
function Person(name, age) {
this.name = name;
this.age = age;
this.hobbies = [];
//这样子相当于只会执行一次的定义
if (typeof this.sayName != 'function') {
Person.prototype.sayName = function () {
console.log(this.name);
}
}
}
寄生构造函数模式【基本不用】:
function Person(name,age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function () {
console.log(this.name);
}
return o;
}
var p = new Person('kk', 19);
稳妥构造函数模式【基本不用】:
不使用new 和 this 关键字
function Person(name,age) {
var o = new Object();
o.sayName = function () {
console.log(name);//这里的name 只有方法内部才能访问的到
}
return o;
}
继承:
原型链【很少单独使用】:
prototype属性实现继承,每一个实例对象都有一个prototype 的属性
所有的函数的默认原型都是Object的实例,默认的原型实例都包含一个指针指向 Object.prototype
instanceof()\isPrototypeof() 确定实例和原型的关系,只要出现在原型链中的对象就会返回true
Person.prototype.isPrototyprOf(obj);
原型链继承一定不要使用字面量的方式,因为这样会导致重写原型,之前的继承会失效
继承添加的方法一定要在继承了原型链之后
原型链问题:
引用对象共享实例问题
function Person(){
this.colors=['red','blue'];
}
function Man(){
}
Man.prototype=new Person();
var m =new Man();
m.colors.push('blink');
var m1 = new Man();
console.log(m.colors);//['red','blue','blink']
console.log(m1.colors);//['red','blue','blink']
借用构造函数【很少单独使用】:
function Base(name){
this.name=name;
}
function Sub(){
Base.call(this,'test');
this.age=age;
}
var s = new Sub();
问题:方法都只能在构造函数中定义,函数不能复用,并且父类的原型方法不可见
组合继承:
function Base(name){
this.name=name;
}
Base.prototype.sayName=function(){
console.log(this.name);
}
function Sub(name,age){
Base.call(this,name);
this.age=age;
}
Sub.prototype=new Base();
Sub.prototype.sayAge=function(){
console.log(this.age);
}
var s1 = new Sub('kk',18);
s1.sayName();
s1.sayAge();
原型式继承:
function object(o){
function F(){}
F.prototype=o;
return new F();
}
var p = {name:'qq',hobbies:['a','b']};
var p1 = object(p);
p1.hobbies.push('c');
console.log(p1.hobbies);//["a", "b", "c"]
var p2 = object(p);
console.log(p2.hobbies);//["a", "b", "c"]
ES5 的 Object.create() 就是使用的这个方法
//类似 defineProperties 的参数使用方式
var p3 = Object.create(p,{
name:{
value:'newP'
}
});
console.log(p3.name);//newP
寄生式继承:
function createObj(obj){
var clone = object(obj);
clone.run=function(){
console.log('running');
}
return clone;
}
var p4 = createObj(p);
p4.run();
寄生组合式继承【最理想的继承范式】:
function object(o){
function F(){}
F.prototype=o;
return new F();
}
function inherit(sub,base){
var proto = object(base.prototype);
proto.constructor = sub;
sub.prototype=proto;
}
function Base(name){
this.name=name;
this.colors=['red'];
}
Base.prototype.sayName=function(){
console.log(this.name);
}
function Sub(name,age){
Base.call(this,name);
this.age=age;
}
inherit(Sub,Base)
Sub.prototype.sayAge=function(){
console.log(this.age);
}
var sub = new Sub('kk',18);
sub.sayName();
sub.sayAge();
console.log(sub.__proto__.constructor);// Sub()
************************ Chapter 7 函数表达式 ************************
func.name;//输出函数名称
//递归方式 arguments.callee() 或 以下方式
var factorial = (function f(num) {
if (num <= 1) {
return 1;
} else {
return num * f(num - 1);
}
});
闭包:
作用域链本质上是一个指向变量对象的指针列表
闭包会携带包含它函数的作用域链,更加占用内存资源
function createF() {
var arr = new Array();
for (var i = 0; i < 10; i++) {
//1. 这种方式的闭包,都会引用到外部函数的 活动对象 i, 最终的值都一样
//arr[i] = function () {
// console.log(i);
//}
//2. 这种优化的方式,就可以实现每次返回不同的值
arr[i] = function (num) {
return function () {
console.log(num);
}
}(i);//这里立即执行了函数,所以传入参数会让num更改
}
return arr;
}
var res = createF();
for (var i = 0; i < res.length; i++) {
res[i]();
}
内存泄漏问题:
function assignHandler() {
var ele = document.getElementById("ele")
ele.onclick = function () {
console.log(ele.id);//这里相当于一直引用着ele 元素,导致循环引用,无法释放
}
}
function assignHandler() {
var ele = document.getElementById("ele")
var id = ele.id;
ele.onclick = function () {
console.log(id);//正确用法
}
ele = null;//释放引用
}
模仿块级作用域:
function test() {
for (var i = 0; i < 10; i++) {
//alert(i);
}
console.log(i);//10
var i;//声明会被忽视,但是赋值才会覆盖 i=100
console.log(i);//10
}
test();
模仿块级作用域:
var f = function () {
console.log('f');
}
f();
//块级作用域
(function () { console.log('f'); })();
//里面的都是块级作用域
(function () {
var btn = document.getElementById("btn");
btn.onclick = function () {
console.log('onclick');
}
console.log('f');
})();
私有变量:
function Person() {
//特权方法,访问私有变量
this.getName = function () {
return name;
};
//特权方法,访问私有变量
this.setName = function (val) {
name = val;
};
}
静态私有变量:
function () {
var privateVal = 10;
function privateF() {
return false;
};
//这里没有使用var ,所以是全局的
Person = function (val) {
name = val;
};
Person.prototype.getName = function () {
return name;
}
Person.prototype.setName = function (val) {
name = val;
}
})();
var p1 = new Person('t1');//t1
console.log(p1.getName());
var p2 = new Person('t2');
console.log(p1.getName());//t2 由于是静态的,所以都改变了
console.log(p2.getName());//t2
模块模式(单例):
var singleton = function () {
var privateVal = 10;
function privateFun() {
return false;
}
return {
pubProp: true,
pubMethod: function () {
privateVal++;
return privateFun();
}
};
}();
var application = function () {
var components = new Array();
components.push(new BaseComponent());
return {
getCompCount: function () {
return components.length;
},
registerComp: function (component) {
if (typeof component == 'object') {
components.push(component);
}
}
};
}();
增强的模块模式:
var singleton = function () {
var privateVal = 10;
function privateFun() {
return false;
}
//所谓的增强就是指定了返回类型
var object = new CustomType();
object.pubProp = true;
object.pubMethod = function () {
privateVal++;
return privateFun();
};
return object;
}();
var application = function () {
var components = new Array();
components.push(new BaseComponent());
//所谓的增强就是指定了返回类型
var app = new BaseComponent();
app.getCompCount = function () {
return components.length;
};
app.registerComp = function (component) {
if (typeof component == 'object') {
components.push(component);
}
};
return app;
}();
严格模式:
eval赋值会导致错误;//eval='a'
getter\setter, 没有设置就访问会报错
************************ Chapter 9 客户端检测 ************************
能力检测:
浏览器能力检测
if(obj.property){
//使用obj.property 方法
}
尽量使用 typeof 进行检测
function hasSort(){
return typeof obj.sort == 'function';
}
//IE
typof document.createElement == 'function'
IE9 之后所有的DOM方法才会返回 'function',因为IE8 之前的所有宿主对象都是COM对象,返回的是'object'
var xhr = new ActiveXObject("Microsoft.XMLHttp");
if (xhr.open) {//函数作为属性检测 IE会发生错误,使用typeof 会放回 'unknow'
}
function isHostMethod(object, prop) {
var t = typeof object[prop];
// IE typeof xhr.open 这里会返回'unknow'
return t == 'function' || (!!(t == 'object' && object[prop])) || t == 'unknow';
}
var res = isHostMethod(xhr, 'open');//true
navigator.vendor;//浏览器的品牌
怪癖检测(略):
var obj = {
toString: function () {
console.log('string');
}
};
for (var i in obj) {
alert(i);
}
用户代理检测:
IE7 和 IE8 的兼容模式:
IE7 navigator.userAgent 返回的是 MSIE 7.0, 没有trident 标记
IE8 的兼容模式 navigator.userAgent 返回的是 MSIE 7.0, 有trident 标记
IE8:
navigator.userAgent 返回的是 MSIE 8.0
Gecko:
//默认加密方式U,不会显示
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0"
用户代理字符串检测技术:
五大呈现引擎:IE\Gecko\WebKit\KHTML\Opera
?: 表示不捕获分组
Javascript 高级程序设计--总结【二】的更多相关文章
- javascript 高级程序设计 十二
1.组合使用原型模式和构造函数模式: 由于原型模式创建对象也有它的局限性------有智慧的人就把原型模式和构造函数模式进行了组合. function Person(name, age, job){/ ...
- JavaScript高级程序设计学习(二)之基本概念
任何语言的核心都必然会描述这门语言基本的工作原理.而描述的内容通常都要涉及这门语 言的语法.操作符.数据类型.内置功能等用于构建复杂解决方案的基本概念.如前所述, ECMA-262通过叫做 ECMAS ...
- 读书时间《JavaScript高级程序设计》二:面向对象
接着上次的进度,开始看第6章. 第6章 面向对象的程序设计 理解对象 创建自定义对象最简单的方式就是创建一个 Object 的实例,然后为它添加属性和方法. var person = new Obje ...
- javascript 高级程序设计(二)-在html中使用javascript
<script> async 可选 charset 可选 defer 可选 language 已废弃 src 可选 type 可选
- JavaScript高级程序设计(二)
一.函数 1.1 JS中函数无重载,同一作用域下定义两个函数,而不会引发错误,但真正调用的是后面定义的函数.例如: function doAdd(iNum){ alert(iNum+100); } f ...
- 《Javascript高级程序设计》阅读记录(二):第四章
这个系列之前文字地址:http://www.cnblogs.com/qixinbo/p/6984374.html 这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较 ...
- 《JavaScript高级程序设计(第3版)》笔记-序
很少看书,不喜欢看书,主要是上学时总坐不住,没有多大定性,一本书可以两天看完,随便翻翻,也可以丢在角落里几个月不去动一下. 上次碰到了<JavaScript高级程序设计(第3版)>感觉真的 ...
- 读javascript高级程序设计08-引用类型之Global、Math、String
一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encod ...
- JavaScript高级程序设计学习(三)之变量、作用域和内存问题
这次讲的主要是变量,作用域和内存问题. 任何一门编程语言,都涉及这三个. 变量,比如全局变量,局部变量等,作用域,也分全局作用域和方法作用域,内存问题,在java中就涉及到一个垃圾回收的问题,由于ja ...
- javascript 高级程序设计 一
前言: 作为一个即将毕业.正在实习的大学生,我也默默的进入了开发者的行列.从一开始的c#编码狗到java程序员再到现在的JS开发者,我一直 希望自己可以在这个'万恶'的互联网时代走的更远.但是我还是一 ...
随机推荐
- Linux学习笔记之十一————Linux常用服务器构建之ssh和scp
一.ssh 1.ssh介绍 SSH为Secure Shell的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议. ...
- Gradle中使用SpringBoot插件构建多模块遇到的问题
通常下,多模块的项目如下: Root project 'demospring' +--- Project ':model' \--- Project ':rest' 那么我们需要在rest模块依赖mo ...
- 从零开始学 Web 之 HTML5(三)网络监听,全屏,文件读取,地理定位接口,应用程序缓存
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- Java提高篇之理解java的三大特性——封装
三大特性之—封装 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐 ...
- JavaScript模拟自由落体
1.效果图 2.实现分析 利用Canvas画圆球.地面: 1.下落过程 物理知识回顾,物体下落过程(不计损耗)由重力势能转换成动能 重力势能 Ep = mgh 动能 Ek = (1/2)mv^2 速 ...
- RockChip RK3326 系统编译问题总结
1. 序言 本文主要记录了RK3326平台系统编译过程中遇到的各种问题,并加以解决! 环境: 宿主Linux:Ubuntu 16.04 目标机:RK3326 (64bit) Toolchain:gcc ...
- c# Newtonsoft.Json封装
public static T Deserialize<T>(string content) where T : class, new() { return JsonConvert.Des ...
- Linux常用基本命令:三剑客命令之-awk动作用法(1)
1,多个动作,怎么写? ghostwu@dev:~/linux/awk$ cat host.txt name ip地址 host1 192.168.1.1 host2 192.177.81.1 hos ...
- Fundebug是这样备份数据的
摘要: 数据还是要备份的,万一删库了呢? 本文代码仓库: fundebug-mongodb-backup 引言 今年8月,腾讯云竟然把客户前沿数据的数据弄没了,Fundebug在第一时间进行了一些简单 ...
- Layui tree 下拉菜单树
1.效果: 2.html 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...