摘要:碰过的一个有趣的问题实现一个构造函数,有一个属性,每次调用该值加。共有方法看下面的代码可以发现,被重复创建了如果不想方法或者属性在每次时新创建一份,可以将其设置在构造函数的原型上。
面向对象有三个特点,一个个来说:
封装 私有变量利用闭包实现对象的私有变量。
function Animal (age) { this.getAge = function () { return age } } var dog = new Animal(3) console.log(dog.age) // undefined console.log(dog.getAge()) // 3
碰过的一个有趣的问题:
实现一个book构造函数,有一个属性id,每次调用该值加1。
运用闭包和立刻执行函数。
let Book = (function () { let id = 1 return function () { this.id = id++ } })() let bok1 = new Book() let bok2 = new Book() let bok3 = new Book() console.log(bok3.id) // 3共有方法
看下面的代码可以发现,getAge被重复创建了
var dog = new Animal(3) var cat = new Animal(5) console.log(dog.getAge === dog.getAge) // false
如果不想方法或者属性在每次new时新创建一份,可以将其设置在构造函数的原型prototype上。
Animal.prototype.feed = function () { console.log("feed") } console.log(dog.feed === cat.feed) // true继承
听说继承有六种方法,假设让Dog继承Animal,无非就是for in 复制属性,修改原型链如dog.prototype = new Animal,直接Object.create,在Dog中使用Animal.call
然而我们记住最好的一种就够了,就是组合继承。
先试下这样写,利用call的继承:
function Animal (name) { this.name = name; this.say = function() { console.log(this.name) } } // *1 function Dog (color, name) { Animal.call(this, name) this.color = color } // *2 let wangcai = new Dog("blue", "wangcai") console.log(wangcai) // {color: "blue", name: "wangcai") wangcai.say() // "wangcal"
可是如果在*1处加上这样的代码
Animal.prototype.say2 = function() { console.log(this.name) }
在*3处输入
wangcai.say2(),会报错提示不存在该方法,说明我们的继承是不完整的。dog没有继承原型链上的方法
我们需要在*2补上:
Dog.prototype = Object.create(Animal.prototype)
这时候不会报错了,补上Object.create的polyfill
function objectCreate (proto) { function F() {} F.prototype = proto; return new F(); }
然而还有一点小漏洞,当我们查看wangcai.constructor时,会发现指向的是Animal。因此我们需要修复一下:
Dog.prototype.constructor = Dog
补充一下new的模拟
function fNew (base) { var o = {} o.__proto__ = base.prototype base.call(o) return o }
完整代码
function Animal (name) { this.name = name; this.say = function() { console.log(this.name) } } Animal.prototype.say2 = function () { console.log(this.name) } function Dog (color, name) { Animal.call(this, name) this.color = color } Dog.prototype = Object.create(Animal.prototype) Dog.prototype.constructor = Dog let wangcai = new Dog("blue", "wangcai")
检测继承是否成功的代码:
console.log(wangcai instanceof Animal) console.log(wangcai instanceof Dog) console.log(wangcai.constructor === Dog) console.log(wangcai.say2 === Animal.prototype.say2) console.log(wangcai.__proto__ === Dog.prototype) console.log(wangcai.__proto__.__proto__ === Animal.prototype) console.log(wangcai.__proto__.__proto__.__proto__ === Object.prototype) console.log(wangcai.constructor === Dog)
使用Object.create()和修复Dog.prototype.constructor = Dog是不是挺多余的?es6提供了这么一个函数Object.setPrototypeOf.
因此我们可以使用
Object.setPrototypeOf(Dog.prototype, Animal.prototype)
替换刚刚提到的两行代码
可以了解到Object.setPrototypeOf(A,B)相当于令A.__proto__ = B。
多态一个函数可以应用于不同的对象。并且根据this的不同,函数调用的结果也不同
function test() { alert([this.a, this.b]); } test.call({a: 10, b: 20}); // 10, 20 test.call({a: 100, b: 200}); // 100, 200 var a = 1; var b = 2; test(); // 1, 2
或是在函数中检测arguments的数量和类型来实现多态
function add (a, b) { if (arguments.length === 2) { return a + b } else { return a + 1 } } console.log(add(1,4)) console.log(add(1))
END
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/95893.html
摘要:对于属性来说类内部的调用方式静态属性是类的属性普通属性是类具体实例化出的对象的属性所以二者是完全不同的调用方式也非常不同静态属性静态属性名类名静态属性名普通属性普通属性名类外部的调用方式静态属性是类的属性普通属性是类具体实例化出的对象的属 对于 属性 来说 类内部的调用方式 静态属性是类的属性 普通属性是类具体实例化出的对象的属性 所以二者是完全不同的, 调用方式也非常不同 ...
摘要:面向对象主要知识点小结,基于构造函数可以理解为通过即将创建的对象将类实例化给一个对象赋予属性或者方法原型便于方法的重用与构造函数模式相比,使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。 JavaScript面向对象主要知识点小结,基于ECMAScript 5. 构造函数 function People(name){ //this可以理解为通过new即将创建...
摘要:参考链接面向对象编程模型现在的很多编程语言基本都具有面向对象的思想,比如等等,而面向对象的主要思想对象,类,继承,封装,多态比较容易理解,这里就不多多描述了。 前言 在我们的日常日发和学习生活中会常常遇到一些名词,比如 命令式编程模型,声明式编程模型,xxx语言是面向对象的等等,这个编程模型到处可见,但是始终搞不清是什么?什么语言又是什么编程模型,当你新接触一门语言的时候,有些问题是需...
阅读 2060·2021-11-23 09:51
阅读 2202·2021-09-29 09:34
阅读 3694·2021-09-22 15:50
阅读 3556·2021-09-22 15:23
阅读 2556·2019-08-30 15:55
阅读 699·2019-08-30 15:53
阅读 3065·2019-08-29 17:09
阅读 2623·2019-08-29 13:57