[[Get]] 和 [[Put]]、getter 和 setter

1、对象属性的操作

通常我们操作对象中的属性时,使用 obj.attribute 或 obj[‘attribute’] ,内部原理就是调用了 [[Get]] 和 [[Put]] 操作,两个都是默认的属性操作行为,而 getter 和 setter 是一种自定义的属性操作行为,使用它们可以覆盖原有的行为。

2、[[Get]] 和 [[Put]]

[[Get]] 作为默认的行为,它做了2件事:

1、首先在该对象中查找同名属性,如果找到了,返回此属性的值。
2、如果在此对象中没有找到,会沿着原型链进行查找,最终没有找到返回undefined。

[[Put]] 的行为大体上可以归结为以下三种情况:

一、如果此对象中存在
1、检查是否存在 getter 和 setter ,如果存在,则不会执行默认行为 。
2、检查它的属性描述符 writable 是否是 false ?如果是,在非严格模式下失效,在严格模式下抛出 TypeError 异常。

let animal = {};
Object.defineProperty(animal,"run",{
    value: 10,
    writable: false		//设置为不可写
});
let dog = {};
dog.__proto__ = animal;
dog.run = 20;
console.log("dog.run:" + dog.run);
dog.run:10

3、如果不满足上述条件,则会赋予它新的值。

二、如果此对象中不存在,而原型链上存在
1、如果此属性 writable: true,会在自身上添加属性或方法,屏蔽掉原型链上同名的属性或方法。

let animal = {name: "animal"};
dog = {};
dog.__proto__ = animal;
dog.name = "dog";
console.log(dog);
{name: "dog"}
  name: "dog"
  __proto__: 
    name: "animal"
    __proto__: Object

2、如果此属性 writable: false,则无法在自身上添加属性或方法,并且也无法修改原型链上的同名属性或方法。

let animal = {};
Object.defineProperty(animal,"name",{
    value: "animal",
    writable: false
});
let dog = {};
dog.__proto__ = animal;
dog.name = "dog";
console.log(dog);
{}
  __proto__: 
    name: "animal"
    __proto__: Object

三、如果此对象中不存在,原型链上也不存在
沿着原型链进行查找,找不到返回 undefined。

3、getter 和 setter

在 ES5 中可以使用 getter 和 setter 改写默认操作,但是只能应用在单个属性上。

一、使用 set 和 get 定义属性,可以理解成定义两个操作属性的方法,当对属性进行操作时,就是调用这两个方法。(__ proto __ 本质上就是通过这种方式实现的,它实际上是定义在Object上,操作 __ proto __,相当于调用它对应的方法)

1、常规的定义方式:使用 this 实现原型链中间互不影响,并且定义中间变量 _ speed _ 。

let animal = {
    get speed(){
        return this._speed_;
    },
    set speed(value){
        this._speed_ = value * 2;
    }
};
let dog = {};
dog.__proto__ = animal;
console.log(dog);
{}
  speed: undefined
  __proto__:
    speed: undefined
    get speed: ƒ speed()
    set speed: ƒ speed(value)
    __proto__: Object

2、验证此属性在原型链上互不影响

let animal = {
    set speed(value){
        this._speed_ = value * 2;
    },
    get speed(){
        return this._speed_;
    }
};
let dog = {};
dog.__proto__ = animal;
dog.speed = 10;
console.log(dog);
console.log(animal);
{_speed_: 20}
  speed: 20
  _speed_: 20
  __proto__: Object
  
{}
  speed: undefined
  get speed: ƒ speed()
  set speed: ƒ speed(value)
  __proto__: Object

注意:不要看控制台 dog. __ proto __ 下的 speed,this的原因,会使 speed 值与期望值不同。

二、不能设置它的 value 和 writable 特性(即使是默认值也不行), 可以设置 configurable 和 enumerable 特性。

1、设置属性 value 和 writable 特性

let animal = {
    set speed(value){
        this._speed_ = value * 2;
    },
    get speed(){
        return this._speed_;
    }
};
Object.defineProperty(animal,"speed",{
    value: 40,
    writable: true
})
console.log(animal);
{speed: 40}
  speed: 40
  __proto__: Object

可以发现当设置属性 value 和 writable 特性,getter 和 setter 行为会被默认
[[Get]] 和 [[Put]] 行为覆盖

2、设置 configurable 和 enumerable 特性

let animal = {
    set speed(value){
        this._speed_ = value * 2;
    },
    get speed(){
        return this._speed_;
    }
};
Object.defineProperty(animal,"speed",{
    configurable: true,
    enumerable: true
})
console.log(animal);
{}
  speed: undefined
  get speed: ƒ speed()
  set speed: ƒ speed(value)
  __proto__: Object

设置 configurable 和 enumerable 特性,getter 和 setter 行为不会被默认
[[Get]] 和 [[Put]] 行为覆盖。

注意:上述只是粗略演示,真实测试很复杂。

哈夫曼编码(Huffman Coding)是一种用于数据压缩的无损数据压缩算法,由David A. Huffman在1952年发明。它通过构建一棵称为哈夫曼树的二叉树,根据字符出现的频率为每个字符分配一个独特的二进制代码,频率越高的字符得到的代码越短,从而实现了对常用字符的高效编码。 在Java中,你可以使用以下步骤来实现哈夫曼编码: 1. **字符频率统计**:读取数据并计算每个字符出现的次数,存储在一个HashMap或PriorityQueue中。 2. **构造哈夫曼树**: - 从频率最高的两个元素开始,创建一个新的节点,其频率是这两个节点的和,然后将它们作为左子树和右子树添加到队列中。 - 重复此过程,每次从队列中取出两个最小频率的节点,合并成新的节点,直到只剩下一个节点为止。 3. **构建编码表**: - 遍历生成的哈夫曼树,从根节点开始,对于每个节点,如果它是左孩子,给其代表的字符分配一个`0`;如果是右孩子,分配一个`1`,直到到达叶子节点,记录下路径上的符号就是该字符的编码。 4. **编码和解码**: - 对于输入的原始文本,遍历每个字符,查找其在编码表中的对应的二进制编码,将编码替换为对应的二进制串。 - 对于编码后的数据,按照相同的规则反向查找,重建原始文本。 以下是一个简单的Java示例(不包括哈夫曼树的构建): ```java import java.util.HashMap; import java.util.PriorityQueue; public class HuffmanCoding { private static final int EOF = 0; public static void main(String[] args) { String input = "your_input_string"; // 假设的字符频率统计 HashMap<Character, Integer> freqMap = new HashMap<>(); freqMap.put('a', 10); freqMap.put('b', 5); freqMap.put('c', 3); // ... (更多字符和频率) PriorityQueue<HuffmanNode> huffmanTree = new PriorityQueue<>((a, b) -> a.frequency - b.frequency); for (Character c : freqMap.keySet()) { HuffmanNode newNode = new HuffmanNode(c, freqMap.get(c), null, null); huffmanTree.add(newNode); } buildHuffmanTree(huffmanTree); // 编码和解码部分 // 编码部分略 // 解码部分:遍历输入字符串,查找字符的编码,并输出解码后的字符串 } private static void buildHuffmanTree(PriorityQueue<HuffmanNode> huffmanTree) { while (huffmanTree.size() > 1) { HuffmanNode left = huffmanTree.poll(); HuffmanNode right = huffmanTree.poll(); HuffmanNode newNode = new HuffmanNode(null, left.frequency + right.frequency, left, right); huffmanTree.add(newNode); } // 最终的根节点就是哈夫曼树 } } class HuffmanNode { Character character; int frequency; HuffmanNode left, right; String code; // 构造函数、gettersetter省略 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值